From 58d503a77da73204f097fae1f1a2a1ce2cf90600 Mon Sep 17 00:00:00 2001 From: sodo Date: Sun, 10 Dec 2023 01:45:24 +0900 Subject: [PATCH 001/760] add avr support --- embassy-executor-macros/src/lib.rs | 7 +++ embassy-executor-macros/src/macros/main.rs | 14 +++++ embassy-executor/Cargo.toml | 1 + embassy-executor/src/arch/avr.rs | 60 ++++++++++++++++++++++ embassy-executor/src/lib.rs | 3 +- 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 embassy-executor/src/arch/avr.rs diff --git a/embassy-executor-macros/src/lib.rs b/embassy-executor-macros/src/lib.rs index c9d58746a..5461fe04c 100644 --- a/embassy-executor-macros/src/lib.rs +++ b/embassy-executor-macros/src/lib.rs @@ -62,6 +62,13 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { task::run(&args.meta, f).unwrap_or_else(|x| x).into() } +#[proc_macro_attribute] +pub fn main_avr(args: TokenStream, item: TokenStream) -> TokenStream { + let args = syn::parse_macro_input!(args as Args); + let f = syn::parse_macro_input!(item as syn::ItemFn); + main::run(&args.meta, f, main::avr()).unwrap_or_else(|x| x).into() +} + /// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task. /// /// The following restrictions apply: diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 3c0d58567..088e64d1c 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -12,6 +12,20 @@ struct Args { entry: Option, } +pub fn avr() -> TokenStream { + quote! { + #[avr_device::entry] + fn main() -> ! { + let mut executor = ::embassy_executor::Executor::new(); + let executor = unsafe { __make_static(&mut executor) }; + + executor.run(|spawner| { + spawner.must_spawn(__embassy_main(spawner)); + }) + } + } +} + pub fn riscv(args: &[NestedMeta]) -> TokenStream { let maybe_entry = match Args::from_list(args) { Ok(args) => args.entry, diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index ec5aca46d..ade37913b 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -55,6 +55,7 @@ critical-section = { version = "1.1", features = ["std"] } # Architecture _arch = [] # some arch was picked +arch-avr = ["_arch", "dep:portable-atomic"] arch-std = ["_arch", "critical-section/std"] arch-cortex-m = ["_arch", "dep:cortex-m"] arch-riscv32 = ["_arch", "dep:portable-atomic"] diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs new file mode 100644 index 000000000..2c715f297 --- /dev/null +++ b/embassy-executor/src/arch/avr.rs @@ -0,0 +1,60 @@ +#[cfg(feature = "executor-interrupt")] +compile_error!("`executor-interrupt` is not supported with `arch-avr`."); + +#[cfg(feature = "executor-thread")] +pub use thread::*; +#[cfg(feature = "executor-thread")] +mod thread { + use core::marker::PhantomData; + + pub use embassy_executor_macros::main_avr as main; + + use crate::{raw, Spawner}; + + #[export_name = "__pender"] + fn __pender(_context: *mut ()) {} + + /// avr Executor + pub struct Executor { + inner: raw::Executor, + not_send: PhantomData<*mut ()>, + } + + impl Executor { + /// Create a new Executor. + pub fn new() -> Self { + Self { + inner: raw::Executor::new(core::ptr::null_mut()), + not_send: PhantomData, + } + } + + /// Run the executor. + /// + /// The `init` closure is called with a [`Spawner`] that spawns tasks on + /// this executor. Use it to spawn the initial task(s). After `init` returns, + /// the executor starts running the tasks. + /// + /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), + /// for example by passing it as an argument to the initial tasks. + /// + /// This function requires `&'static mut self`. This means you have to store the + /// Executor instance in a place where it'll live forever and grants you mutable + /// access. There's a few ways to do this: + /// + /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) + /// - a `static mut` (unsafe) + /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) + /// + /// This function never returns. + pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + init(self.inner.spawner()); + + loop { + unsafe { + self.inner.poll(); + } + } + } + } +} diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 4c6900a6d..834ebf16a 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -20,9 +20,10 @@ macro_rules! check_at_most_one { check_at_most_one!(@amo [$($f)*] [$($f)*] []); }; } -check_at_most_one!("arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); +check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); #[cfg(feature = "_arch")] +#[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] #[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")] #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] From 13af76af88a82f6c0f453b66520f0ff83df09c2d Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Mon, 11 Dec 2023 21:08:58 +1000 Subject: [PATCH 002/760] Add example for using CAN with STM32F103 (BluePill) with a real CAN --- examples/stm32f1/src/bin/can.rs | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 examples/stm32f1/src/bin/can.rs diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs new file mode 100644 index 000000000..abe60b350 --- /dev/null +++ b/examples/stm32f1/src/bin/can.rs @@ -0,0 +1,79 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::bind_interrupts; +use embassy_stm32::can::bxcan::filter::Mask32; +use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId, Id}; +use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; +use embassy_stm32::Config; + +use embassy_stm32::peripherals::CAN; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USB_LP_CAN1_RX0 => Rx0InterruptHandler; + CAN1_RX1 => Rx1InterruptHandler; + CAN1_SCE => SceInterruptHandler; + USB_HP_CAN1_TX => TxInterruptHandler; +}); + +// This example is configured to work with real CAN transceivers on B8/B9. +// See other examples for loopback. + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + + let p = embassy_stm32::init(Config::default()); + + // Set alternate pin mapping to B8/B9 + embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); + + let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); + + + can.as_mut() + .modify_filters() + .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + + can.as_mut() + .modify_config() + .set_loopback(false) + .set_silent(false) + .leave_disabled(); + + + can.set_bitrate(250_000); + + can.enable().await; + + + let mut i: u8 = 0; + loop { + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); + can.write(&tx_frame).await; + + match can.read().await { + Ok(env) => { + + match env.frame.id() { + Id::Extended(id) => { + defmt::println!("Extended Frame id={:x}", id.as_raw()); + }, + Id::Standard(id) => { + defmt::println!("Standard Frame id={:x}", id.as_raw()); + }, + } + + }, + Err(err) => { + defmt::println!("Error {}", err); + + } + } + i += 1; + } +} From b34c8e3eb1f3adab3e28c3b0b8ae3ab4c339c33b Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Mon, 11 Dec 2023 21:25:05 +1000 Subject: [PATCH 003/760] Update formatting. --- examples/stm32f1/src/bin/can.rs | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index abe60b350..625a3843c 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -4,13 +4,12 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::bind_interrupts; use embassy_stm32::can::bxcan::filter::Mask32; -use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId, Id}; +use embassy_stm32::can::bxcan::{Fifo, Frame, Id, StandardId}; use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; -use embassy_stm32::Config; use embassy_stm32::peripherals::CAN; +use embassy_stm32::{bind_interrupts, Config}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -23,10 +22,8 @@ bind_interrupts!(struct Irqs { // This example is configured to work with real CAN transceivers on B8/B9. // See other examples for loopback. - #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Config::default()); // Set alternate pin mapping to B8/B9 @@ -34,7 +31,6 @@ async fn main(_spawner: Spawner) { let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); - can.as_mut() .modify_filters() .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); @@ -44,34 +40,27 @@ async fn main(_spawner: Spawner) { .set_loopback(false) .set_silent(false) .leave_disabled(); - can.set_bitrate(250_000); can.enable().await; - let mut i: u8 = 0; loop { let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); can.write(&tx_frame).await; match can.read().await { - Ok(env) => { - - match env.frame.id() { - Id::Extended(id) => { - defmt::println!("Extended Frame id={:x}", id.as_raw()); - }, - Id::Standard(id) => { - defmt::println!("Standard Frame id={:x}", id.as_raw()); - }, + Ok(env) => match env.frame.id() { + Id::Extended(id) => { + defmt::println!("Extended Frame id={:x}", id.as_raw()); + } + Id::Standard(id) => { + defmt::println!("Standard Frame id={:x}", id.as_raw()); } - }, Err(err) => { defmt::println!("Error {}", err); - } } i += 1; From 3626deecaab1ed5b2f2c97ef49f6dbf058ad068a Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Mon, 11 Dec 2023 21:26:23 +1000 Subject: [PATCH 004/760] More formatting. --- examples/stm32f1/src/bin/can.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index 625a3843c..a5ce819d4 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -7,7 +7,6 @@ use embassy_executor::Spawner; use embassy_stm32::can::bxcan::filter::Mask32; use embassy_stm32::can::bxcan::{Fifo, Frame, Id, StandardId}; use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; - use embassy_stm32::peripherals::CAN; use embassy_stm32::{bind_interrupts, Config}; use {defmt_rtt as _, panic_probe as _}; @@ -54,7 +53,7 @@ async fn main(_spawner: Spawner) { Ok(env) => match env.frame.id() { Id::Extended(id) => { defmt::println!("Extended Frame id={:x}", id.as_raw()); - } + } Id::Standard(id) => { defmt::println!("Standard Frame id={:x}", id.as_raw()); } From 663fa2addd30463328f6186e14f98680b4a35c9b Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Mon, 11 Dec 2023 13:27:55 +0100 Subject: [PATCH 005/760] Introduce reset_{at|after} functions for Ticker. --- embassy-time/src/timer.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 574d715da..3444d3e24 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -184,6 +184,16 @@ impl Ticker { self.expires_at = Instant::now() + self.duration; } + /// Reset the ticker to fire for the next time on the deadline. + pub fn reset_at(&mut self, deadline: Instant) { + self.expires_at = deadline; + } + + /// Resets the ticker, after the specified duration has passed. + pub fn reset_after(&mut self, after: Duration) { + self.expires_at = Instant::now() + after; + } + /// Waits for the next tick. pub fn next(&mut self) -> impl Future + '_ { poll_fn(|cx| { From 8707462ec23807782796fbac4295bc5bce9ff136 Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Mon, 11 Dec 2023 16:11:57 +0100 Subject: [PATCH 006/760] Adjusted documentation and reset_after behaviour. --- embassy-time/src/timer.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 3444d3e24..fe0e93951 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -185,13 +185,15 @@ impl Ticker { } /// Reset the ticker to fire for the next time on the deadline. + /// If the deadline is in the past, the ticker will fire instantly. pub fn reset_at(&mut self, deadline: Instant) { self.expires_at = deadline; } /// Resets the ticker, after the specified duration has passed. + /// If the specified duration is zero, the next tick will be after the duration of the ticker. pub fn reset_after(&mut self, after: Duration) { - self.expires_at = Instant::now() + after; + self.expires_at = Instant::now() + after + self.duration; } /// Waits for the next tick. From 6782fb1efa1bd4c5372220bb38539ea1e7ef6ffa Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 13 Dec 2023 11:41:46 +0200 Subject: [PATCH 007/760] embassy-boot: Add explanation to dfu vs active size assertion --- embassy-boot/boot/src/boot_loader.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index a8c19197b..1663f4f2c 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs @@ -224,6 +224,7 @@ impl BootLoader( ) { assert_eq!(active.capacity() as u32 % page_size, 0); assert_eq!(dfu.capacity() as u32 % page_size, 0); + // DFU partition has to be bigger than ACTIVE partition to handle swap algorithm assert!(dfu.capacity() as u32 - active.capacity() as u32 >= page_size); assert!(2 + 2 * (active.capacity() as u32 / page_size) <= state.capacity() as u32 / STATE::WRITE_SIZE as u32); } From 172ed52128e0da519c13b7a354aeb98c492be3c3 Mon Sep 17 00:00:00 2001 From: sodo Date: Tue, 12 Dec 2023 16:51:24 +0900 Subject: [PATCH 008/760] ci.sh: add avr --- ci.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci.sh b/ci.sh index 8a5e206d2..a5ddda3a1 100755 --- a/ci.sh +++ b/ci.sh @@ -207,6 +207,10 @@ cargo batch \ --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ $BUILD_EXTRA +# walkaround: "-Z" option not working on cargo batch +cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr +cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,integrated-timers + rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble From d596a1091d25e89533d08a1f96678f1c1182dc40 Mon Sep 17 00:00:00 2001 From: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:17:07 -0500 Subject: [PATCH 009/760] add `susependable` field to `embassy_usb::builder::Config` - allow for optional override of `Suspend` event for a UsbDevice --- embassy-usb/src/builder.rs | 10 ++++++++++ embassy-usb/src/lib.rs | 8 +++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index c4705d041..ebc1283e6 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -94,6 +94,15 @@ pub struct Config<'a> { /// Default: 100mA /// Max: 500mA pub max_power: u16, + + /// Allow the bus to be suspended. + /// + /// If set to `true`, the bus will put itself in the suspended state + /// when it receives a `driver::Event::Suspend` bus event. If you wish + /// to override this behavior, set this field to `false`. + /// + /// Default: `true` + pub suspendable: bool, } impl<'a> Config<'a> { @@ -114,6 +123,7 @@ impl<'a> Config<'a> { supports_remote_wakeup: false, composite_with_iads: false, max_power: 100, + suspendable: true, } } } diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 241e33a78..ff3295871 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -471,9 +471,11 @@ impl<'d, D: Driver<'d>> Inner<'d, D> { } Event::Suspend => { trace!("usb: suspend"); - self.suspended = true; - for h in &mut self.handlers { - h.suspended(true); + if self.config.suspendable { + self.suspended = true; + for h in &mut self.handlers { + h.suspended(true); + } } } Event::PowerDetected => { From 876faa5685de66ce422bc9196f2442195cdff63b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 13 Dec 2023 19:00:26 +0100 Subject: [PATCH 010/760] docs: more docs in embassy-boot crate documentation --- docs/modules/ROOT/pages/bootloader.adoc | 4 +++- embassy-boot/boot/README.md | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/bootloader.adoc b/docs/modules/ROOT/pages/bootloader.adoc index b7215e52a..3b0cdb182 100644 --- a/docs/modules/ROOT/pages/bootloader.adoc +++ b/docs/modules/ROOT/pages/bootloader.adoc @@ -45,6 +45,8 @@ The BOOTLOADER_STATE partition must be big enough to store one word per page in The bootloader has a platform-agnostic part, which implements the power fail safe swapping algorithm given the boundaries set by the partitions. The platform-specific part is a minimal shim that provides additional functionality such as watchdogs or supporting the nRF52 softdevice. +NOTE: The linker scripts for the application and bootloader look similar, but the FLASH region must point to the BOOTLOADER partition for the bootloader, and the ACTIVE partition for the application. + === FirmwareUpdater The `FirmwareUpdater` is an object for conveniently flashing firmware to the DFU partition and subsequently marking it as being ready for swapping with the active partition on the next reset. Its principle methods are `write_firmware`, which is called once per the size of the flash "write block" (typically 4KiB), and `mark_updated`, which is the final call. @@ -91,4 +93,4 @@ cp $FIRMWARE_DIR/myfirmware $FIRMWARE_DIR/myfirmware+signed tail -n1 $SECRETS_DIR/message.txt.sig | base64 -d -i - | dd ibs=10 skip=1 >> $FIRMWARE_DIR/myfirmware+signed ---- -Remember, guard the `$SECRETS_DIR/key.sec` key as compromising it means that another party can sign your firmware. \ No newline at end of file +Remember, guard the `$SECRETS_DIR/key.sec` key as compromising it means that another party can sign your firmware. diff --git a/embassy-boot/boot/README.md b/embassy-boot/boot/README.md index 07755bc6c..3fc81f24b 100644 --- a/embassy-boot/boot/README.md +++ b/embassy-boot/boot/README.md @@ -8,6 +8,24 @@ The bootloader can be used either as a library or be flashed directly with the d By design, the bootloader does not provide any network capabilities. Networking capabilities for fetching new firmware can be provided by the user application, using the bootloader as a library for updating the firmware, or by using the bootloader as a library and adding this capability yourself. +## Overview + +The bootloader divides the storage into 4 main partitions, configurable when creating the bootloader instance or via linker scripts: + +* 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. + +For any partition, the following preconditions are required: + +* Partitions must be aligned on the page size. +* Partitions must be a multiple of the page size. + +The linker scripts for the application and bootloader look similar, but the FLASH region must point to the BOOTLOADER partition for the bootloader, and the ACTIVE partition for the application. + +For more details on the bootloader, see [the documentation](https://embassy.dev/book/dev/bootloader.html). + ## Hardware support The bootloader supports different hardware in separate crates: @@ -16,6 +34,7 @@ The bootloader supports different hardware in separate crates: * `embassy-boot-rp` - for the RP2040 microcontrollers. * `embassy-boot-stm32` - for the STM32 microcontrollers. + ## Minimum supported Rust version (MSRV) `embassy-boot` is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. From 976a7ae22aa222213861c12d515115aac87bd2e0 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Wed, 13 Dec 2023 14:40:49 -0500 Subject: [PATCH 011/760] Add embassy-usb-dfu --- embassy-boot/boot/src/boot_loader.rs | 4 +- .../boot/src/firmware_updater/asynch.rs | 13 +- .../boot/src/firmware_updater/blocking.rs | 17 +- embassy-boot/boot/src/lib.rs | 3 + embassy-boot/stm32/src/lib.rs | 9 +- embassy-usb-dfu/Cargo.toml | 31 +++ embassy-usb-dfu/src/application.rs | 114 ++++++++++ embassy-usb-dfu/src/bootloader.rs | 196 ++++++++++++++++++ embassy-usb-dfu/src/consts.rs | 96 +++++++++ embassy-usb-dfu/src/lib.rs | 16 ++ 10 files changed, 492 insertions(+), 7 deletions(-) create mode 100644 embassy-usb-dfu/Cargo.toml create mode 100644 embassy-usb-dfu/src/application.rs create mode 100644 embassy-usb-dfu/src/bootloader.rs create mode 100644 embassy-usb-dfu/src/consts.rs create mode 100644 embassy-usb-dfu/src/lib.rs diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index a8c19197b..c0deca22b 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs @@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; -use crate::{State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, DFU_DETACH_MAGIC}; /// Errors returned by bootloader #[derive(PartialEq, Eq, Debug)] @@ -384,6 +384,8 @@ impl BootLoader FirmwareUpdater<'d, DFU, STATE> { self.state.mark_updated().await } + /// Mark to trigger USB DFU on next boot. + pub async fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> { + self.state.verify_booted().await?; + self.state.mark_dfu().await + } + /// Mark firmware boot successful and stop rollback on reset. pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { self.state.mark_booted().await @@ -247,6 +253,11 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { self.set_magic(SWAP_MAGIC).await } + /// Mark to trigger USB DFU on next boot. + pub async fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> { + self.set_magic(DFU_DETACH_MAGIC).await + } + /// Mark firmware boot successful and stop rollback on reset. pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { self.set_magic(BOOT_MAGIC).await diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs index 76e4264a0..b2a633d1e 100644 --- a/embassy-boot/boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/boot/src/firmware_updater/blocking.rs @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage::nor_flash::NorFlash; use super::FirmwareUpdaterConfig; -use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, DFU_DETACH_MAGIC}; /// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to /// 'mess up' the internal bootloader state @@ -168,6 +168,12 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> self.state.mark_updated() } + /// Mark to trigger USB DFU device on next boot. + pub fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> { + self.state.verify_booted()?; + self.state.mark_dfu() + } + /// Mark firmware boot successful and stop rollback on reset. pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { self.state.mark_booted() @@ -226,7 +232,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { // Make sure we are running a booted firmware to avoid reverting to a bad state. fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { - if self.get_state()? == State::Boot { + if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach { Ok(()) } else { Err(FirmwareUpdaterError::BadState) @@ -243,6 +249,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { Ok(State::Swap) + } else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) { + Ok(State::DfuDetach) } else { Ok(State::Boot) } @@ -253,6 +261,11 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { self.set_magic(SWAP_MAGIC) } + /// Mark to trigger USB DFU on next boot. + pub fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> { + self.set_magic(DFU_DETACH_MAGIC) + } + /// Mark firmware boot successful and stop rollback on reset. pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { self.set_magic(BOOT_MAGIC) diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 9e70a4dca..451992945 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -23,6 +23,7 @@ pub use firmware_updater::{ pub(crate) const BOOT_MAGIC: u8 = 0xD0; pub(crate) const SWAP_MAGIC: u8 = 0xF0; +pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0; /// The state of the bootloader after running prepare. #[derive(PartialEq, Eq, Debug)] @@ -32,6 +33,8 @@ pub enum State { Boot, /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. Swap, + /// Application has received a DFU_DETACH request over USB, and is rebooting into the bootloader to apply a DFU. + DfuDetach, } /// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs index c418cb262..4b4091ac9 100644 --- a/embassy-boot/stm32/src/lib.rs +++ b/embassy-boot/stm32/src/lib.rs @@ -10,7 +10,10 @@ pub use embassy_boot::{ use embedded_storage::nor_flash::NorFlash; /// A bootloader for STM32 devices. -pub struct BootLoader; +pub struct BootLoader { + /// The reported state of the bootloader after preparing for boot + pub state: State, +} impl BootLoader { /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware @@ -19,8 +22,8 @@ impl BootLoader { ) -> Self { let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); let mut boot = embassy_boot::BootLoader::new(config); - boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); - Self + let state = boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); + Self { state } } /// Boots the application. diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml new file mode 100644 index 000000000..62398afbc --- /dev/null +++ b/embassy-usb-dfu/Cargo.toml @@ -0,0 +1,31 @@ +[package] +edition = "2021" +name = "embassy-usb-dfu" +version = "0.1.0" +description = "An implementation of the USB DFU 1.1 protocol, using embassy-boot" +license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +categories = [ + "embedded", + "no-std", + "asynchronous" +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bitflags = "2.4.1" +cortex-m = { version = "0.7.7", features = ["inline-asm"] } +defmt = { version = "0.3.5", optional = true } +embassy-boot = { version = "0.1.1", path = "../embassy-boot/boot" } +embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-futures = { version = "0.1.1", path = "../embassy-futures" } +embassy-sync = { version = "0.5.0", path = "../embassy-sync" } +embassy-time = { version = "0.2.0", path = "../embassy-time" } +embassy-usb = { version = "0.1.0", path = "../embassy-usb", default-features = false } +embedded-storage = { version = "0.3.1" } + +[features] +bootloader = [] +application = [] +defmt = ["dep:defmt"] diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs new file mode 100644 index 000000000..5a52a9fed --- /dev/null +++ b/embassy-usb-dfu/src/application.rs @@ -0,0 +1,114 @@ + +use embassy_boot::BlockingFirmwareUpdater; +use embassy_time::{Instant, Duration}; +use embassy_usb::{Handler, control::{RequestType, Recipient, OutResponse, InResponse}, Builder, driver::Driver}; +use embedded_storage::nor_flash::NorFlash; + +use crate::consts::{DfuAttributes, Request, Status, State, USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT}; + +/// Internal state for the DFU class +pub struct Control<'d, DFU: NorFlash, STATE: NorFlash> { + updater: BlockingFirmwareUpdater<'d, DFU, STATE>, + attrs: DfuAttributes, + state: State, + timeout: Option, + detach_start: Option, +} + +impl<'d, DFU: NorFlash, STATE: NorFlash> Control<'d, DFU, STATE> { + pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { + Control { updater, attrs, state: State::AppIdle, detach_start: None, timeout: None } + } +} + +impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { + fn reset(&mut self) { + if let Some(start) = self.detach_start { + let delta = Instant::now() - start; + let timeout = self.timeout.unwrap(); + #[cfg(feature = "defmt")] + defmt::info!("Received RESET with delta = {}, timeout = {}", delta.as_millis(), timeout.as_millis()); + if delta < timeout { + self.updater.mark_dfu().expect("Failed to mark DFU mode in bootloader"); + cortex_m::asm::dsb(); + cortex_m::peripheral::SCB::sys_reset(); + } + } + } + + fn control_out(&mut self, req: embassy_usb::control::Request, _: &[u8]) -> Option { + if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { + return None; + } + + #[cfg(feature = "defmt")] + defmt::info!("Received request {}", req); + + match Request::try_from(req.request) { + Ok(Request::Detach) => { + #[cfg(feature = "defmt")] + defmt::info!("Received DETACH, awaiting USB reset"); + self.detach_start = Some(Instant::now()); + self.timeout = Some(Duration::from_millis(req.value as u64)); + self.state = State::AppDetach; + Some(OutResponse::Accepted) + } + _ => { + None + } + } + } + + fn control_in<'a>(&'a mut self, req: embassy_usb::control::Request, buf: &'a mut [u8]) -> Option> { + if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { + return None; + } + + #[cfg(feature = "defmt")] + defmt::info!("Received request {}", req); + + match Request::try_from(req.request) { + Ok(Request::GetStatus) => { + buf[0..6].copy_from_slice(&[Status::Ok as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]); + Some(InResponse::Accepted(buf)) + } + _ => None + } + } +} + +/// An implementation of the USB DFU 1.1 runtime protocol +/// +/// This function will add a DFU interface descriptor to the provided Builder, and register the provided Control as a handler for the USB device. The USB builder can be used as normal once this is complete. +/// The handler is responsive to DFU GetStatus and Detach commands. +/// +/// Once a detach command, followed by a USB reset is received by the host, a magic number will be written into the bootloader state partition to indicate that +/// it should expose a DFU device, and a software reset will be issued. +/// +/// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. +pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>(builder: &mut Builder<'d, D>, handler: &'d mut Control<'d, DFU, STATE>, timeout: Duration) { + #[cfg(feature = "defmt")] + defmt::info!("Application USB DFU initializing"); + let mut func = builder.function(0x00, 0x00, 0x00); + let mut iface = func.interface(); + let mut alt = iface.alt_setting( + USB_CLASS_APPN_SPEC, + APPN_SPEC_SUBCLASS_DFU, + DFU_PROTOCOL_RT, + None, + ); + let timeout = timeout.as_millis() as u16; + alt.descriptor( + DESC_DFU_FUNCTIONAL, + &[ + handler.attrs.bits(), + (timeout & 0xff) as u8, + ((timeout >> 8) & 0xff) as u8, + 0x40, 0x00, // 64B control buffer size for application side + 0x10, 0x01, // DFU 1.1 + ], + ); + + drop(func); + builder.handler(handler); +} \ No newline at end of file diff --git a/embassy-usb-dfu/src/bootloader.rs b/embassy-usb-dfu/src/bootloader.rs new file mode 100644 index 000000000..7bcb0b258 --- /dev/null +++ b/embassy-usb-dfu/src/bootloader.rs @@ -0,0 +1,196 @@ +use embassy_boot::BlockingFirmwareUpdater; +use embassy_usb::{ + control::{InResponse, OutResponse, Recipient, RequestType}, + driver::Driver, + Builder, Handler, +}; +use embedded_storage::nor_flash::{NorFlashErrorKind, NorFlash}; + +use crate::consts::{DfuAttributes, Request, State, Status, USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, DESC_DFU_FUNCTIONAL}; + +/// Internal state for USB DFU +pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> { + updater: BlockingFirmwareUpdater<'d, DFU, STATE>, + attrs: DfuAttributes, + state: State, + status: Status, + offset: usize, +} + +impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, BLOCK_SIZE> { + pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { + Self { + updater, + attrs, + state: State::DfuIdle, + status: Status::Ok, + offset: 0, + } + } + + fn reset_state(&mut self) { + self.offset = 0; + self.state = State::DfuIdle; + self.status = Status::Ok; + } +} + +impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Control<'d, DFU, STATE, BLOCK_SIZE> { + fn control_out( + &mut self, + req: embassy_usb::control::Request, + data: &[u8], + ) -> Option { + if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { + return None; + } + match Request::try_from(req.request) { + Ok(Request::Abort) => { + self.reset_state(); + Some(OutResponse::Accepted) + } + Ok(Request::Dnload) if self.attrs.contains(DfuAttributes::CAN_DOWNLOAD) => { + if req.value == 0 { + self.state = State::Download; + self.offset = 0; + } + + let mut buf = [0; BLOCK_SIZE]; + buf[..data.len()].copy_from_slice(data); + + if req.length == 0 { + match self.updater.mark_updated() { + Ok(_) => { + self.status = Status::Ok; + self.state = State::ManifestSync; + } + Err(e) => { + self.state = State::Error; + match e { + embassy_boot::FirmwareUpdaterError::Flash(e) => match e { + NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite, + NorFlashErrorKind::OutOfBounds => { + self.status = Status::ErrAddress + } + _ => self.status = Status::ErrUnknown, + }, + embassy_boot::FirmwareUpdaterError::Signature(_) => { + self.status = Status::ErrVerify + } + embassy_boot::FirmwareUpdaterError::BadState => { + self.status = Status::ErrUnknown + } + } + } + } + } else { + if self.state != State::Download { + // Unexpected DNLOAD while chip is waiting for a GETSTATUS + self.status = Status::ErrUnknown; + self.state = State::Error; + return Some(OutResponse::Rejected); + } + match self.updater.write_firmware(self.offset, &buf[..]) { + Ok(_) => { + self.status = Status::Ok; + self.state = State::DlSync; + self.offset += data.len(); + } + Err(e) => { + self.state = State::Error; + match e { + embassy_boot::FirmwareUpdaterError::Flash(e) => match e { + NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite, + NorFlashErrorKind::OutOfBounds => { + self.status = Status::ErrAddress + } + _ => self.status = Status::ErrUnknown, + }, + embassy_boot::FirmwareUpdaterError::Signature(_) => { + self.status = Status::ErrVerify + } + embassy_boot::FirmwareUpdaterError::BadState => { + self.status = Status::ErrUnknown + } + } + } + } + } + + Some(OutResponse::Accepted) + } + Ok(Request::Detach) => Some(OutResponse::Accepted), // Device is already in DFU mode + Ok(Request::ClrStatus) => { + self.reset_state(); + Some(OutResponse::Accepted) + } + _ => None, + } + } + + fn control_in<'a>( + &'a mut self, + req: embassy_usb::control::Request, + buf: &'a mut [u8], + ) -> Option> { + if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { + return None; + } + match Request::try_from(req.request) { + Ok(Request::GetStatus) => { + //TODO: Configurable poll timeout, ability to add string for Vendor error + buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]); + match self.state { + State::DlSync => self.state = State::Download, + State::ManifestSync => cortex_m::peripheral::SCB::sys_reset(), + _ => {} + } + + Some(InResponse::Accepted(&buf[0..6])) + } + Ok(Request::GetState) => { + buf[0] = self.state as u8; + Some(InResponse::Accepted(&buf[0..1])) + } + Ok(Request::Upload) if self.attrs.contains(DfuAttributes::CAN_UPLOAD) => { + //TODO: FirmwareUpdater does not provide a way of reading the active partition, can't upload. + Some(InResponse::Rejected) + } + _ => None, + } + } +} + +/// An implementation of the USB DFU 1.1 protocol +/// +/// This function will add a DFU interface descriptor to the provided Builder, and register the provided Control as a handler for the USB device +/// The handler is responsive to DFU GetState, GetStatus, Abort, and ClrStatus commands, as well as Download if configured by the user. +/// +/// Once the host has initiated a DFU download operation, the chunks sent by the host will be written to the DFU partition. +/// Once the final sync in the manifestation phase has been received, the handler will trigger a system reset to swap the new firmware. +pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize>( + builder: &mut Builder<'d, D>, + handler: &'d mut Control<'d, DFU, STATE, BLOCK_SIZE>, +) { + let mut func = builder.function(0x00, 0x00, 0x00); + let mut iface = func.interface(); + let mut alt = iface.alt_setting( + USB_CLASS_APPN_SPEC, + APPN_SPEC_SUBCLASS_DFU, + DFU_PROTOCOL_DFU, + None, + ); + alt.descriptor( + DESC_DFU_FUNCTIONAL, + &[ + handler.attrs.bits(), + 0xc4, 0x09, // 2500ms timeout, doesn't affect operation as DETACH not necessary in bootloader code + (BLOCK_SIZE & 0xff) as u8, + ((BLOCK_SIZE & 0xff00) >> 8) as u8, + 0x10, 0x01, // DFU 1.1 + ], + ); + + drop(func); + builder.handler(handler); +} diff --git a/embassy-usb-dfu/src/consts.rs b/embassy-usb-dfu/src/consts.rs new file mode 100644 index 000000000..b083af9de --- /dev/null +++ b/embassy-usb-dfu/src/consts.rs @@ -0,0 +1,96 @@ + +pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE; +pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01; +#[allow(unused)] +pub(crate) const DFU_PROTOCOL_DFU: u8 = 0x02; +#[allow(unused)] +pub(crate) const DFU_PROTOCOL_RT: u8 = 0x01; +pub(crate) const DESC_DFU_FUNCTIONAL: u8 = 0x21; + +#[cfg(feature = "defmt")] +defmt::bitflags! { + pub struct DfuAttributes: u8 { + const WILL_DETACH = 0b0000_1000; + const MANIFESTATION_TOLERANT = 0b0000_0100; + const CAN_UPLOAD = 0b0000_0010; + const CAN_DOWNLOAD = 0b0000_0001; + } +} + +#[cfg(not(feature = "defmt"))] +bitflags::bitflags! { + pub struct DfuAttributes: u8 { + const WILL_DETACH = 0b0000_1000; + const MANIFESTATION_TOLERANT = 0b0000_0100; + const CAN_UPLOAD = 0b0000_0010; + const CAN_DOWNLOAD = 0b0000_0001; + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +#[allow(unused)] +pub enum State { + AppIdle = 0, + AppDetach = 1, + DfuIdle = 2, + DlSync = 3, + DlBusy = 4, + Download = 5, + ManifestSync = 6, + Manifest = 7, + ManifestWaitReset = 8, + UploadIdle = 9, + Error = 10, +} + +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +#[allow(unused)] +pub enum Status { + Ok = 0x00, + ErrTarget = 0x01, + ErrFile = 0x02, + ErrWrite = 0x03, + ErrErase = 0x04, + ErrCheckErased = 0x05, + ErrProg = 0x06, + ErrVerify = 0x07, + ErrAddress = 0x08, + ErrNotDone = 0x09, + ErrFirmware = 0x0A, + ErrVendor = 0x0B, + ErrUsbr = 0x0C, + ErrPor = 0x0D, + ErrUnknown = 0x0E, + ErrStalledPkt = 0x0F, +} + +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +pub enum Request { + Detach = 0, + Dnload = 1, + Upload = 2, + GetStatus = 3, + ClrStatus = 4, + GetState = 5, + Abort = 6, +} + +impl TryFrom for Request { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Request::Detach), + 1 => Ok(Request::Dnload), + 2 => Ok(Request::Upload), + 3 => Ok(Request::GetStatus), + 4 => Ok(Request::ClrStatus), + 5 => Ok(Request::GetState), + 6 => Ok(Request::Abort), + _ => Err(()), + } + } +} diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs new file mode 100644 index 000000000..dcdb11b2a --- /dev/null +++ b/embassy-usb-dfu/src/lib.rs @@ -0,0 +1,16 @@ +#![no_std] + +pub mod consts; + +#[cfg(feature = "bootloader")] +mod bootloader; +#[cfg(feature = "bootloader")] +pub use self::bootloader::*; + +#[cfg(feature = "application")] +mod application; +#[cfg(feature = "application")] +pub use self::application::*; + +#[cfg(any(all(feature = "bootloader", feature = "application"), not(any(feature = "bootloader", feature = "application"))))] +compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features"); From 6bf70e14fb14882ce6adf0d47179b7408bdcb184 Mon Sep 17 00:00:00 2001 From: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed, 13 Dec 2023 14:50:13 -0500 Subject: [PATCH 012/760] Update usb.rs - add check of `dev_resume_from_host` interrupt register to catch wake event --- embassy-rp/src/usb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 4ab881f6e..4a74ee6f7 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -363,7 +363,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { let siestatus = regs.sie_status().read(); let intrstatus = regs.intr().read(); - if siestatus.resume() { + if siestatus.resume() || intrstatus.dev_resume_from_host() { regs.sie_status().write(|w| w.set_resume(true)); return Poll::Ready(Event::Resume); } From c2942f2727739d8972ad211721b1bb1804fb7b4a Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Wed, 13 Dec 2023 14:53:49 -0500 Subject: [PATCH 013/760] fmt --- embassy-usb-dfu/src/application.rs | 75 +++++++++++++++++++----------- embassy-usb-dfu/src/bootloader.rs | 56 +++++++++------------- embassy-usb-dfu/src/consts.rs | 1 - embassy-usb-dfu/src/lib.rs | 5 +- 4 files changed, 73 insertions(+), 64 deletions(-) diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 5a52a9fed..2e7bda121 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -1,10 +1,14 @@ - use embassy_boot::BlockingFirmwareUpdater; -use embassy_time::{Instant, Duration}; -use embassy_usb::{Handler, control::{RequestType, Recipient, OutResponse, InResponse}, Builder, driver::Driver}; +use embassy_time::{Duration, Instant}; +use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; +use embassy_usb::driver::Driver; +use embassy_usb::{Builder, Handler}; use embedded_storage::nor_flash::NorFlash; -use crate::consts::{DfuAttributes, Request, Status, State, USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT}; +use crate::consts::{ + DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT, + USB_CLASS_APPN_SPEC, +}; /// Internal state for the DFU class pub struct Control<'d, DFU: NorFlash, STATE: NorFlash> { @@ -17,7 +21,13 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash> { impl<'d, DFU: NorFlash, STATE: NorFlash> Control<'d, DFU, STATE> { pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { - Control { updater, attrs, state: State::AppIdle, detach_start: None, timeout: None } + Control { + updater, + attrs, + state: State::AppIdle, + detach_start: None, + timeout: None, + } } } @@ -27,7 +37,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { let delta = Instant::now() - start; let timeout = self.timeout.unwrap(); #[cfg(feature = "defmt")] - defmt::info!("Received RESET with delta = {}, timeout = {}", delta.as_millis(), timeout.as_millis()); + defmt::info!( + "Received RESET with delta = {}, timeout = {}", + delta.as_millis(), + timeout.as_millis() + ); if delta < timeout { self.updater.mark_dfu().expect("Failed to mark DFU mode in bootloader"); cortex_m::asm::dsb(); @@ -36,7 +50,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { } } - fn control_out(&mut self, req: embassy_usb::control::Request, _: &[u8]) -> Option { + fn control_out( + &mut self, + req: embassy_usb::control::Request, + _: &[u8], + ) -> Option { if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { return None; } @@ -53,13 +71,15 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { self.state = State::AppDetach; Some(OutResponse::Accepted) } - _ => { - None - } + _ => None, } } - fn control_in<'a>(&'a mut self, req: embassy_usb::control::Request, buf: &'a mut [u8]) -> Option> { + fn control_in<'a>( + &'a mut self, + req: embassy_usb::control::Request, + buf: &'a mut [u8], + ) -> Option> { if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { return None; } @@ -72,31 +92,30 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { buf[0..6].copy_from_slice(&[Status::Ok as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]); Some(InResponse::Accepted(buf)) } - _ => None + _ => None, } } } /// An implementation of the USB DFU 1.1 runtime protocol -/// +/// /// This function will add a DFU interface descriptor to the provided Builder, and register the provided Control as a handler for the USB device. The USB builder can be used as normal once this is complete. -/// The handler is responsive to DFU GetStatus and Detach commands. -/// +/// The handler is responsive to DFU GetStatus and Detach commands. +/// /// Once a detach command, followed by a USB reset is received by the host, a magic number will be written into the bootloader state partition to indicate that /// it should expose a DFU device, and a software reset will be issued. -/// +/// /// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. -pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>(builder: &mut Builder<'d, D>, handler: &'d mut Control<'d, DFU, STATE>, timeout: Duration) { +pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>( + builder: &mut Builder<'d, D>, + handler: &'d mut Control<'d, DFU, STATE>, + timeout: Duration, +) { #[cfg(feature = "defmt")] defmt::info!("Application USB DFU initializing"); let mut func = builder.function(0x00, 0x00, 0x00); let mut iface = func.interface(); - let mut alt = iface.alt_setting( - USB_CLASS_APPN_SPEC, - APPN_SPEC_SUBCLASS_DFU, - DFU_PROTOCOL_RT, - None, - ); + let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None); let timeout = timeout.as_millis() as u16; alt.descriptor( DESC_DFU_FUNCTIONAL, @@ -104,11 +123,13 @@ pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>(builder: &mut handler.attrs.bits(), (timeout & 0xff) as u8, ((timeout >> 8) & 0xff) as u8, - 0x40, 0x00, // 64B control buffer size for application side - 0x10, 0x01, // DFU 1.1 + 0x40, + 0x00, // 64B control buffer size for application side + 0x10, + 0x01, // DFU 1.1 ], ); drop(func); - builder.handler(handler); -} \ No newline at end of file + builder.handler(handler); +} diff --git a/embassy-usb-dfu/src/bootloader.rs b/embassy-usb-dfu/src/bootloader.rs index 7bcb0b258..215058932 100644 --- a/embassy-usb-dfu/src/bootloader.rs +++ b/embassy-usb-dfu/src/bootloader.rs @@ -1,12 +1,13 @@ use embassy_boot::BlockingFirmwareUpdater; -use embassy_usb::{ - control::{InResponse, OutResponse, Recipient, RequestType}, - driver::Driver, - Builder, Handler, -}; -use embedded_storage::nor_flash::{NorFlashErrorKind, NorFlash}; +use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; +use embassy_usb::driver::Driver; +use embassy_usb::{Builder, Handler}; +use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind}; -use crate::consts::{DfuAttributes, Request, State, Status, USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, DESC_DFU_FUNCTIONAL}; +use crate::consts::{ + DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU, + USB_CLASS_APPN_SPEC, +}; /// Internal state for USB DFU pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> { @@ -69,17 +70,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co match e { embassy_boot::FirmwareUpdaterError::Flash(e) => match e { NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite, - NorFlashErrorKind::OutOfBounds => { - self.status = Status::ErrAddress - } + NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress, _ => self.status = Status::ErrUnknown, }, - embassy_boot::FirmwareUpdaterError::Signature(_) => { - self.status = Status::ErrVerify - } - embassy_boot::FirmwareUpdaterError::BadState => { - self.status = Status::ErrUnknown - } + embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify, + embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown, } } } @@ -101,17 +96,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co match e { embassy_boot::FirmwareUpdaterError::Flash(e) => match e { NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite, - NorFlashErrorKind::OutOfBounds => { - self.status = Status::ErrAddress - } + NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress, _ => self.status = Status::ErrUnknown, }, - embassy_boot::FirmwareUpdaterError::Signature(_) => { - self.status = Status::ErrVerify - } - embassy_boot::FirmwareUpdaterError::BadState => { - self.status = Status::ErrUnknown - } + embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify, + embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown, } } } @@ -162,10 +151,10 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co } /// An implementation of the USB DFU 1.1 protocol -/// +/// /// This function will add a DFU interface descriptor to the provided Builder, and register the provided Control as a handler for the USB device /// The handler is responsive to DFU GetState, GetStatus, Abort, and ClrStatus commands, as well as Download if configured by the user. -/// +/// /// Once the host has initiated a DFU download operation, the chunks sent by the host will be written to the DFU partition. /// Once the final sync in the manifestation phase has been received, the handler will trigger a system reset to swap the new firmware. pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize>( @@ -174,20 +163,17 @@ pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, const BLOCK_SI ) { let mut func = builder.function(0x00, 0x00, 0x00); let mut iface = func.interface(); - let mut alt = iface.alt_setting( - USB_CLASS_APPN_SPEC, - APPN_SPEC_SUBCLASS_DFU, - DFU_PROTOCOL_DFU, - None, - ); + let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, None); alt.descriptor( DESC_DFU_FUNCTIONAL, &[ handler.attrs.bits(), - 0xc4, 0x09, // 2500ms timeout, doesn't affect operation as DETACH not necessary in bootloader code + 0xc4, + 0x09, // 2500ms timeout, doesn't affect operation as DETACH not necessary in bootloader code (BLOCK_SIZE & 0xff) as u8, ((BLOCK_SIZE & 0xff00) >> 8) as u8, - 0x10, 0x01, // DFU 1.1 + 0x10, + 0x01, // DFU 1.1 ], ); diff --git a/embassy-usb-dfu/src/consts.rs b/embassy-usb-dfu/src/consts.rs index b083af9de..b359a107e 100644 --- a/embassy-usb-dfu/src/consts.rs +++ b/embassy-usb-dfu/src/consts.rs @@ -1,4 +1,3 @@ - pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE; pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01; #[allow(unused)] diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs index dcdb11b2a..81ef041f8 100644 --- a/embassy-usb-dfu/src/lib.rs +++ b/embassy-usb-dfu/src/lib.rs @@ -12,5 +12,8 @@ mod application; #[cfg(feature = "application")] pub use self::application::*; -#[cfg(any(all(feature = "bootloader", feature = "application"), not(any(feature = "bootloader", feature = "application"))))] +#[cfg(any( + all(feature = "bootloader", feature = "application"), + not(any(feature = "bootloader", feature = "application")) +))] compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features"); From 702d2a1a193985c9b8da6fc5e532ac55b5485464 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Wed, 13 Dec 2023 16:08:20 -0500 Subject: [PATCH 014/760] Formatting fixes, add example using stm32wb55 --- .../boot/src/firmware_updater/asynch.rs | 2 +- .../boot/src/firmware_updater/blocking.rs | 2 +- examples/boot-usb-dfu/.cargo/config.toml | 9 ++ .../application/stm32wb/.cargo/config.toml | 9 ++ .../application/stm32wb/Cargo.toml | 32 +++++++ .../application/stm32wb/README.md | 29 ++++++ .../boot-usb-dfu/application/stm32wb/build.rs | 37 ++++++++ .../boot-usb-dfu/application/stm32wb/memory.x | 15 +++ .../application/stm32wb/src/main.rs | 64 +++++++++++++ .../bootloader/stm32wb/Cargo.toml | 63 ++++++++++++ .../boot-usb-dfu/bootloader/stm32wb/README.md | 11 +++ .../boot-usb-dfu/bootloader/stm32wb/build.rs | 27 ++++++ .../boot-usb-dfu/bootloader/stm32wb/memory.x | 18 ++++ .../bootloader/stm32wb/src/main.rs | 95 +++++++++++++++++++ 14 files changed, 411 insertions(+), 2 deletions(-) create mode 100644 examples/boot-usb-dfu/.cargo/config.toml create mode 100644 examples/boot-usb-dfu/application/stm32wb/.cargo/config.toml create mode 100644 examples/boot-usb-dfu/application/stm32wb/Cargo.toml create mode 100644 examples/boot-usb-dfu/application/stm32wb/README.md create mode 100644 examples/boot-usb-dfu/application/stm32wb/build.rs create mode 100644 examples/boot-usb-dfu/application/stm32wb/memory.x create mode 100644 examples/boot-usb-dfu/application/stm32wb/src/main.rs create mode 100644 examples/boot-usb-dfu/bootloader/stm32wb/Cargo.toml create mode 100644 examples/boot-usb-dfu/bootloader/stm32wb/README.md create mode 100644 examples/boot-usb-dfu/bootloader/stm32wb/build.rs create mode 100644 examples/boot-usb-dfu/bootloader/stm32wb/memory.x create mode 100644 examples/boot-usb-dfu/bootloader/stm32wb/src/main.rs diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs index 0a3cbc136..82e99965b 100644 --- a/embassy-boot/boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/boot/src/firmware_updater/asynch.rs @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage_async::nor_flash::NorFlash; use super::FirmwareUpdaterConfig; -use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, DFU_DETACH_MAGIC}; +use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; /// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to /// 'mess up' the internal bootloader state diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs index b2a633d1e..ae4179ba3 100644 --- a/embassy-boot/boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/boot/src/firmware_updater/blocking.rs @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage::nor_flash::NorFlash; use super::FirmwareUpdaterConfig; -use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, DFU_DETACH_MAGIC}; +use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; /// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to /// 'mess up' the internal bootloader state diff --git a/examples/boot-usb-dfu/.cargo/config.toml b/examples/boot-usb-dfu/.cargo/config.toml new file mode 100644 index 000000000..de3a814f7 --- /dev/null +++ b/examples/boot-usb-dfu/.cargo/config.toml @@ -0,0 +1,9 @@ +[unstable] +build-std = ["core"] +build-std-features = ["panic_immediate_abort"] + +[build] +target = "thumbv7em-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/boot-usb-dfu/application/stm32wb/.cargo/config.toml b/examples/boot-usb-dfu/application/stm32wb/.cargo/config.toml new file mode 100644 index 000000000..4f8094ff2 --- /dev/null +++ b/examples/boot-usb-dfu/application/stm32wb/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32WLE5JCIx" + +[build] +target = "thumbv7em-none-eabihf" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/boot-usb-dfu/application/stm32wb/Cargo.toml b/examples/boot-usb-dfu/application/stm32wb/Cargo.toml new file mode 100644 index 000000000..0a41c0648 --- /dev/null +++ b/examples/boot-usb-dfu/application/stm32wb/Cargo.toml @@ -0,0 +1,32 @@ +[package] +edition = "2021" +name = "embassy-boot-stm32wl-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } +embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" } +embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application"] } + +defmt = { version = "0.3", optional = true } +defmt-rtt = { version = "0.4", optional = true } +panic-reset = { version = "0.1.1" } +embedded-hal = { version = "0.2.6" } + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" + +[features] +defmt = [ + "dep:defmt", + "embassy-stm32/defmt", + "embassy-boot-stm32/defmt", + "embassy-sync/defmt", +] +skip-include = [] diff --git a/examples/boot-usb-dfu/application/stm32wb/README.md b/examples/boot-usb-dfu/application/stm32wb/README.md new file mode 100644 index 000000000..c8dce0387 --- /dev/null +++ b/examples/boot-usb-dfu/application/stm32wb/README.md @@ -0,0 +1,29 @@ +# Examples using bootloader + +Example for STM32WL demonstrating the bootloader. The example consists of application binaries, 'a' +which allows you to press a button to start the DFU process, and 'b' which is the updated +application. + + +## Prerequisites + +* `cargo-binutils` +* `cargo-flash` +* `embassy-boot-stm32` + +## Usage + +``` +# Flash bootloader +cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32wl55jc-cm4 --chip STM32WLE5JCIx +# Build 'b' +cargo build --release --bin b +# Generate binary for 'b' +cargo objcopy --release --bin b -- -O binary b.bin +``` + +# Flash `a` (which includes b.bin) + +``` +cargo flash --release --bin a --chip STM32WLE5JCIx +``` diff --git a/examples/boot-usb-dfu/application/stm32wb/build.rs b/examples/boot-usb-dfu/application/stm32wb/build.rs new file mode 100644 index 000000000..e1da69328 --- /dev/null +++ b/examples/boot-usb-dfu/application/stm32wb/build.rs @@ -0,0 +1,37 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + } +} diff --git a/examples/boot-usb-dfu/application/stm32wb/memory.x b/examples/boot-usb-dfu/application/stm32wb/memory.x new file mode 100644 index 000000000..f51875766 --- /dev/null +++ b/examples/boot-usb-dfu/application/stm32wb/memory.x @@ -0,0 +1,15 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K + BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K + FLASH : ORIGIN = 0x08008000, LENGTH = 32K + DFU : ORIGIN = 0x08010000, LENGTH = 36K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K +} + +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); + +__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER); diff --git a/examples/boot-usb-dfu/application/stm32wb/src/main.rs b/examples/boot-usb-dfu/application/stm32wb/src/main.rs new file mode 100644 index 000000000..f03003ffe --- /dev/null +++ b/examples/boot-usb-dfu/application/stm32wb/src/main.rs @@ -0,0 +1,64 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::cell::RefCell; + +#[cfg(feature = "defmt-rtt")] +use defmt_rtt::*; +use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; +use embassy_executor::Spawner; +use embassy_stm32::flash::{Flash, WRITE_SIZE}; +use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32::usb::{self, Driver}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_sync::blocking_mutex::Mutex; +use embassy_time::Duration; +use embassy_usb::Builder; +use embassy_usb_dfu::consts::DfuAttributes; +use embassy_usb_dfu::{usb_dfu, Control}; +use panic_reset as _; + +bind_interrupts!(struct Irqs { + USB_LP => usb::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = embassy_stm32::Config::default(); + config.rcc = WPAN_DEFAULT; + let p = embassy_stm32::init(config); + let flash = Flash::new_blocking(p.FLASH); + let flash = Mutex::new(RefCell::new(flash)); + + let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); + let mut magic = AlignedBuffer([0; WRITE_SIZE]); + let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0); + updater.mark_booted().expect("Failed to mark booted"); + + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-DFU Runtime example"); + config.serial_number = Some("1235678"); + + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD); + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], + &mut control_buf, + ); + + usb_dfu::<_, _, _>(&mut builder, &mut state, Duration::from_millis(2500)); + + let mut dev = builder.build(); + dev.run().await +} diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/Cargo.toml b/examples/boot-usb-dfu/bootloader/stm32wb/Cargo.toml new file mode 100644 index 000000000..774a8223d --- /dev/null +++ b/examples/boot-usb-dfu/bootloader/stm32wb/Cargo.toml @@ -0,0 +1,63 @@ +[package] +edition = "2021" +name = "stm32-bootloader-example" +version = "0.1.0" +description = "Example bootloader for STM32 chips" +license = "MIT OR Apache-2.0" + +[dependencies] +defmt = { version = "0.3", optional = true } +defmt-rtt = { version = "0.4", optional = true } + +embassy-stm32 = { path = "../../../../embassy-stm32", features = ["stm32wb55rg"] } +embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32" } +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +cortex-m-rt = { version = "0.7" } +embedded-storage = "0.3.1" +embedded-storage-async = "0.4.0" +cfg-if = "1.0.0" +embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["bootloader"] } +embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false } +embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } + +[features] +defmt = [ + "dep:defmt", + "embassy-boot-stm32/defmt", + "embassy-stm32/defmt", + "embassy-usb/defmt", + "embassy-usb-dfu/defmt" +] +debug = ["defmt-rtt", "defmt"] + +[profile.dev] +debug = 2 +debug-assertions = true +incremental = false +opt-level = 'z' +overflow-checks = true + +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 'z' +overflow-checks = false + +# do not optimize proc-macro crates = faster builds from scratch +[profile.dev.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +[profile.release.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/README.md b/examples/boot-usb-dfu/bootloader/stm32wb/README.md new file mode 100644 index 000000000..a82b730b9 --- /dev/null +++ b/examples/boot-usb-dfu/bootloader/stm32wb/README.md @@ -0,0 +1,11 @@ +# Bootloader for STM32 + +The bootloader uses `embassy-boot` to interact with the flash. + +# Usage + +Flash the bootloader + +``` +cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx +``` diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/build.rs b/examples/boot-usb-dfu/bootloader/stm32wb/build.rs new file mode 100644 index 000000000..fd605991f --- /dev/null +++ b/examples/boot-usb-dfu/bootloader/stm32wb/build.rs @@ -0,0 +1,27 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + } +} diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/memory.x b/examples/boot-usb-dfu/bootloader/stm32wb/memory.x new file mode 100644 index 000000000..b6f185ef7 --- /dev/null +++ b/examples/boot-usb-dfu/bootloader/stm32wb/memory.x @@ -0,0 +1,18 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x08000000, LENGTH = 24K + BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K + ACTIVE : ORIGIN = 0x08008000, LENGTH = 32K + DFU : ORIGIN = 0x08010000, LENGTH = 36K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K +} + +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH); + +__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH); +__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH); + +__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(FLASH); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(FLASH); diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/src/main.rs b/examples/boot-usb-dfu/bootloader/stm32wb/src/main.rs new file mode 100644 index 000000000..00a535d35 --- /dev/null +++ b/examples/boot-usb-dfu/bootloader/stm32wb/src/main.rs @@ -0,0 +1,95 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use cortex_m_rt::{entry, exception}; +#[cfg(feature = "defmt")] +use defmt_rtt as _; +use embassy_boot_stm32::*; +use embassy_stm32::flash::{Flash, BANK1_REGION, WRITE_SIZE}; +use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32::usb::Driver; +use embassy_stm32::{bind_interrupts, peripherals, usb}; +use embassy_sync::blocking_mutex::Mutex; +use embassy_usb::Builder; +use embassy_usb_dfu::consts::DfuAttributes; +use embassy_usb_dfu::{usb_dfu, Control}; + +bind_interrupts!(struct Irqs { + USB_LP => usb::InterruptHandler; +}); + +#[entry] +fn main() -> ! { + let mut config = embassy_stm32::Config::default(); + config.rcc = WPAN_DEFAULT; + let p = embassy_stm32::init(config); + + // Uncomment this if you are debugging the bootloader with debugger/RTT attached, + // as it prevents a hard fault when accessing flash 'too early' after boot. + /* + for i in 0..10000000 { + cortex_m::asm::nop(); + } + */ + + let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); + let flash = Mutex::new(RefCell::new(layout.bank1_region)); + + let config = BootLoaderConfig::from_linkerfile_blocking(&flash); + let active_offset = config.active.offset(); + let bl = BootLoader::prepare::<_, _, _, 2048>(config); + if bl.state == State::DfuDetach { + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-DFU Bootloader example"); + config.serial_number = Some("1235678"); + + let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); + let mut buffer = AlignedBuffer([0; WRITE_SIZE]); + let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); + + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 4096]; + let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD); + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], + &mut control_buf, + ); + + usb_dfu::<_, _, _, 4096>(&mut builder, &mut state); + + let mut dev = builder.build(); + embassy_futures::block_on(dev.run()); + } + + unsafe { bl.load(BANK1_REGION.base + active_offset) } +} + +#[no_mangle] +#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +unsafe extern "C" fn HardFault() { + cortex_m::peripheral::SCB::sys_reset(); +} + +#[exception] +unsafe fn DefaultHandler(_: i16) -> ! { + const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; + let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + + panic!("DefaultHandler #{:?}", irqn); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + cortex_m::asm::udf(); +} From b60b3f4eb8f22ecda1c30d63213010f1b6b47686 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Wed, 13 Dec 2023 16:19:59 -0500 Subject: [PATCH 015/760] Last fmt hopefully --- embassy-boot/boot/src/boot_loader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index 340962a7a..b3970d867 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs @@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; -use crate::{State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, DFU_DETACH_MAGIC}; +use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; /// Errors returned by bootloader #[derive(PartialEq, Eq, Debug)] From b17f16f0af635f4268543dcfe4cee1ec48b216a1 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 14 Dec 2023 09:11:30 +0200 Subject: [PATCH 016/760] embassy-boot: Fix formatting for tables Tables describing the a-b flashing were all garbled up in the cargo doc output, so fix up the syntax. --- embassy-boot/boot/src/boot_loader.rs | 36 +++++++++------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index 1663f4f2c..65b12dc5f 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs @@ -135,51 +135,44 @@ impl BootLoader BootLoader Result { // Ensure we have enough progress pages to store copy progress From 879c0ad9890e80f2e7c19c715347b86b61eb432a Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 14 Dec 2023 21:33:35 +0800 Subject: [PATCH 017/760] after stm32-metapac update, TIM CR1 ARPE enum to bool --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/timer/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 074538d3b..f54d5608f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8f5fcae8c289c1ad481cc3a2bb37db023a61599c" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-91cee0d1fdcb4e447b65a09756b506f4af91b7e2" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8f5fcae8c289c1ad481cc3a2bb37db023a61599c", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-91cee0d1fdcb4e447b65a09756b506f4af91b7e2", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 2313a5b94..9f93c6425 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -77,7 +77,7 @@ pub(crate) mod sealed { Self::regs().dier().write(|r| r.set_uie(enable)); } - fn set_autoreload_preload(&mut self, enable: vals::Arpe) { + fn set_autoreload_preload(&mut self, enable: bool) { Self::regs().cr1().modify(|r| r.set_arpe(enable)); } From e27e00f6280683293f427d0731aa69ca32dbbe60 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 09:36:22 -0500 Subject: [PATCH 018/760] Address reviews --- .../boot/src/firmware_updater/asynch.rs | 10 + .../boot/src/firmware_updater/blocking.rs | 10 + embassy-boot/boot/src/lib.rs | 2 +- embassy-usb-dfu/src/application.rs | 36 ++- embassy-usb-dfu/src/bootloader.rs | 8 +- embassy-usb-dfu/src/fmt.rs | 258 ++++++++++++++++++ embassy-usb-dfu/src/lib.rs | 1 + examples/boot-usb-dfu/.cargo/config.toml | 9 - .../stm32wb-dfu}/.cargo/config.toml | 0 .../application/stm32wb-dfu}/Cargo.toml | 1 + .../application/stm32wb-dfu}/README.md | 0 .../application/stm32wb-dfu}/build.rs | 0 .../application/stm32wb-dfu}/memory.x | 0 .../application/stm32wb-dfu}/src/main.rs | 0 .../bootloader/stm32wb-dfu}/Cargo.toml | 0 .../bootloader/stm32wb-dfu}/README.md | 0 .../bootloader/stm32wb-dfu}/build.rs | 0 .../bootloader/stm32wb-dfu}/memory.x | 0 .../bootloader/stm32wb-dfu}/src/main.rs | 13 +- 19 files changed, 307 insertions(+), 41 deletions(-) create mode 100644 embassy-usb-dfu/src/fmt.rs delete mode 100644 examples/boot-usb-dfu/.cargo/config.toml rename examples/{boot-usb-dfu/application/stm32wb => boot/application/stm32wb-dfu}/.cargo/config.toml (100%) rename examples/{boot-usb-dfu/application/stm32wb => boot/application/stm32wb-dfu}/Cargo.toml (98%) rename examples/{boot-usb-dfu/application/stm32wb => boot/application/stm32wb-dfu}/README.md (100%) rename examples/{boot-usb-dfu/application/stm32wb => boot/application/stm32wb-dfu}/build.rs (100%) rename examples/{boot-usb-dfu/application/stm32wb => boot/application/stm32wb-dfu}/memory.x (100%) rename examples/{boot-usb-dfu/application/stm32wb => boot/application/stm32wb-dfu}/src/main.rs (100%) rename examples/{boot-usb-dfu/bootloader/stm32wb => boot/bootloader/stm32wb-dfu}/Cargo.toml (100%) rename examples/{boot-usb-dfu/bootloader/stm32wb => boot/bootloader/stm32wb-dfu}/README.md (100%) rename examples/{boot-usb-dfu/bootloader/stm32wb => boot/bootloader/stm32wb-dfu}/build.rs (100%) rename examples/{boot-usb-dfu/bootloader/stm32wb => boot/bootloader/stm32wb-dfu}/memory.x (100%) rename examples/{boot-usb-dfu/bootloader/stm32wb => boot/bootloader/stm32wb-dfu}/src/main.rs (91%) diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs index 82e99965b..d8d85c3d2 100644 --- a/embassy-boot/boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/boot/src/firmware_updater/asynch.rs @@ -213,6 +213,16 @@ pub struct FirmwareState<'d, STATE> { } impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { + /// Create a firmware state instance from a FirmwareUpdaterConfig with a buffer for magic content and state partition. + /// + /// # Safety + /// + /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from + /// and written to. + pub fn from_config(config: FirmwareUpdaterConfig, aligned: &'d mut [u8]) -> Self { + Self::new(config.state, aligned) + } + /// Create a firmware state instance with a buffer for magic content and state partition. /// /// # Safety diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs index ae4179ba3..4f56f152d 100644 --- a/embassy-boot/boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/boot/src/firmware_updater/blocking.rs @@ -219,6 +219,16 @@ pub struct BlockingFirmwareState<'d, STATE> { } impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { + /// Creates a firmware state instance from a FirmwareUpdaterConfig, with a buffer for magic content and state partition. + /// + /// # Safety + /// + /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from + /// and written to. + pub fn from_config(config: FirmwareUpdaterConfig, aligned: &'d mut [u8]) -> Self { + Self::new(config.state, aligned) + } + /// Create a firmware state instance with a buffer for magic content and state partition. /// /// # Safety diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 451992945..15b69f69d 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -33,7 +33,7 @@ pub enum State { Boot, /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. Swap, - /// Application has received a DFU_DETACH request over USB, and is rebooting into the bootloader to apply a DFU. + /// Application has received a request to reboot into DFU mode to apply an update. DfuDetach, } diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 2e7bda121..0b7b53af8 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -1,4 +1,4 @@ -use embassy_boot::BlockingFirmwareUpdater; +use embassy_boot::BlockingFirmwareState; use embassy_time::{Duration, Instant}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; @@ -11,18 +11,18 @@ use crate::consts::{ }; /// Internal state for the DFU class -pub struct Control<'d, DFU: NorFlash, STATE: NorFlash> { - updater: BlockingFirmwareUpdater<'d, DFU, STATE>, +pub struct Control<'d, STATE: NorFlash> { + firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes, state: State, timeout: Option, detach_start: Option, } -impl<'d, DFU: NorFlash, STATE: NorFlash> Control<'d, DFU, STATE> { - pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { +impl<'d, STATE: NorFlash> Control<'d, STATE> { + pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { Control { - updater, + firmware_state, attrs, state: State::AppIdle, detach_start: None, @@ -31,19 +31,20 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Control<'d, DFU, STATE> { } } -impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { +impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> { fn reset(&mut self) { if let Some(start) = self.detach_start { let delta = Instant::now() - start; let timeout = self.timeout.unwrap(); - #[cfg(feature = "defmt")] - defmt::info!( + trace!( "Received RESET with delta = {}, timeout = {}", delta.as_millis(), timeout.as_millis() ); if delta < timeout { - self.updater.mark_dfu().expect("Failed to mark DFU mode in bootloader"); + self.firmware_state + .mark_dfu() + .expect("Failed to mark DFU mode in bootloader"); cortex_m::asm::dsb(); cortex_m::peripheral::SCB::sys_reset(); } @@ -59,13 +60,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { return None; } - #[cfg(feature = "defmt")] - defmt::info!("Received request {}", req); + trace!("Received request {}", req); match Request::try_from(req.request) { Ok(Request::Detach) => { - #[cfg(feature = "defmt")] - defmt::info!("Received DETACH, awaiting USB reset"); + trace!("Received DETACH, awaiting USB reset"); self.detach_start = Some(Instant::now()); self.timeout = Some(Duration::from_millis(req.value as u64)); self.state = State::AppDetach; @@ -84,8 +83,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { return None; } - #[cfg(feature = "defmt")] - defmt::info!("Received request {}", req); + trace!("Received request {}", req); match Request::try_from(req.request) { Ok(Request::GetStatus) => { @@ -106,13 +104,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { /// it should expose a DFU device, and a software reset will be issued. /// /// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. -pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>( +pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash>( builder: &mut Builder<'d, D>, - handler: &'d mut Control<'d, DFU, STATE>, + handler: &'d mut Control<'d, STATE>, timeout: Duration, ) { - #[cfg(feature = "defmt")] - defmt::info!("Application USB DFU initializing"); let mut func = builder.function(0x00, 0x00, 0x00); let mut iface = func.interface(); let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None); diff --git a/embassy-usb-dfu/src/bootloader.rs b/embassy-usb-dfu/src/bootloader.rs index 215058932..99384d961 100644 --- a/embassy-usb-dfu/src/bootloader.rs +++ b/embassy-usb-dfu/src/bootloader.rs @@ -1,4 +1,4 @@ -use embassy_boot::BlockingFirmwareUpdater; +use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; use embassy_usb::{Builder, Handler}; @@ -56,8 +56,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co self.offset = 0; } - let mut buf = [0; BLOCK_SIZE]; - buf[..data.len()].copy_from_slice(data); + let mut buf = AlignedBuffer([0; BLOCK_SIZE]); + buf.as_mut()[..data.len()].copy_from_slice(data); if req.length == 0 { match self.updater.mark_updated() { @@ -85,7 +85,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co self.state = State::Error; return Some(OutResponse::Rejected); } - match self.updater.write_firmware(self.offset, &buf[..]) { + match self.updater.write_firmware(self.offset, buf.as_ref()) { Ok(_) => { self.status = Status::Ok; self.state = State::DlSync; diff --git a/embassy-usb-dfu/src/fmt.rs b/embassy-usb-dfu/src/fmt.rs new file mode 100644 index 000000000..78e583c1c --- /dev/null +++ b/embassy-usb-dfu/src/fmt.rs @@ -0,0 +1,258 @@ +#![macro_use] +#![allow(unused_macros)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unreachable { + ($($x:tt)*) => { + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) + }; +} + +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs index 81ef041f8..ae0fbbd4c 100644 --- a/embassy-usb-dfu/src/lib.rs +++ b/embassy-usb-dfu/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +mod fmt; pub mod consts; diff --git a/examples/boot-usb-dfu/.cargo/config.toml b/examples/boot-usb-dfu/.cargo/config.toml deleted file mode 100644 index de3a814f7..000000000 --- a/examples/boot-usb-dfu/.cargo/config.toml +++ /dev/null @@ -1,9 +0,0 @@ -[unstable] -build-std = ["core"] -build-std-features = ["panic_immediate_abort"] - -[build] -target = "thumbv7em-none-eabi" - -[env] -DEFMT_LOG = "trace" diff --git a/examples/boot-usb-dfu/application/stm32wb/.cargo/config.toml b/examples/boot/application/stm32wb-dfu/.cargo/config.toml similarity index 100% rename from examples/boot-usb-dfu/application/stm32wb/.cargo/config.toml rename to examples/boot/application/stm32wb-dfu/.cargo/config.toml diff --git a/examples/boot-usb-dfu/application/stm32wb/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml similarity index 98% rename from examples/boot-usb-dfu/application/stm32wb/Cargo.toml rename to examples/boot/application/stm32wb-dfu/Cargo.toml index 0a41c0648..e67224ce6 100644 --- a/examples/boot-usb-dfu/application/stm32wb/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -25,6 +25,7 @@ cortex-m-rt = "0.7.0" [features] defmt = [ "dep:defmt", + "dep:defmt-rtt", "embassy-stm32/defmt", "embassy-boot-stm32/defmt", "embassy-sync/defmt", diff --git a/examples/boot-usb-dfu/application/stm32wb/README.md b/examples/boot/application/stm32wb-dfu/README.md similarity index 100% rename from examples/boot-usb-dfu/application/stm32wb/README.md rename to examples/boot/application/stm32wb-dfu/README.md diff --git a/examples/boot-usb-dfu/application/stm32wb/build.rs b/examples/boot/application/stm32wb-dfu/build.rs similarity index 100% rename from examples/boot-usb-dfu/application/stm32wb/build.rs rename to examples/boot/application/stm32wb-dfu/build.rs diff --git a/examples/boot-usb-dfu/application/stm32wb/memory.x b/examples/boot/application/stm32wb-dfu/memory.x similarity index 100% rename from examples/boot-usb-dfu/application/stm32wb/memory.x rename to examples/boot/application/stm32wb-dfu/memory.x diff --git a/examples/boot-usb-dfu/application/stm32wb/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs similarity index 100% rename from examples/boot-usb-dfu/application/stm32wb/src/main.rs rename to examples/boot/application/stm32wb-dfu/src/main.rs diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml similarity index 100% rename from examples/boot-usb-dfu/bootloader/stm32wb/Cargo.toml rename to examples/boot/bootloader/stm32wb-dfu/Cargo.toml diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md similarity index 100% rename from examples/boot-usb-dfu/bootloader/stm32wb/README.md rename to examples/boot/bootloader/stm32wb-dfu/README.md diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/build.rs b/examples/boot/bootloader/stm32wb-dfu/build.rs similarity index 100% rename from examples/boot-usb-dfu/bootloader/stm32wb/build.rs rename to examples/boot/bootloader/stm32wb-dfu/build.rs diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/memory.x b/examples/boot/bootloader/stm32wb-dfu/memory.x similarity index 100% rename from examples/boot-usb-dfu/bootloader/stm32wb/memory.x rename to examples/boot/bootloader/stm32wb-dfu/memory.x diff --git a/examples/boot-usb-dfu/bootloader/stm32wb/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs similarity index 91% rename from examples/boot-usb-dfu/bootloader/stm32wb/src/main.rs rename to examples/boot/bootloader/stm32wb-dfu/src/main.rs index 00a535d35..a2b884770 100644 --- a/examples/boot-usb-dfu/bootloader/stm32wb/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -26,13 +26,12 @@ fn main() -> ! { config.rcc = WPAN_DEFAULT; let p = embassy_stm32::init(config); - // Uncomment this if you are debugging the bootloader with debugger/RTT attached, - // as it prevents a hard fault when accessing flash 'too early' after boot. - /* - for i in 0..10000000 { - cortex_m::asm::nop(); - } - */ + // Prevent a hard fault when accessing flash 'too early' after boot. + #[cfg(feature = "defmt")] + for _ in 0..10000000 { + cortex_m::asm::nop(); + } + let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); let flash = Mutex::new(RefCell::new(layout.bank1_region)); From c1438fe87bf363b018231bd36e188c72679eb202 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 09:38:02 -0500 Subject: [PATCH 019/760] fmt --- embassy-boot/boot/src/firmware_updater/blocking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs index 4f56f152d..c4c142169 100644 --- a/embassy-boot/boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/boot/src/firmware_updater/blocking.rs @@ -220,9 +220,9 @@ pub struct BlockingFirmwareState<'d, STATE> { impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { /// Creates a firmware state instance from a FirmwareUpdaterConfig, with a buffer for magic content and state partition. - /// + /// /// # Safety - /// + /// /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from /// and written to. pub fn from_config(config: FirmwareUpdaterConfig, aligned: &'d mut [u8]) -> Self { From 9cc5d8ac892d4efbb629ab3bafdf341edd50ca7e Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 09:38:49 -0500 Subject: [PATCH 020/760] fmt --- examples/boot/bootloader/stm32wb-dfu/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index a2b884770..db7039e8c 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -31,7 +31,6 @@ fn main() -> ! { for _ in 0..10000000 { cortex_m::asm::nop(); } - let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); let flash = Mutex::new(RefCell::new(layout.bank1_region)); From ef692c514101d6c91059c13af52cdd70dc5cd6e0 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 10:06:36 -0500 Subject: [PATCH 021/760] SCB::sys_reset has a DSB internally, no need to replicate --- embassy-usb-dfu/src/application.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 0b7b53af8..5ff8f90f8 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -45,7 +45,6 @@ impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> { self.firmware_state .mark_dfu() .expect("Failed to mark DFU mode in bootloader"); - cortex_m::asm::dsb(); cortex_m::peripheral::SCB::sys_reset(); } } From d81395fab3c4e336650b0481790ecdab7d7aa13f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 14 Dec 2023 16:01:51 +0100 Subject: [PATCH 022/760] Update embedded-hal to 1.0.0-rc.3 --- cyw43/Cargo.toml | 2 +- .../layer-by-layer/blinky-hal/src/main.rs | 2 +- embassy-embedded-hal/Cargo.toml | 4 +- embassy-net-adin1110/Cargo.toml | 8 +- embassy-net-enc28j60/Cargo.toml | 4 +- embassy-net-esp-hosted/Cargo.toml | 4 +- embassy-net-wiznet/Cargo.toml | 4 +- embassy-nrf/Cargo.toml | 5 +- embassy-nrf/src/gpio.rs | 67 +++++++----- embassy-nrf/src/gpiote.rs | 10 +- embassy-rp/Cargo.toml | 6 +- embassy-rp/src/gpio.rs | 101 ++++++++++-------- embassy-stm32/Cargo.toml | 6 +- embassy-stm32/src/exti.rs | 14 +-- embassy-stm32/src/gpio.rs | 94 ++++++++-------- embassy-time/CHANGELOG.md | 4 +- embassy-time/Cargo.toml | 4 +- examples/nrf52840/Cargo.toml | 6 +- examples/rp/Cargo.toml | 6 +- examples/rp/src/bin/button.rs | 2 +- examples/stm32c0/src/bin/button.rs | 2 +- examples/stm32f3/src/bin/button.rs | 2 +- examples/stm32f4/src/bin/button.rs | 2 +- examples/stm32f7/src/bin/button.rs | 2 +- examples/stm32g0/src/bin/button.rs | 2 +- examples/stm32g4/src/bin/button.rs | 2 +- examples/stm32h5/Cargo.toml | 4 +- examples/stm32h7/Cargo.toml | 4 +- examples/stm32l0/src/bin/button.rs | 2 +- examples/stm32l4/Cargo.toml | 6 +- examples/stm32l4/src/bin/button.rs | 2 +- .../src/bin/spe_adin1110_http_server.rs | 8 +- .../stm32l4/src/bin/spi_blocking_async.rs | 2 +- examples/stm32l4/src/bin/spi_dma.rs | 2 +- examples/stm32wl/src/bin/button.rs | 2 +- tests/nrf/Cargo.toml | 4 +- tests/rp/Cargo.toml | 6 +- tests/rp/src/bin/gpio.rs | 10 +- tests/rp/src/bin/pwm.rs | 8 +- tests/stm32/Cargo.toml | 4 +- tests/stm32/src/bin/gpio.rs | 12 +-- 41 files changed, 238 insertions(+), 203 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 293c00982..72faad805 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -23,7 +23,7 @@ cortex-m = "0.7.6" cortex-m-rt = "0.7.0" futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } -embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.3" } num_enum = { version = "0.5.7", default-features = false } [package.metadata.embassy_docs] diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs index d0c9f4907..54b87662e 100644 --- a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs +++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs @@ -9,7 +9,7 @@ use {defmt_rtt as _, panic_probe as _}; fn main() -> ! { let p = embassy_stm32::init(Default::default()); let mut led = Output::new(p.PB14, Level::High, Speed::VeryHigh); - let button = Input::new(p.PC13, Pull::Up); + let mut button = Input::new(p.PC13, Pull::Up); loop { if button.is_low() { diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 2a0b25479..f292f952d 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -23,8 +23,8 @@ embassy-time = { version = "0.2", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", ] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } nb = "1.0.0" diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index d95b2628c..adcdfe80f 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -13,16 +13,16 @@ edition = "2021" heapless = "0.8" defmt = { version = "0.3", optional = true } log = { version = "0.4", default-features = false, optional = true } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } -embedded-hal-bus = { version = "=0.1.0-rc.2", features = ["async"] } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] } embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } embassy-time = { version = "0.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" [dev-dependencies] -embedded-hal-mock = { git = "https://github.com/Dirbaio/embedded-hal-mock", rev = "c5c4dca18e043e6386aee02173f61a65fea3981e", features = ["embedded-hal-async", "eh1"] } +embedded-hal-mock = { git = "https://github.com/Dirbaio/embedded-hal-mock", rev = "b5a2274759a8c484f4fae71a22f8a083fdd9d5da", features = ["embedded-hal-async", "eh1"] } crc = "3.0.1" env_logger = "0.10" critical-section = { version = "1.1.2", features = ["std"] } diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index 72e1d4e5c..8cd723c4c 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" edition = "2021" [dependencies] -embedded-hal = { version = "1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal = { version = "1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-time = { version = "0.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index eb44a6544..70b1bbe2a 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -12,8 +12,8 @@ embassy-sync = { version = "0.5.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} -embedded-hal = { version = "1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal = { version = "1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } noproto = { git="https://github.com/embassy-rs/noproto", rev = "f5e6d1f325b6ad4e344f60452b09576e24671f62", default-features = false, features = ["derive"] } #noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] } diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 9c103ebb1..a1f0b0c51 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" edition = "2021" [dependencies] -embedded-hal = { version = "1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal = { version = "1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } embassy-time = { version = "0.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index a7f3cb35d..6d7440519 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -94,8 +94,8 @@ embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } @@ -120,4 +120,3 @@ nrf52840-pac = { version = "0.12.0", optional = true } nrf5340-app-pac = { version = "0.12.0", optional = true } nrf5340-net-pac = { version = "0.12.0", optional = true } nrf9160-pac = { version = "0.12.0", optional = true } - diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index cf6225282..85977a804 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -52,19 +52,19 @@ impl<'d, T: Pin> Input<'d, T> { /// Test if current pin level is high. #[inline] - pub fn is_high(&self) -> bool { + pub fn is_high(&mut self) -> bool { self.pin.is_high() } /// Test if current pin level is low. #[inline] - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { self.pin.is_low() } /// Returns current pin level #[inline] - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.pin.get_level() } } @@ -160,19 +160,19 @@ impl<'d, T: Pin> Output<'d, T> { /// Is the output pin set as high? #[inline] - pub fn is_set_high(&self) -> bool { + pub fn is_set_high(&mut self) -> bool { self.pin.is_set_high() } /// Is the output pin set as low? #[inline] - pub fn is_set_low(&self) -> bool { + pub fn is_set_low(&mut self) -> bool { self.pin.is_set_low() } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn get_output_level(&mut self) -> Level { self.pin.get_output_level() } } @@ -277,19 +277,24 @@ impl<'d, T: Pin> Flex<'d, T> { /// Test if current pin level is high. #[inline] - pub fn is_high(&self) -> bool { + pub fn is_high(&mut self) -> bool { !self.is_low() } /// Test if current pin level is low. #[inline] - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { + self.ref_is_low() + } + + #[inline] + pub(crate) fn ref_is_low(&self) -> bool { self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 } /// Returns current pin level #[inline] - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.is_high().into() } @@ -316,19 +321,25 @@ impl<'d, T: Pin> Flex<'d, T> { /// Is the output pin set as high? #[inline] - pub fn is_set_high(&self) -> bool { + pub fn is_set_high(&mut self) -> bool { !self.is_set_low() } /// Is the output pin set as low? #[inline] - pub fn is_set_low(&self) -> bool { + pub fn is_set_low(&mut self) -> bool { + self.ref_is_set_low() + } + + /// Is the output pin set as low? + #[inline] + pub(crate) fn ref_is_set_low(&self) -> bool { self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn get_output_level(&mut self) -> Level { self.is_set_high().into() } } @@ -498,11 +509,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(self.is_high()) + Ok(!self.pin.ref_is_low()) } fn is_low(&self) -> Result { - Ok(self.is_low()) + Ok(self.pin.ref_is_low()) } } @@ -520,11 +531,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) + Ok(!self.pin.ref_is_set_low()) } fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) + Ok(self.pin.ref_is_set_low()) } } @@ -535,11 +546,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(self.is_high()) + Ok(!self.ref_is_low()) } fn is_low(&self) -> Result { - Ok(self.is_low()) + Ok(self.ref_is_low()) } } @@ -557,11 +568,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) + Ok(!self.ref_is_set_low()) } fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) + Ok(self.ref_is_set_low()) } } } @@ -571,11 +582,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { } impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } @@ -595,11 +606,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { } impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.is_set_high()) } - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(self.is_set_low()) } } @@ -612,11 +623,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { /// /// If the pin is not in input mode the result is unspecified. impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } @@ -632,11 +643,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { } impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.is_set_high()) } - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(self.is_set_low()) } } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index fd629ea76..07196abf7 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -243,7 +243,7 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { /// Create a new GPIOTE output channel driver. - pub fn new(ch: impl Peripheral

+ 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { + pub fn new(ch: impl Peripheral

+ 'd, mut pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { into_ref!(ch); let g = regs(); let num = ch.number(); @@ -481,11 +481,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(self.pin.is_high()) + Ok(!self.pin.pin.ref_is_low()) } fn is_low(&self) -> Result { - Ok(self.pin.is_low()) + Ok(self.pin.pin.ref_is_low()) } } } @@ -495,11 +495,11 @@ impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputCha } impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChannel<'d, C, T> { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.pin.is_high()) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.pin.is_low()) } } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index dfdd1fee9..c557940b1 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -78,9 +78,9 @@ fixed = "1.23.1" rp-pac = { version = "6" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } -embedded-hal-nb = { version = "=1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-nb = { version = "=1.0.0-rc.3" } pio-proc = {version= "0.2" } pio = {version= "0.2.1" } diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 9034f3f36..23273e627 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -105,18 +105,18 @@ impl<'d, T: Pin> Input<'d, T> { } #[inline] - pub fn is_high(&self) -> bool { + pub fn is_high(&mut self) -> bool { self.pin.is_high() } #[inline] - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { self.pin.is_low() } /// Returns current pin level #[inline] - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.pin.get_level() } @@ -357,19 +357,19 @@ impl<'d, T: Pin> Output<'d, T> { /// Is the output pin set as high? #[inline] - pub fn is_set_high(&self) -> bool { + pub fn is_set_high(&mut self) -> bool { self.pin.is_set_high() } /// Is the output pin set as low? #[inline] - pub fn is_set_low(&self) -> bool { + pub fn is_set_low(&mut self) -> bool { self.pin.is_set_low() } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn get_output_level(&mut self) -> Level { self.pin.get_output_level() } @@ -434,19 +434,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { /// Is the output level high? #[inline] - pub fn is_set_high(&self) -> bool { + pub fn is_set_high(&mut self) -> bool { !self.is_set_low() } /// Is the output level low? #[inline] - pub fn is_set_low(&self) -> bool { + pub fn is_set_low(&mut self) -> bool { self.pin.is_set_as_output() } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn get_output_level(&mut self) -> Level { self.is_set_high().into() } @@ -457,18 +457,18 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { } #[inline] - pub fn is_high(&self) -> bool { + pub fn is_high(&mut self) -> bool { self.pin.is_high() } #[inline] - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { self.pin.is_low() } /// Returns current pin level #[inline] - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.is_high().into() } @@ -590,7 +590,12 @@ impl<'d, T: Pin> Flex<'d, T> { } #[inline] - fn is_set_as_output(&self) -> bool { + pub fn is_set_as_output(&mut self) -> bool { + self.ref_is_set_as_output() + } + + #[inline] + pub(crate) fn ref_is_set_as_output(&self) -> bool { (self.pin.sio_oe().value().read() & self.bit()) != 0 } @@ -600,18 +605,23 @@ impl<'d, T: Pin> Flex<'d, T> { } #[inline] - pub fn is_high(&self) -> bool { + pub fn is_high(&mut self) -> bool { !self.is_low() } #[inline] - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { + self.ref_is_low() + } + + #[inline] + pub(crate) fn ref_is_low(&self) -> bool { self.pin.sio_in().read() & self.bit() == 0 } /// Returns current pin level #[inline] - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.is_high().into() } @@ -638,19 +648,24 @@ impl<'d, T: Pin> Flex<'d, T> { /// Is the output level high? #[inline] - pub fn is_set_high(&self) -> bool { + pub fn is_set_high(&mut self) -> bool { !self.is_set_low() } /// Is the output level low? #[inline] - pub fn is_set_low(&self) -> bool { + pub fn is_set_low(&mut self) -> bool { + self.ref_is_set_low() + } + + #[inline] + pub(crate) fn ref_is_set_low(&self) -> bool { (self.pin.sio_out().value().read() & self.bit()) == 0 } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn get_output_level(&mut self) -> Level { self.is_set_high().into() } @@ -912,11 +927,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(self.is_high()) + Ok(!self.pin.ref_is_low()) } fn is_low(&self) -> Result { - Ok(self.is_low()) + Ok(self.pin.ref_is_low()) } } @@ -934,11 +949,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) + Ok(!self.pin.ref_is_set_low()) } fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) + Ok(self.pin.ref_is_set_low()) } } @@ -954,11 +969,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(self.is_high()) + Ok(!self.pin.ref_is_low()) } fn is_low(&self) -> Result { - Ok(self.is_low()) + Ok(self.pin.ref_is_low()) } } @@ -978,11 +993,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) + Ok(!self.pin.ref_is_set_as_output()) } fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) + Ok(self.pin.ref_is_set_as_output()) } } @@ -998,11 +1013,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(self.is_high()) + Ok(!self.ref_is_low()) } fn is_low(&self) -> Result { - Ok(self.is_low()) + Ok(self.ref_is_low()) } } @@ -1020,11 +1035,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) + Ok(!self.ref_is_set_low()) } fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) + Ok(self.ref_is_set_low()) } } @@ -1042,11 +1057,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { } impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } @@ -1066,11 +1081,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { } impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.is_set_high()) } - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(self.is_set_low()) } } @@ -1096,11 +1111,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { } impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.is_set_high()) } - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(self.is_set_low()) } } @@ -1112,11 +1127,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrai } impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } @@ -1126,11 +1141,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { } impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } @@ -1146,11 +1161,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { } impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.is_set_high()) } - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(self.is_set_low()) } } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 074538d3b..3de15debe 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -42,9 +42,9 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-executor = { version = "0.4.0", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } -embedded-hal-nb = { version = "=1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-nb = { version = "=1.0.0-rc.3" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index dbd24804f..e77ac30fb 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -97,15 +97,15 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { Self { pin } } - pub fn is_high(&self) -> bool { + pub fn is_high(&mut self) -> bool { self.pin.is_high() } - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { self.pin.is_low() } - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.pin.get_level() } @@ -142,11 +142,11 @@ impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T> type Error = Infallible; fn is_high(&self) -> Result { - Ok(self.is_high()) + Ok(!self.pin.pin.ref_is_low()) } fn is_low(&self) -> Result { - Ok(self.is_low()) + Ok(self.pin.pin.ref_is_low()) } } @@ -155,11 +155,11 @@ impl<'d, T: GpioPin> embedded_hal_1::digital::ErrorType for ExtiInput<'d, T> { } impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index b863c4ffe..bb3cf2bc4 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -142,36 +142,46 @@ impl<'d, T: Pin> Flex<'d, T> { } #[inline] - pub fn is_high(&self) -> bool { - !self.is_low() + pub fn is_high(&mut self) -> bool { + !self.ref_is_low() } #[inline] - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { + self.ref_is_low() + } + + #[inline] + pub(crate) fn ref_is_low(&self) -> bool { let state = self.pin.block().idr().read().idr(self.pin.pin() as _); state == vals::Idr::LOW } #[inline] - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.is_high().into() } #[inline] - pub fn is_set_high(&self) -> bool { - !self.is_set_low() + pub fn is_set_high(&mut self) -> bool { + !self.ref_is_set_low() } /// Is the output pin set as low? #[inline] - pub fn is_set_low(&self) -> bool { + pub fn is_set_low(&mut self) -> bool { + self.ref_is_set_low() + } + + #[inline] + pub(crate) fn ref_is_set_low(&self) -> bool { let state = self.pin.block().odr().read().odr(self.pin.pin() as _); state == vals::Odr::LOW } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn get_output_level(&mut self) -> Level { self.is_set_high().into() } @@ -310,17 +320,17 @@ impl<'d, T: Pin> Input<'d, T> { } #[inline] - pub fn is_high(&self) -> bool { + pub fn is_high(&mut self) -> bool { self.pin.is_high() } #[inline] - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { self.pin.is_low() } #[inline] - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.pin.get_level() } } @@ -399,19 +409,19 @@ impl<'d, T: Pin> Output<'d, T> { /// Is the output pin set as high? #[inline] - pub fn is_set_high(&self) -> bool { + pub fn is_set_high(&mut self) -> bool { self.pin.is_set_high() } /// Is the output pin set as low? #[inline] - pub fn is_set_low(&self) -> bool { + pub fn is_set_low(&mut self) -> bool { self.pin.is_set_low() } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn get_output_level(&mut self) -> Level { self.pin.get_output_level() } @@ -453,18 +463,18 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { } #[inline] - pub fn is_high(&self) -> bool { + pub fn is_high(&mut self) -> bool { !self.pin.is_low() } #[inline] - pub fn is_low(&self) -> bool { + pub fn is_low(&mut self) -> bool { self.pin.is_low() } /// Returns current pin level #[inline] - pub fn get_level(&self) -> Level { + pub fn get_level(&mut self) -> Level { self.pin.get_level() } @@ -488,19 +498,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { /// Is the output pin set as high? #[inline] - pub fn is_set_high(&self) -> bool { + pub fn is_set_high(&mut self) -> bool { self.pin.is_set_high() } /// Is the output pin set as low? #[inline] - pub fn is_set_low(&self) -> bool { + pub fn is_set_low(&mut self) -> bool { self.pin.is_set_low() } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn get_output_level(&mut self) -> Level { self.pin.get_output_level() } @@ -777,12 +787,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { #[inline] fn is_high(&self) -> Result { - Ok(self.is_high()) + Ok(!self.pin.ref_is_low()) } #[inline] fn is_low(&self) -> Result { - Ok(self.is_low()) + Ok(self.pin.ref_is_low()) } } @@ -805,13 +815,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { #[inline] fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) + Ok(!self.pin.ref_is_set_low()) } /// Is the output pin set as low? #[inline] fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) + Ok(self.pin.ref_is_set_low()) } } @@ -843,13 +853,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { #[inline] fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) + Ok(!self.pin.ref_is_set_low()) } /// Is the output pin set as low? #[inline] fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) + Ok(self.pin.ref_is_set_low()) } } @@ -867,12 +877,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { #[inline] fn is_high(&self) -> Result { - Ok(self.is_high()) + Ok(!self.ref_is_low()) } #[inline] fn is_low(&self) -> Result { - Ok(self.is_low()) + Ok(self.ref_is_low()) } } @@ -895,13 +905,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { #[inline] fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) + Ok(!self.ref_is_set_low()) } /// Is the output pin set as low? #[inline] fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) + Ok(self.ref_is_set_low()) } } @@ -920,12 +930,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { #[inline] - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } #[inline] - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } @@ -948,13 +958,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { #[inline] - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.is_set_high()) } /// Is the output pin set as low? #[inline] - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(self.is_set_low()) } } @@ -972,12 +982,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { #[inline] - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } #[inline] - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } @@ -996,13 +1006,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { #[inline] - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.is_set_high()) } /// Is the output pin set as low? #[inline] - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(self.is_set_low()) } } @@ -1016,12 +1026,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrai impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { #[inline] - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(self.is_high()) } #[inline] - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(self.is_low()) } } @@ -1051,13 +1061,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { #[inline] - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.is_set_high()) } /// Is the output pin set as low? #[inline] - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(self.is_set_low()) } } diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index d8c0c7d08..99f6ef7ac 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -24,8 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.1.3 - 2023-08-28 -- Update `embedded-hal-async` to `1.0.0-rc.2` -- Update `embedded-hal v1` to `1.0.0-rc.2` +- Update `embedded-hal-async` to `1.0.0-rc.3` +- Update `embedded-hal v1` to `1.0.0-rc.3` ## 0.1.2 - 2023-07-05 diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 94e79382f..6d9b7aa69 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -235,8 +235,8 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } futures-util = { version = "0.3.17", default-features = false } critical-section = "1.1" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 65cd631f8..1c49c32e1 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -36,9 +36,9 @@ rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.1" usbd-hid = "0.6.0" serde = { version = "1.0.136", default-features = false } -embedded-hal = { version = "1.0.0-rc.2" } -embedded-hal-async = { version = "1.0.0-rc.2" } -embedded-hal-bus = { version = "0.1.0-rc.2", features = ["async"] } +embedded-hal = { version = "1.0.0-rc.3" } +embedded-hal-async = { version = "1.0.0-rc.3" } +embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] } num-integer = { version = "0.1.45", default-features = false } microfft = "0.5.0" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 7f637758d..521f17b82 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -38,9 +38,9 @@ smart-leds = "0.3.0" heapless = "0.8" usbd-hid = "0.6.1" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = "1.0.0-rc.2" -embedded-hal-bus = { version = "0.1.0-rc.2", features = ["async"] } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = "1.0.0-rc.3" +embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-storage = { version = "0.3" } static_cell = { version = "2", features = ["nightly"]} diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs index d7aa89410..a9f34ab5d 100644 --- a/examples/rp/src/bin/button.rs +++ b/examples/rp/src/bin/button.rs @@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { // Use PIN_28, Pin34 on J0 for RP Pico, as a input. // You need to add your own button. - let button = Input::new(p.PIN_28, Pull::Up); + let mut button = Input::new(p.PIN_28, Pull::Up); loop { if button.is_high() { diff --git a/examples/stm32c0/src/bin/button.rs b/examples/stm32c0/src/bin/button.rs index 72a3f5cbf..40c58013b 100644 --- a/examples/stm32c0/src/bin/button.rs +++ b/examples/stm32c0/src/bin/button.rs @@ -13,7 +13,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PC13, Pull::Up); + let mut button = Input::new(p.PC13, Pull::Up); loop { if button.is_high() { diff --git a/examples/stm32f3/src/bin/button.rs b/examples/stm32f3/src/bin/button.rs index b55bf3901..2f47d8f80 100644 --- a/examples/stm32f3/src/bin/button.rs +++ b/examples/stm32f3/src/bin/button.rs @@ -13,7 +13,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PA0, Pull::Down); + let mut button = Input::new(p.PA0, Pull::Down); let mut led1 = Output::new(p.PE9, Level::High, Speed::Low); let mut led2 = Output::new(p.PE15, Level::High, Speed::Low); diff --git a/examples/stm32f4/src/bin/button.rs b/examples/stm32f4/src/bin/button.rs index b13e64531..aa1eed46f 100644 --- a/examples/stm32f4/src/bin/button.rs +++ b/examples/stm32f4/src/bin/button.rs @@ -13,7 +13,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PC13, Pull::Down); + let mut button = Input::new(p.PC13, Pull::Down); let mut led1 = Output::new(p.PB0, Level::High, Speed::Low); let _led2 = Output::new(p.PB7, Level::High, Speed::Low); let mut led3 = Output::new(p.PB14, Level::High, Speed::Low); diff --git a/examples/stm32f7/src/bin/button.rs b/examples/stm32f7/src/bin/button.rs index b13e64531..aa1eed46f 100644 --- a/examples/stm32f7/src/bin/button.rs +++ b/examples/stm32f7/src/bin/button.rs @@ -13,7 +13,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PC13, Pull::Down); + let mut button = Input::new(p.PC13, Pull::Down); let mut led1 = Output::new(p.PB0, Level::High, Speed::Low); let _led2 = Output::new(p.PB7, Level::High, Speed::Low); let mut led3 = Output::new(p.PB14, Level::High, Speed::Low); diff --git a/examples/stm32g0/src/bin/button.rs b/examples/stm32g0/src/bin/button.rs index 72a3f5cbf..40c58013b 100644 --- a/examples/stm32g0/src/bin/button.rs +++ b/examples/stm32g0/src/bin/button.rs @@ -13,7 +13,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PC13, Pull::Up); + let mut button = Input::new(p.PC13, Pull::Up); loop { if button.is_high() { diff --git a/examples/stm32g4/src/bin/button.rs b/examples/stm32g4/src/bin/button.rs index 15abd86d9..127efb08a 100644 --- a/examples/stm32g4/src/bin/button.rs +++ b/examples/stm32g4/src/bin/button.rs @@ -13,7 +13,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PC13, Pull::Down); + let mut button = Input::new(p.PC13, Pull::Down); loop { if button.is_high() { diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 0ed0ce3c0..f714a3984 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -19,8 +19,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } embedded-io-async = { version = "0.6.1" } embedded-nal-async = { version = "0.7.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index baa530cf6..c6aea3e11 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -19,8 +19,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } embedded-nal-async = { version = "0.7.1" } embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/stm32l0/src/bin/button.rs b/examples/stm32l0/src/bin/button.rs index 9d194471e..3e56160e9 100644 --- a/examples/stm32l0/src/bin/button.rs +++ b/examples/stm32l0/src/bin/button.rs @@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PB2, Pull::Up); + let mut button = Input::new(p.PB2, Pull::Up); let mut led1 = Output::new(p.PA5, Level::High, Speed::Low); let mut led2 = Output::new(p.PB5, Level::High, Speed::Low); diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index a936d27c3..2861216d4 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -24,9 +24,9 @@ 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" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } -embedded-hal-bus = { version = "=0.1.0-rc.2", features = ["async"] } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] } 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 } diff --git a/examples/stm32l4/src/bin/button.rs b/examples/stm32l4/src/bin/button.rs index 73b1962e8..0a102c2d6 100644 --- a/examples/stm32l4/src/bin/button.rs +++ b/examples/stm32l4/src/bin/button.rs @@ -12,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PC13, Pull::Up); + let mut button = Input::new(p.PC13, Pull::Up); loop { if button.is_high() { diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 4826e0bed..8ec810c7f 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -114,8 +114,8 @@ async fn main(spawner: Spawner) { let led_uc4_blue = Output::new(dp.PG15, Level::High, Speed::Low); // Read the uc_cfg switches - let uc_cfg0 = Input::new(dp.PB2, Pull::None); - let uc_cfg1 = Input::new(dp.PF11, Pull::None); + let mut uc_cfg0 = Input::new(dp.PB2, Pull::None); + let mut uc_cfg1 = Input::new(dp.PF11, Pull::None); let _uc_cfg2 = Input::new(dp.PG6, Pull::None); let _uc_cfg3 = Input::new(dp.PG11, Pull::None); @@ -133,8 +133,8 @@ async fn main(spawner: Spawner) { // Setup IO and SPI for the SPE chip let spe_reset_n = Output::new(dp.PC7, Level::Low, Speed::Low); - let spe_cfg0 = Input::new(dp.PC8, Pull::None); - let spe_cfg1 = Input::new(dp.PC9, Pull::None); + let mut spe_cfg0 = Input::new(dp.PC8, Pull::None); + let mut spe_cfg1 = Input::new(dp.PC9, Pull::None); let _spe_ts_capt = Output::new(dp.PC6, Level::Low, Speed::Low); let spe_int = Input::new(dp.PB11, Pull::None); diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs index f1b80087c..903ca58df 100644 --- a/examples/stm32l4/src/bin/spi_blocking_async.rs +++ b/examples/stm32l4/src/bin/spi_blocking_async.rs @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh); let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh); let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); - let ready = Input::new(p.PE1, Pull::Up); + let mut ready = Input::new(p.PE1, Pull::Up); cortex_m::asm::delay(100_000); reset.set_high(); diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs index ff9b5b43b..58cf2e51e 100644 --- a/examples/stm32l4/src/bin/spi_dma.rs +++ b/examples/stm32l4/src/bin/spi_dma.rs @@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) { let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh); let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh); let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); - let ready = Input::new(p.PE1, Pull::Up); + let mut ready = Input::new(p.PE1, Pull::Up); cortex_m::asm::delay(100_000); reset.set_high(); diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index 982a7a112..6c1f5a5ef 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -13,7 +13,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PA0, Pull::Up); + let mut button = Input::new(p.PA0, Pull::Up); let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); let mut led2 = Output::new(p.PB9, Level::High, Speed::Low); diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 7b0d59ee2..b6067abcc 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -16,8 +16,8 @@ embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } -embedded-hal-async = { version = "1.0.0-rc.2" } -embedded-hal-bus = { version = "0.1.0-rc.2", features = ["async"] } +embedded-hal-async = { version = "1.0.0-rc.3" } +embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] } static_cell = { version = "2", features = [ "nightly" ] } perf-client = { path = "../perf-client" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 44fb7bed6..028ce43ee 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -24,9 +24,9 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6" } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } -embedded-hal-bus = { version = "=0.1.0-rc.2", features = ["async"] } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] } panic-probe = { version = "0.3.0", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } embedded-io-async = { version = "0.6.1" } diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs index e0c309887..a57d5d9e8 100644 --- a/tests/rp/src/bin/gpio.rs +++ b/tests/rp/src/bin/gpio.rs @@ -16,10 +16,10 @@ async fn main(_spawner: Spawner) { // Test initial output { - let b = Input::new(&mut b, Pull::None); + let mut b = Input::new(&mut b, Pull::None); { - let a = Output::new(&mut a, Level::Low); + let mut a = Output::new(&mut a, Level::Low); delay(); assert!(b.is_low()); assert!(!b.is_high()); @@ -64,7 +64,7 @@ async fn main(_spawner: Spawner) { // Test input no pull { - let b = Input::new(&mut b, Pull::None); + let mut b = Input::new(&mut b, Pull::None); // no pull, the status is undefined let mut a = Output::new(&mut a, Level::Low); @@ -77,7 +77,7 @@ async fn main(_spawner: Spawner) { // Test input pulldown { - let b = Input::new(&mut b, Pull::Down); + let mut b = Input::new(&mut b, Pull::Down); delay(); assert!(b.is_low()); @@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) { // Test input pullup { - let b = Input::new(&mut b, Pull::Up); + let mut b = Input::new(&mut b, Pull::Up); delay(); assert!(b.is_high()); diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs index e71d9e610..3fc0bb2a0 100644 --- a/tests/rp/src/bin/pwm.rs +++ b/tests/rp/src/bin/pwm.rs @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) { // Test output from A { - let pin1 = Input::new(&mut p9, Pull::None); + let mut pin1 = Input::new(&mut p9, Pull::None); let _pwm = Pwm::new_output_a(&mut p.PWM_CH3, &mut p6, cfg.clone()); Timer::after_millis(1).await; assert_eq!(pin1.is_low(), invert_a); @@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) { // Test output from B { - let pin2 = Input::new(&mut p11, Pull::None); + let mut pin2 = Input::new(&mut p11, Pull::None); let _pwm = Pwm::new_output_b(&mut p.PWM_CH3, &mut p7, cfg.clone()); Timer::after_millis(1).await; assert_ne!(pin2.is_low(), invert_a); @@ -73,8 +73,8 @@ async fn main(_spawner: Spawner) { // Test output from A+B { - let pin1 = Input::new(&mut p9, Pull::None); - let pin2 = Input::new(&mut p11, Pull::None); + let mut pin1 = Input::new(&mut p9, Pull::None); + let mut pin2 = Input::new(&mut p11, Pull::None); let _pwm = Pwm::new_output_ab(&mut p.PWM_CH3, &mut p6, &mut p7, cfg.clone()); Timer::after_millis(1).await; assert_eq!(pin1.is_low(), invert_a); diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 4f53e84f0..bdec41571 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -63,8 +63,8 @@ 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" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } -embedded-hal-async = { version = "=1.0.0-rc.2" } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } +embedded-hal-async = { version = "=1.0.0-rc.3" } micromath = "2.0.0" panic-probe = { version = "0.3.0", features = ["print-defmt"] } rand_core = { version = "0.6", default-features = false } diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs index c4e2fe161..9f1993024 100644 --- a/tests/stm32/src/bin/gpio.rs +++ b/tests/stm32/src/bin/gpio.rs @@ -20,10 +20,10 @@ async fn main(_spawner: Spawner) { // Test initial output { - let b = Input::new(&mut b, Pull::None); + let mut b = Input::new(&mut b, Pull::None); { - let a = Output::new(&mut a, Level::Low, Speed::Low); + let mut a = Output::new(&mut a, Level::Low, Speed::Low); delay(); assert!(b.is_low()); assert!(!b.is_high()); @@ -68,7 +68,7 @@ async fn main(_spawner: Spawner) { // Test input no pull { - let b = Input::new(&mut b, Pull::None); + let mut b = Input::new(&mut b, Pull::None); // no pull, the status is undefined let mut a = Output::new(&mut a, Level::Low, Speed::Low); @@ -81,7 +81,7 @@ async fn main(_spawner: Spawner) { // Test input pulldown { - let b = Input::new(&mut b, Pull::Down); + let mut b = Input::new(&mut b, Pull::Down); delay(); assert!(b.is_low()); @@ -95,7 +95,7 @@ async fn main(_spawner: Spawner) { // Test input pullup { - let b = Input::new(&mut b, Pull::Up); + let mut b = Input::new(&mut b, Pull::Up); delay(); assert!(b.is_high()); @@ -109,7 +109,7 @@ async fn main(_spawner: Spawner) { // Test output open drain { - let b = Input::new(&mut b, Pull::Down); + let mut b = Input::new(&mut b, Pull::Down); // no pull, the status is undefined let mut a = OutputOpenDrain::new(&mut a, Level::Low, Speed::Low, Pull::None); From a34abd849f09187edea48713538403ebf44d6576 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 10:30:10 -0500 Subject: [PATCH 023/760] Add examples to ci.sh --- ci.sh | 2 ++ examples/boot/application/stm32wb-dfu/Cargo.toml | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 8a5e206d2..83c05d1b9 100755 --- a/ci.sh +++ b/ci.sh @@ -173,10 +173,12 @@ cargo batch \ --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \ --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \ --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \ + --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/boot/stm32wb-dfu \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ + --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf \ --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index e67224ce6..57d51de02 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -30,4 +30,3 @@ defmt = [ "embassy-boot-stm32/defmt", "embassy-sync/defmt", ] -skip-include = [] From e579095a9075c8a3efdb956877b533f47ef1ec42 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 14 Dec 2023 16:30:45 +0100 Subject: [PATCH 024/760] ci: fix test job not caching anything. --- .github/ci/build-stable.sh | 2 +- .github/ci/build.sh | 2 +- .github/ci/crlf.sh | 2 +- .github/ci/test.sh | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/ci/build-stable.sh b/.github/ci/build-stable.sh index 9160a2be2..e0bd77867 100755 --- a/.github/ci/build-stable.sh +++ b/.github/ci/build-stable.sh @@ -27,4 +27,4 @@ sed -i 's/channel.*/channel = "beta"/g' rust-toolchain.toml # Save lockfiles echo Saving lockfiles... -find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+ \ No newline at end of file +find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+ diff --git a/.github/ci/build.sh b/.github/ci/build.sh index e7a6c0d86..77d2b3cab 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -31,4 +31,4 @@ hashtime save /ci/cache/filetime.json # Save lockfiles echo Saving lockfiles... -find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+ \ No newline at end of file +find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+ diff --git a/.github/ci/crlf.sh b/.github/ci/crlf.sh index 457510407..69838ce88 100755 --- a/.github/ci/crlf.sh +++ b/.github/ci/crlf.sh @@ -14,4 +14,4 @@ else echo -e "ERROR: Found ${NR_FILES} files with CRLF endings." echo "$FILES_WITH_CRLF" exit "$NR_FILES" -fi \ No newline at end of file +fi diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 1ee760d31..0ec65d2a1 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -4,6 +4,10 @@ set -euo pipefail +export RUSTUP_HOME=/ci/cache/rustup +export CARGO_HOME=/ci/cache/cargo +export CARGO_TARGET_DIR=/ci/cache/target + 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 From 27d054aa6875d977efc5f5c3554c57fd1245bdb9 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 10:34:22 -0500 Subject: [PATCH 025/760] Adjust toml files, fix application example --- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/src/main.rs | 10 +++++----- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 57d51de02..0ed0b75e0 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "embassy-boot-stm32wl-examples" +name = "embassy-boot-stm32wb-dfu-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index f03003ffe..cdac903b5 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -6,7 +6,7 @@ use core::cell::RefCell; #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; -use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; +use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig}; use embassy_executor::Spawner; use embassy_stm32::flash::{Flash, WRITE_SIZE}; use embassy_stm32::rcc::WPAN_DEFAULT; @@ -33,8 +33,8 @@ async fn main(_spawner: Spawner) { let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); - let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0); - updater.mark_booted().expect("Failed to mark booted"); + let mut firmware_state = BlockingFirmwareState::from_config(config, &mut magic.0); + firmware_state.mark_booted().expect("Failed to mark booted"); let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) { let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD); + let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD); let mut builder = Builder::new( driver, config, @@ -57,7 +57,7 @@ async fn main(_spawner: Spawner) { &mut control_buf, ); - usb_dfu::<_, _, _>(&mut builder, &mut state, Duration::from_millis(2500)); + usb_dfu::<_, _>(&mut builder, &mut state, Duration::from_millis(2500)); let mut dev = builder.build(); dev.run().await diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 774a8223d..fde9eb57d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -1,8 +1,8 @@ [package] edition = "2021" -name = "stm32-bootloader-example" +name = "stm32wb-dfu-bootloader-example" version = "0.1.0" -description = "Example bootloader for STM32 chips" +description = "Example USB DFUbootloader for the STM32WB series of chips" license = "MIT OR Apache-2.0" [dependencies] From cbc8ccc51e8e747fab51ac377225495cd24eb447 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 10:56:16 -0500 Subject: [PATCH 026/760] Adjust stm32wb-dfu example memory maps to fix linker errors --- examples/boot/application/stm32wb-dfu/memory.x | 4 ++-- examples/boot/bootloader/stm32wb-dfu/memory.x | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/boot/application/stm32wb-dfu/memory.x b/examples/boot/application/stm32wb-dfu/memory.x index f51875766..ff1b800d2 100644 --- a/examples/boot/application/stm32wb-dfu/memory.x +++ b/examples/boot/application/stm32wb-dfu/memory.x @@ -3,8 +3,8 @@ MEMORY /* NOTE 1 K = 1 KiBi = 1024 bytes */ BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - FLASH : ORIGIN = 0x08008000, LENGTH = 32K - DFU : ORIGIN = 0x08010000, LENGTH = 36K + FLASH : ORIGIN = 0x08008000, LENGTH = 128K + DFU : ORIGIN = 0x08028000, LENGTH = 132K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } diff --git a/examples/boot/bootloader/stm32wb-dfu/memory.x b/examples/boot/bootloader/stm32wb-dfu/memory.x index b6f185ef7..858062631 100644 --- a/examples/boot/bootloader/stm32wb-dfu/memory.x +++ b/examples/boot/bootloader/stm32wb-dfu/memory.x @@ -3,8 +3,8 @@ MEMORY /* NOTE 1 K = 1 KiBi = 1024 bytes */ FLASH : ORIGIN = 0x08000000, LENGTH = 24K BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - ACTIVE : ORIGIN = 0x08008000, LENGTH = 32K - DFU : ORIGIN = 0x08010000, LENGTH = 36K + ACTIVE : ORIGIN = 0x08008000, LENGTH = 128K + DFU : ORIGIN = 0x08028000, LENGTH = 132K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K } From 9f9f6e75bb3ef6d285ebed88a20ab57fb55f3d07 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 13:29:26 -0500 Subject: [PATCH 027/760] Abstract chip reset logic, add Reset impls for cortex-m and esp32c3 --- embassy-usb-dfu/Cargo.toml | 5 +-- embassy-usb-dfu/src/application.rs | 17 ++++++---- embassy-usb-dfu/src/bootloader.rs | 19 ++++++++---- embassy-usb-dfu/src/lib.rs | 31 +++++++++++++++++++ .../boot/application/stm32wb-dfu/Cargo.toml | 2 +- .../boot/application/stm32wb-dfu/src/main.rs | 4 +-- .../boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- .../boot/bootloader/stm32wb-dfu/src/main.rs | 4 +-- 8 files changed, 64 insertions(+), 20 deletions(-) diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 62398afbc..02146c646 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -15,15 +15,16 @@ categories = [ [dependencies] bitflags = "2.4.1" -cortex-m = { version = "0.7.7", features = ["inline-asm"] } +cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } defmt = { version = "0.3.5", optional = true } embassy-boot = { version = "0.1.1", path = "../embassy-boot/boot" } -embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } +# embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-time = { version = "0.2.0", path = "../embassy-time" } embassy-usb = { version = "0.1.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } +esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } [features] bootloader = [] diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 5ff8f90f8..75689db26 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -1,3 +1,5 @@ +use core::marker::PhantomData; + use embassy_boot::BlockingFirmwareState; use embassy_time::{Duration, Instant}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; @@ -9,17 +11,19 @@ use crate::consts::{ DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT, USB_CLASS_APPN_SPEC, }; +use crate::Reset; /// Internal state for the DFU class -pub struct Control<'d, STATE: NorFlash> { +pub struct Control<'d, STATE: NorFlash, RST: Reset> { firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes, state: State, timeout: Option, detach_start: Option, + _rst: PhantomData, } -impl<'d, STATE: NorFlash> Control<'d, STATE> { +impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { Control { firmware_state, @@ -27,11 +31,12 @@ impl<'d, STATE: NorFlash> Control<'d, STATE> { state: State::AppIdle, detach_start: None, timeout: None, + _rst: PhantomData, } } } -impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> { +impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { fn reset(&mut self) { if let Some(start) = self.detach_start { let delta = Instant::now() - start; @@ -45,7 +50,7 @@ impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> { self.firmware_state .mark_dfu() .expect("Failed to mark DFU mode in bootloader"); - cortex_m::peripheral::SCB::sys_reset(); + RST::sys_reset() } } } @@ -103,9 +108,9 @@ impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> { /// it should expose a DFU device, and a software reset will be issued. /// /// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. -pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash>( +pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>( builder: &mut Builder<'d, D>, - handler: &'d mut Control<'d, STATE>, + handler: &'d mut Control<'d, STATE, RST>, timeout: Duration, ) { let mut func = builder.function(0x00, 0x00, 0x00); diff --git a/embassy-usb-dfu/src/bootloader.rs b/embassy-usb-dfu/src/bootloader.rs index 99384d961..d41e6280d 100644 --- a/embassy-usb-dfu/src/bootloader.rs +++ b/embassy-usb-dfu/src/bootloader.rs @@ -1,3 +1,5 @@ +use core::marker::PhantomData; + use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; @@ -8,17 +10,19 @@ use crate::consts::{ DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU, USB_CLASS_APPN_SPEC, }; +use crate::Reset; /// Internal state for USB DFU -pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> { +pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> { updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes, state: State, status: Status, offset: usize, + _rst: PhantomData, } -impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, BLOCK_SIZE> { +impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> { pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { Self { updater, @@ -26,6 +30,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Control<'d, DF state: State::DfuIdle, status: Status::Ok, offset: 0, + _rst: PhantomData, } } @@ -36,7 +41,9 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Control<'d, DF } } -impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Control<'d, DFU, STATE, BLOCK_SIZE> { +impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Handler + for Control<'d, DFU, STATE, RST, BLOCK_SIZE> +{ fn control_out( &mut self, req: embassy_usb::control::Request, @@ -131,7 +138,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]); match self.state { State::DlSync => self.state = State::Download, - State::ManifestSync => cortex_m::peripheral::SCB::sys_reset(), + State::ManifestSync => RST::sys_reset(), _ => {} } @@ -157,9 +164,9 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co /// /// Once the host has initiated a DFU download operation, the chunks sent by the host will be written to the DFU partition. /// Once the final sync in the manifestation phase has been received, the handler will trigger a system reset to swap the new firmware. -pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize>( +pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize>( builder: &mut Builder<'d, D>, - handler: &'d mut Control<'d, DFU, STATE, BLOCK_SIZE>, + handler: &'d mut Control<'d, DFU, STATE, RST, BLOCK_SIZE>, ) { let mut func = builder.function(0x00, 0x00, 0x00); let mut iface = func.interface(); diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs index ae0fbbd4c..283905de9 100644 --- a/embassy-usb-dfu/src/lib.rs +++ b/embassy-usb-dfu/src/lib.rs @@ -18,3 +18,34 @@ pub use self::application::*; not(any(feature = "bootloader", feature = "application")) ))] compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features"); + +/// Provides a platform-agnostic interface for initiating a system reset. +/// +/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a +/// reset request without interfacing with any other peripherals. +/// +/// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function. +pub trait Reset { + fn sys_reset() -> !; +} + +#[cfg(feature = "esp32c3-hal")] +pub struct ResetImmediate; + +#[cfg(feature = "esp32c3-hal")] +impl Reset for ResetImmediate { + fn sys_reset() -> ! { + esp32c3_hal::reset::software_reset(); + loop {} + } +} + +#[cfg(feature = "cortex-m")] +pub struct ResetImmediate; + +#[cfg(feature = "cortex-m")] +impl Reset for ResetImmediate { + fn sys_reset() -> ! { + cortex_m::peripheral::SCB::sys_reset() + } +} diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 0ed0b75e0..f6beea498 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -12,7 +12,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", feature embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" } -embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application"] } +embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index cdac903b5..fbecbf23b 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -16,7 +16,7 @@ use embassy_sync::blocking_mutex::Mutex; use embassy_time::Duration; use embassy_usb::Builder; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control}; +use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; use panic_reset as _; bind_interrupts!(struct Irqs { @@ -57,7 +57,7 @@ async fn main(_spawner: Spawner) { &mut control_buf, ); - usb_dfu::<_, _>(&mut builder, &mut state, Duration::from_millis(2500)); + usb_dfu::<_, _, ResetImmediate>(&mut builder, &mut state, Duration::from_millis(2500)); let mut dev = builder.build(); dev.run().await diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index fde9eb57d..e849eb539 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -17,7 +17,7 @@ cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" cfg-if = "1.0.0" -embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["bootloader"] } +embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["bootloader", "cortex-m"] } embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false } embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index db7039e8c..a7ab813b6 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -14,7 +14,7 @@ use embassy_stm32::{bind_interrupts, peripherals, usb}; use embassy_sync::blocking_mutex::Mutex; use embassy_usb::Builder; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control}; +use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; bind_interrupts!(struct Irqs { USB_LP => usb::InterruptHandler; @@ -64,7 +64,7 @@ fn main() -> ! { &mut control_buf, ); - usb_dfu::<_, _, _, 4096>(&mut builder, &mut state); + usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state); let mut dev = builder.build(); embassy_futures::block_on(dev.run()); From 33e8943e5b6e637b82f13c77bd88bb56d55ab515 Mon Sep 17 00:00:00 2001 From: Kaitlyn Kenwell Date: Thu, 14 Dec 2023 14:16:58 -0500 Subject: [PATCH 028/760] Rename bootloader feature to dfu --- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-dfu/src/lib.rs | 8 ++++---- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 02146c646..ee110ee87 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -27,6 +27,6 @@ embedded-storage = { version = "0.3.1" } esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } [features] -bootloader = [] +dfu = [] application = [] defmt = ["dep:defmt"] diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs index 283905de9..389bb33f2 100644 --- a/embassy-usb-dfu/src/lib.rs +++ b/embassy-usb-dfu/src/lib.rs @@ -3,9 +3,9 @@ mod fmt; pub mod consts; -#[cfg(feature = "bootloader")] +#[cfg(feature = "dfu")] mod bootloader; -#[cfg(feature = "bootloader")] +#[cfg(feature = "dfu")] pub use self::bootloader::*; #[cfg(feature = "application")] @@ -14,8 +14,8 @@ mod application; pub use self::application::*; #[cfg(any( - all(feature = "bootloader", feature = "application"), - not(any(feature = "bootloader", feature = "application")) + all(feature = "dfu", feature = "application"), + not(any(feature = "dfu", feature = "application")) ))] compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features"); diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index e849eb539..ada073970 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -17,7 +17,7 @@ cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" cfg-if = "1.0.0" -embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["bootloader", "cortex-m"] } +embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false } embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } From 98481c20fe44d5f0dea88675d08aa21c0fd8091c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 14 Dec 2023 21:11:33 +0100 Subject: [PATCH 029/760] use released embedded-hal-mock. --- embassy-net-adin1110/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index adcdfe80f..b1582ac9b 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -22,7 +22,7 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" [dev-dependencies] -embedded-hal-mock = { git = "https://github.com/Dirbaio/embedded-hal-mock", rev = "b5a2274759a8c484f4fae71a22f8a083fdd9d5da", features = ["embedded-hal-async", "eh1"] } +embedded-hal-mock = { version = "0.10.0-rc.4", features = ["embedded-hal-async", "eh1"] } crc = "3.0.1" env_logger = "0.10" critical-section = { version = "1.1.2", features = ["std"] } From a165d73eedfd7e02fe5360e9d844882e0d0df113 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 15 Dec 2023 14:10:11 +0800 Subject: [PATCH 030/760] add ws2812 example for stm32f4 with PWM and DMA --- examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 135 +++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 examples/stm32f4/src/bin/ws2812_pwm_dma.rs diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs new file mode 100644 index 000000000..79493dced --- /dev/null +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -0,0 +1,135 @@ +// Configure TIM3 in PWM mode, and start DMA Transfer(s) to send color data into ws2812. +// We assume the DIN pin of ws2812 connect to GPIO PB4, and ws2812 is properly powered. +// +// This demo is a combination of HAL, PAC, and manually invoke `dma::Transfer` +// +// Warning: +// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use embassy_executor::Spawner; + +use embassy_stm32::{ + gpio::OutputType, + pac, + time::khz, + timer::{ + simple_pwm::{PwmPin, SimplePwm}, + Channel, CountingMode, + }, +}; +use embassy_time::Timer; + +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut device_config = embassy_stm32::Config::default(); + + // set SYSCLK/HCLK/PCLK2 to 20 MHz, thus each tick is 0.05 us, + // and ws2812 timings are integer multiples of 0.05 us + { + use embassy_stm32::rcc::*; + use embassy_stm32::time::*; + device_config.enable_debug_during_sleep = true; + device_config.rcc.hse = Some(Hse { + freq: mhz(12), + mode: HseMode::Oscillator, + }); + device_config.rcc.sys = Sysclk::PLL1_P; + device_config.rcc.pll_src = PllSource::HSE; + device_config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL80, + divp: Some(PllPDiv::DIV8), + divq: None, + divr: None, + }); + } + + let mut dp = embassy_stm32::init(device_config); + + let mut ws2812_pwm = SimplePwm::new( + dp.TIM3, + Some(PwmPin::new_ch1(dp.PB4, OutputType::PushPull)), + None, + None, + None, + khz(800), // data rate of ws2812 + CountingMode::EdgeAlignedUp, + ); + + // PAC level hacking, + // enable auto-reload preload, and enable timer-update-event trigger DMA + { + pac::TIM3.cr1().modify(|v| v.set_arpe(true)); + pac::TIM3.dier().modify(|v| v.set_ude(true)); + } + + // construct ws2812 non-return-to-zero (NRZ) code bit by bit + + let max_duty = ws2812_pwm.get_max_duty(); + let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing + let n1 = 2 * n0; // ws2812 Bit 1 high level timing + + let turn_off = [ + n0, n0, n0, n0, n0, n0, n0, n0, // Green + n0, n0, n0, n0, n0, n0, n0, n0, // Red + n0, n0, n0, n0, n0, n0, n0, n0, // Blue + 0, // keep PWM output low after a transfer + ]; + + let dim_white = [ + n0, n0, n0, n0, n0, n0, n1, n0, // Green + n0, n0, n0, n0, n0, n0, n1, n0, // Red + n0, n0, n0, n0, n0, n0, n1, n0, // Blue + 0, // keep PWM output low after a transfer + ]; + + let color_list = [&turn_off, &dim_white]; + + // make sure PWM output keep low on first start + ws2812_pwm.set_duty(Channel::Ch1, 0); + + { + use embassy_stm32::dma::{Burst, FifoThreshold, Transfer, TransferOptions}; + + // configure FIFO and MBURST of DMA, to minimize DMA occupation on AHB/APB + let mut dma_transfer_option = TransferOptions::default(); + dma_transfer_option.fifo_threshold = Some(FifoThreshold::Full); + dma_transfer_option.mburst = Burst::Incr8; + + let mut color_list_index = 0; + + loop { + // start PWM output + ws2812_pwm.enable(Channel::Ch1); + + unsafe { + Transfer::new_write( + // with &mut, we can easily reuse same DMA channel multiple times + &mut dp.DMA1_CH2, + 5, + color_list[color_list_index], + pac::TIM3.ccr(0).as_ptr() as *mut _, + dma_transfer_option, + ) + .await; + // ws2812 need at least 50 us low level input to confirm the input data and change it's state + Timer::after_micros(50).await; + } + + // stop PWM output for saving some energy + ws2812_pwm.disable(Channel::Ch1); + + // wait another half second, so that we can see color change + Timer::after_millis(500).await; + + // flip the index bit so that next round DMA transfer the other color data + color_list_index ^= 1; + } + } +} From 77e372e842c64b95e94fff93a711112514588841 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 15 Dec 2023 14:15:45 +0800 Subject: [PATCH 031/760] cargo fmt --- examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index 79493dced..0c3444a47 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -11,18 +11,12 @@ #![feature(type_alias_impl_trait)] use embassy_executor::Spawner; - -use embassy_stm32::{ - gpio::OutputType, - pac, - time::khz, - timer::{ - simple_pwm::{PwmPin, SimplePwm}, - Channel, CountingMode, - }, -}; +use embassy_stm32::gpio::OutputType; +use embassy_stm32::pac; +use embassy_stm32::time::khz; +use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::timer::{Channel, CountingMode}; use embassy_time::Timer; - use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] From e5e85ba02bc91a47d80ba89dee27e6ccb20f0ccd Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Fri, 15 Dec 2023 11:42:58 +0100 Subject: [PATCH 032/760] STM32H7: Allow PLL1 DIVP of 1 for certain series --- embassy-stm32/src/rcc/h.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 1889eb280..18dff9f29 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -70,7 +70,9 @@ pub struct Pll { pub mul: PllMul, /// PLL P division factor. If None, PLL P output is disabled. - /// On PLL1, it must be even (in particular, it cannot be 1.) + /// On PLL1, it must be even for most series (in particular, + /// it cannot be 1 in series other than STM32H723/733, + /// STM32H725/735 and STM32H730.) pub divp: Option, /// PLL Q division factor. If None, PLL Q output is disabled. pub divq: Option, @@ -729,9 +731,12 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { let p = config.divp.map(|div| { if num == 0 { - // on PLL1, DIVP must be even. + // on PLL1, DIVP must be even for most series. // The enum value is 1 less than the divider, so check it's odd. + #[cfg(not(pwr_h7rm0468))] assert!(div.to_bits() % 2 == 1); + #[cfg(pwr_h7rm0468)] + assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0); } vco_clk / div From a8d0da91dc7b43bb05b200e7f530e58e25f20194 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Fri, 15 Dec 2023 12:22:17 +0100 Subject: [PATCH 033/760] STM32H7: adjust frequency limits for series in RM0468 --- embassy-stm32/src/rcc/h.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 18dff9f29..f28bd0b9d 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -478,7 +478,14 @@ pub(crate) unsafe fn init(config: Config) { VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)), VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)), }; - #[cfg(all(stm32h7, not(pwr_h7rm0455)))] + #[cfg(pwr_h7rm0468)] + let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { + VoltageScale::Scale0 => (Hertz(550_000_000), Hertz(275_000_000), Hertz(137_500_000)), + VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), + VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), + VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)), + }; + #[cfg(all(stm32h7, not(any(pwr_h7rm0455, pwr_h7rm0468))))] let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)), VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), From c17fee27bb37233df7300bea3c2658f87df9dd6b Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Fri, 15 Dec 2023 13:53:06 +0100 Subject: [PATCH 034/760] STM32H7: limit max frequency to 520MHz until cpu frequency boost option is implemented --- embassy-stm32/src/rcc/h.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index f28bd0b9d..389b2a871 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -480,7 +480,7 @@ pub(crate) unsafe fn init(config: Config) { }; #[cfg(pwr_h7rm0468)] let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { - VoltageScale::Scale0 => (Hertz(550_000_000), Hertz(275_000_000), Hertz(137_500_000)), + VoltageScale::Scale0 => (Hertz(520_000_000), Hertz(275_000_000), Hertz(137_500_000)), VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)), From 560e72813292e0ceb32b25daf887bb69b48af771 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Fri, 15 Dec 2023 14:14:30 +0100 Subject: [PATCH 035/760] STM32H7: adjust flash latency and programming delay for series in RM0468 --- embassy-stm32/src/rcc/h.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 389b2a871..15b51a398 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -832,7 +832,7 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { _ => unreachable!(), }; - #[cfg(flash_h7)] + #[cfg(all(flash_h7, not(pwr_h7rm0468)))] let (latency, wrhighfreq) = match (vos, clk.0) { // VOS 0 range VCORE 1.26V - 1.40V (VoltageScale::Scale0, ..=70_000_000) => (0, 0), @@ -861,6 +861,30 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { _ => unreachable!(), }; + // See RM0468 Rev 3 Table 16. FLASH recommended number of wait + // states and programming delay + #[cfg(all(flash_h7, pwr_h7rm0468))] + let (latency, wrhighfreq) = match (vos, clk.0) { + // VOS 0 range VCORE 1.26V - 1.40V + (VoltageScale::Scale0, ..=70_000_000) => (0, 0), + (VoltageScale::Scale0, ..=140_000_000) => (1, 1), + (VoltageScale::Scale0, ..=210_000_000) => (2, 2), + (VoltageScale::Scale0, ..=275_000_000) => (3, 3), + // VOS 1 range VCORE 1.15V - 1.26V + (VoltageScale::Scale1, ..=67_000_000) => (0, 0), + (VoltageScale::Scale1, ..=133_000_000) => (1, 1), + (VoltageScale::Scale1, ..=200_000_000) => (2, 2), + // VOS 2 range VCORE 1.05V - 1.15V + (VoltageScale::Scale2, ..=50_000_000) => (0, 0), + (VoltageScale::Scale2, ..=100_000_000) => (1, 1), + (VoltageScale::Scale2, ..=150_000_000) => (2, 2), + // VOS 3 range VCORE 0.95V - 1.05V + (VoltageScale::Scale3, ..=35_000_000) => (0, 0), + (VoltageScale::Scale3, ..=70_000_000) => (1, 1), + (VoltageScale::Scale3, ..=85_000_000) => (2, 2), + _ => unreachable!(), + }; + // See RM0455 Rev 10 Table 16. FLASH recommended number of wait // states and programming delay #[cfg(flash_h7ab)] From ea1e1973eb88a3a57e7f4e2ad97d32e5fcd8b8d1 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 16 Dec 2023 02:15:56 +0800 Subject: [PATCH 036/760] unify channel assign --- examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index 0c3444a47..52cc665c7 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -85,8 +85,10 @@ async fn main(_spawner: Spawner) { let color_list = [&turn_off, &dim_white]; + let pwm_channel = Channel::Ch1; + // make sure PWM output keep low on first start - ws2812_pwm.set_duty(Channel::Ch1, 0); + ws2812_pwm.set_duty(pwm_channel, 0); { use embassy_stm32::dma::{Burst, FifoThreshold, Transfer, TransferOptions}; @@ -100,7 +102,7 @@ async fn main(_spawner: Spawner) { loop { // start PWM output - ws2812_pwm.enable(Channel::Ch1); + ws2812_pwm.enable(pwm_channel); unsafe { Transfer::new_write( @@ -108,7 +110,7 @@ async fn main(_spawner: Spawner) { &mut dp.DMA1_CH2, 5, color_list[color_list_index], - pac::TIM3.ccr(0).as_ptr() as *mut _, + pac::TIM3.ccr(pwm_channel.raw()).as_ptr() as *mut _, dma_transfer_option, ) .await; @@ -117,7 +119,7 @@ async fn main(_spawner: Spawner) { } // stop PWM output for saving some energy - ws2812_pwm.disable(Channel::Ch1); + ws2812_pwm.disable(pwm_channel); // wait another half second, so that we can see color change Timer::after_millis(500).await; From 3568e4a5ffb1aebb97dd58975b02a00cd0a116fe Mon Sep 17 00:00:00 2001 From: Piotr Esden-Tempski Date: Fri, 15 Dec 2023 16:47:56 -0800 Subject: [PATCH 037/760] STM32 QSPI: Fix flash selection. --- embassy-stm32/src/qspi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 4b0e8ecef..1153455c7 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -119,7 +119,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { Some(nss.map_into()), dma, config, - FlashSelection::Flash2, + FlashSelection::Flash1, ) } From f6bc96dfbd1ec363a7bed877240a971ff1760200 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Sat, 16 Dec 2023 03:44:15 +0000 Subject: [PATCH 038/760] STM32: Enable flash support for STM32G4 --- embassy-stm32/src/flash/f0.rs | 2 +- embassy-stm32/src/flash/f3.rs | 2 +- embassy-stm32/src/flash/f4.rs | 2 +- embassy-stm32/src/flash/f7.rs | 2 +- embassy-stm32/src/flash/{g0.rs => g.rs} | 2 +- embassy-stm32/src/flash/h7.rs | 2 +- embassy-stm32/src/flash/l.rs | 2 +- embassy-stm32/src/flash/mod.rs | 6 +++--- 8 files changed, 10 insertions(+), 10 deletions(-) rename embassy-stm32/src/flash/{g0.rs => g.rs} (98%) diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index 1ab8435a0..80d2a8166 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E pub(crate) unsafe fn clear_all_err() { // read and write back the same value. - // This clears all "write 0 to clear" bits. + // This clears all "write 1 to clear" bits. pac::FLASH.sr().modify(|_| {}); } diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 7e6d7ca26..27d5281a7 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E pub(crate) unsafe fn clear_all_err() { // read and write back the same value. - // This clears all "write 0 to clear" bits. + // This clears all "write 1 to clear" bits. pac::FLASH.sr().modify(|_| {}); } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 5d07020ce..f442c5894 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -337,7 +337,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E pub(crate) fn clear_all_err() { // read and write back the same value. - // This clears all "write 0 to clear" bits. + // This clears all "write 1 to clear" bits. pac::FLASH.sr().modify(|_| {}); } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index b52231ca8..017393e80 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -69,7 +69,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E pub(crate) unsafe fn clear_all_err() { // read and write back the same value. - // This clears all "write 0 to clear" bits. + // This clears all "write 1 to clear" bits. pac::FLASH.sr().modify(|_| {}); } diff --git a/embassy-stm32/src/flash/g0.rs b/embassy-stm32/src/flash/g.rs similarity index 98% rename from embassy-stm32/src/flash/g0.rs rename to embassy-stm32/src/flash/g.rs index 19a388970..08145e9c4 100644 --- a/embassy-stm32/src/flash/g0.rs +++ b/embassy-stm32/src/flash/g.rs @@ -92,6 +92,6 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { pub(crate) unsafe fn clear_all_err() { // read and write back the same value. - // This clears all "write 0 to clear" bits. + // This clears all "write 1 to clear" bits. pac::FLASH.sr().modify(|_| {}); } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index b064fd6ea..555f8d155 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -113,7 +113,7 @@ pub(crate) unsafe fn clear_all_err() { unsafe fn bank_clear_all_err(bank: pac::flash::Bank) { // read and write back the same value. - // This clears all "write 0 to clear" bits. + // This clears all "write 1 to clear" bits. bank.sr().modify(|_| {}); } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 1db0da923..e0159a3f6 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -120,7 +120,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E pub(crate) unsafe fn clear_all_err() { // read and write back the same value. - // This clears all "write 0 to clear" bits. + // This clears all "write 1 to clear" bits. pac::FLASH.sr().modify(|_| {}); } diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index fb20dcd38..3e8f2830b 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -63,13 +63,13 @@ impl FlashRegion { #[cfg_attr(flash_f3, path = "f3.rs")] #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] -#[cfg_attr(flash_g0, path = "g0.rs")] +#[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")] #[cfg_attr(flash_h7, path = "h7.rs")] #[cfg_attr(flash_h7ab, path = "h7.rs")] #[cfg_attr( not(any( - flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_h7, - flash_h7ab + flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_g4, + flash_h7, flash_h7ab )), path = "other.rs" )] From a5379e708cab6e284a00f8b01e9db3d5c2eb400c Mon Sep 17 00:00:00 2001 From: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sat, 16 Dec 2023 08:19:52 -0500 Subject: [PATCH 039/760] remove `suspendable` field from `embassy_usb::builder::Config` --- embassy-usb/src/builder.rs | 10 ---------- embassy-usb/src/lib.rs | 8 +++----- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index ebc1283e6..c4705d041 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -94,15 +94,6 @@ pub struct Config<'a> { /// Default: 100mA /// Max: 500mA pub max_power: u16, - - /// Allow the bus to be suspended. - /// - /// If set to `true`, the bus will put itself in the suspended state - /// when it receives a `driver::Event::Suspend` bus event. If you wish - /// to override this behavior, set this field to `false`. - /// - /// Default: `true` - pub suspendable: bool, } impl<'a> Config<'a> { @@ -123,7 +114,6 @@ impl<'a> Config<'a> { supports_remote_wakeup: false, composite_with_iads: false, max_power: 100, - suspendable: true, } } } diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index ff3295871..241e33a78 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -471,11 +471,9 @@ impl<'d, D: Driver<'d>> Inner<'d, D> { } Event::Suspend => { trace!("usb: suspend"); - if self.config.suspendable { - self.suspended = true; - for h in &mut self.handlers { - h.suspended(true); - } + self.suspended = true; + for h in &mut self.handlers { + h.suspended(true); } } Event::PowerDetected => { From 0a890cfbe7fc10bc40f2e97bc4fac17630e9864f Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sun, 17 Dec 2023 23:47:00 +0800 Subject: [PATCH 040/760] stm32f4 ws2812 example with spi ... ... and more doc on TIM&DMA version, also remove useless TIM APRE settings, and use for loop instead of manually flip the index bit, and replace `embassy_time::Timer` with `embassy_time::Ticker`, for more constant time interval. --- examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 74 +++++++++-------- examples/stm32f4/src/bin/ws2812_spi.rs | 95 ++++++++++++++++++++++ 2 files changed, 135 insertions(+), 34 deletions(-) create mode 100644 examples/stm32f4/src/bin/ws2812_spi.rs diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index 52cc665c7..dccd639ac 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -1,7 +1,16 @@ // Configure TIM3 in PWM mode, and start DMA Transfer(s) to send color data into ws2812. // We assume the DIN pin of ws2812 connect to GPIO PB4, and ws2812 is properly powered. // -// This demo is a combination of HAL, PAC, and manually invoke `dma::Transfer` +// The idea is that the data rate of ws2812 is 800 kHz, and it use different duty ratio to represent bit 0 and bit 1. +// Thus we can set TIM overflow at 800 kHz, and let TIM Update Event trigger a DMA transfer, then let DMA change CCR value, +// such that pwm duty ratio meet the bit representation of ws2812. +// +// You may want to modify TIM CCR with Cortex core directly, +// but according to my test, Cortex core will need to run far more than 100 MHz to catch up with TIM. +// Thus we need to use a DMA. +// +// This demo is a combination of HAL, PAC, and manually invoke `dma::Transfer`. +// If you need a simpler way to control ws2812, you may want to take a look at `ws2812_spi.rs` file, which make use of SPI. // // Warning: // DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. @@ -16,7 +25,7 @@ use embassy_stm32::pac; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::{Channel, CountingMode}; -use embassy_time::Timer; +use embassy_time::{Duration, Ticker, Timer}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -33,7 +42,6 @@ async fn main(_spawner: Spawner) { freq: mhz(12), mode: HseMode::Oscillator, }); - device_config.rcc.sys = Sysclk::PLL1_P; device_config.rcc.pll_src = PllSource::HSE; device_config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV6, @@ -42,6 +50,7 @@ async fn main(_spawner: Spawner) { divq: None, divr: None, }); + device_config.rcc.sys = Sysclk::PLL1_P; } let mut dp = embassy_stm32::init(device_config); @@ -56,14 +65,11 @@ async fn main(_spawner: Spawner) { CountingMode::EdgeAlignedUp, ); - // PAC level hacking, - // enable auto-reload preload, and enable timer-update-event trigger DMA - { - pac::TIM3.cr1().modify(|v| v.set_arpe(true)); - pac::TIM3.dier().modify(|v| v.set_ude(true)); - } + // PAC level hacking, enable timer-update-event trigger DMA + pac::TIM3.dier().modify(|v| v.set_ude(true)); // construct ws2812 non-return-to-zero (NRZ) code bit by bit + // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low let max_duty = ws2812_pwm.get_max_duty(); let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing @@ -83,7 +89,7 @@ async fn main(_spawner: Spawner) { 0, // keep PWM output low after a transfer ]; - let color_list = [&turn_off, &dim_white]; + let color_list = &[&turn_off, &dim_white]; let pwm_channel = Channel::Ch1; @@ -98,34 +104,34 @@ async fn main(_spawner: Spawner) { dma_transfer_option.fifo_threshold = Some(FifoThreshold::Full); dma_transfer_option.mburst = Burst::Incr8; - let mut color_list_index = 0; + // flip color at 2 Hz + let mut ticker = Ticker::every(Duration::from_micros(500)); loop { - // start PWM output - ws2812_pwm.enable(pwm_channel); + for &color in color_list { + // start PWM output + ws2812_pwm.enable(pwm_channel); - unsafe { - Transfer::new_write( - // with &mut, we can easily reuse same DMA channel multiple times - &mut dp.DMA1_CH2, - 5, - color_list[color_list_index], - pac::TIM3.ccr(pwm_channel.raw()).as_ptr() as *mut _, - dma_transfer_option, - ) - .await; - // ws2812 need at least 50 us low level input to confirm the input data and change it's state - Timer::after_micros(50).await; + unsafe { + Transfer::new_write( + // with &mut, we can easily reuse same DMA channel multiple times + &mut dp.DMA1_CH2, + 5, + color, + pac::TIM3.ccr(pwm_channel.raw()).as_ptr() as *mut _, + dma_transfer_option, + ) + .await; + // ws2812 need at least 50 us low level input to confirm the input data and change it's state + Timer::after_micros(50).await; + } + + // stop PWM output for saving some energy + ws2812_pwm.disable(pwm_channel); + + // wait until ticker tick + ticker.next().await; } - - // stop PWM output for saving some energy - ws2812_pwm.disable(pwm_channel); - - // wait another half second, so that we can see color change - Timer::after_millis(500).await; - - // flip the index bit so that next round DMA transfer the other color data - color_list_index ^= 1; } } } diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs new file mode 100644 index 000000000..e0d28af7f --- /dev/null +++ b/examples/stm32f4/src/bin/ws2812_spi.rs @@ -0,0 +1,95 @@ +// Mimic PWM with SPI, to control ws2812 +// We assume the DIN pin of ws2812 connect to GPIO PB5, and ws2812 is properly powered. +// +// The idea is that the data rate of ws2812 is 800 kHz, and it use different duty ratio to represent bit 0 and bit 1. +// Thus we can adjust SPI to send each *round* of data at 800 kHz, and in each *round*, we can adjust each *bit* to mimic 2 different PWM waveform. +// such that the output waveform meet the bit representation of ws2812. +// +// If you want to save SPI for other purpose, you may want to take a look at `ws2812_tim_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. + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use embassy_stm32::time::khz; +use embassy_stm32::{dma, spi}; +use embassy_time::{Duration, Ticker, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +// we use 16 bit data frame format of SPI, to let timing as accurate as possible. +// thanks to loose tolerance of ws2812 timing, you can also use 8 bit data frame format, thus you need want to adjust the bit representation. +const N0: u16 = 0b1111100000000000u16; // ws2812 Bit 0 high level timing +const N1: u16 = 0b1111111111000000u16; // ws2812 Bit 1 high level timing + +// ws2812 only need 24 bits for each LED, but we add one bit more to keep SPI output low + +static TURN_OFF: [u16; 25] = [ + N0, N0, N0, N0, N0, N0, N0, N0, // Green + N0, N0, N0, N0, N0, N0, N0, N0, // Red + N0, N0, N0, N0, N0, N0, N0, N0, // Blue + 0, // keep SPI output low after last bit +]; + +static DIM_WHITE: [u16; 25] = [ + N0, N0, N0, N0, N0, N0, N1, N0, // Green + N0, N0, N0, N0, N0, N0, N1, N0, // Red + N0, N0, N0, N0, N0, N0, N1, N0, // Blue + 0, // keep SPI output low after last bit +]; + +static COLOR_LIST: &[&[u16]] = &[&TURN_OFF, &DIM_WHITE]; + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let mut device_config = embassy_stm32::Config::default(); + + // Since we use 16 bit SPI, and we need each round 800 kHz, + // thus SPI output speed should be 800 kHz * 16 = 12.8 MHz, and APB clock should be 2 * 12.8 MHz = 25.6 MHz. + // + // As for my setup, with 12 MHz HSE, I got 25.5 MHz SYSCLK, which is slightly slower, but it's ok for ws2812. + { + use embassy_stm32::rcc::{Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllSource, Sysclk}; + use embassy_stm32::time::mhz; + device_config.enable_debug_during_sleep = true; + device_config.rcc.hse = Some(Hse { + freq: mhz(12), + mode: HseMode::Oscillator, + }); + device_config.rcc.pll_src = PllSource::HSE; + device_config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL102, + divp: Some(PllPDiv::DIV8), + divq: None, + divr: None, + }); + device_config.rcc.sys = Sysclk::PLL1_P; + } + + let dp = embassy_stm32::init(device_config); + + // Set SPI output speed. + // It's ok to blindly set frequency to 12800 kHz, the hal crate will take care of the SPI CR1 BR field. + // And in my case, the real bit rate will be 25.5 MHz / 2 = 12_750 kHz + let mut spi_config = spi::Config::default(); + spi_config.frequency = khz(12_800); + + // Since we only output waveform, then the Rx and Sck it is not considered + let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH2, dma::NoDma, spi_config); + + // flip color at 2 Hz + let mut ticker = Ticker::every(Duration::from_millis(500)); + + loop { + for &color in COLOR_LIST { + ws2812_spi.write(color).await.unwrap(); + // ws2812 need at least 50 us low level input to confirm the input data and change it's state + Timer::after_micros(50).await; + // wait until ticker tick + ticker.next().await; + } + } +} From 1934c2abc81f0dd981fad625ec2712964d0a1a91 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Mon, 18 Dec 2023 00:06:32 +0800 Subject: [PATCH 041/760] match up with stm32f429zi feature flag stm32f429 has less DMA channel than stm32f411 --- examples/stm32f4/src/bin/ws2812_spi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs index e0d28af7f..170f0b59b 100644 --- a/examples/stm32f4/src/bin/ws2812_spi.rs +++ b/examples/stm32f4/src/bin/ws2812_spi.rs @@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) { spi_config.frequency = khz(12_800); // Since we only output waveform, then the Rx and Sck it is not considered - let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH2, dma::NoDma, spi_config); + let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config); // flip color at 2 Hz let mut ticker = Ticker::every(Duration::from_millis(500)); From 05b8818de01866fa988a8f65a395690f02176b34 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Mon, 18 Dec 2023 01:02:58 +0800 Subject: [PATCH 042/760] typo fix --- examples/stm32f4/src/bin/ws2812_spi.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs index 170f0b59b..eca657900 100644 --- a/examples/stm32f4/src/bin/ws2812_spi.rs +++ b/examples/stm32f4/src/bin/ws2812_spi.rs @@ -5,7 +5,7 @@ // Thus we can adjust SPI to send each *round* of data at 800 kHz, and in each *round*, we can adjust each *bit* to mimic 2 different PWM waveform. // such that the output waveform meet the bit representation of ws2812. // -// If you want to save SPI for other purpose, you may want to take a look at `ws2812_tim_dma.rs` file, which make use of TIM and DMA. +// 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. @@ -20,11 +20,12 @@ use embassy_time::{Duration, Ticker, Timer}; use {defmt_rtt as _, panic_probe as _}; // we use 16 bit data frame format of SPI, to let timing as accurate as possible. -// thanks to loose tolerance of ws2812 timing, you can also use 8 bit data frame format, thus you need want to adjust the bit representation. +// thanks to loose tolerance of ws2812 timing, you can also use 8 bit data frame format, thus you will need to adjust the bit representation. const N0: u16 = 0b1111100000000000u16; // ws2812 Bit 0 high level timing const N1: u16 = 0b1111111111000000u16; // ws2812 Bit 1 high level timing -// ws2812 only need 24 bits for each LED, but we add one bit more to keep SPI output low +// ws2812 only need 24 bits for each LED, +// but we add one bit more to keep SPI output low at the end static TURN_OFF: [u16; 25] = [ N0, N0, N0, N0, N0, N0, N0, N0, // Green @@ -77,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut spi_config = spi::Config::default(); spi_config.frequency = khz(12_800); - // Since we only output waveform, then the Rx and Sck it is not considered + // Since we only output waveform, then the Rx and Sck and RxDma it is not considered let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config); // flip color at 2 Hz From b857334f92fc188004567edb93e0d1dfce4c259e Mon Sep 17 00:00:00 2001 From: RobertTDowling Date: Sun, 17 Dec 2023 15:11:03 -0800 Subject: [PATCH 043/760] STM32: Fix race in alarm setting, which impacted scheduling. Detect potential race condition (should be rare) and return false back to caller, allowing them to handle the possibility that either the alarm was never set because it was in the past (old meaning of false), or that in fact the alarm was set and may have fired within the race window (new meaning of false). In either case, the caller needs to make sure the callback got called. --- embassy-stm32/src/time_driver.rs | 19 ++++++++++++++++--- embassy-time/src/driver.rs | 4 ++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index ea9c22d87..9981800b2 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -474,16 +474,29 @@ impl Driver for RtcDriver { return false; } - let safe_timestamp = timestamp.max(t + 3); - // Write the CCR value regardless of whether we're going to enable it now or not. // This way, when we enable it later, the right value is already set. - r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)); + r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16)); // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. let diff = timestamp - t; r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); + // Reevaluate if the alarm timestamp is still in the future + let t = self.now(); + if timestamp <= t { + // If alarm timestamp has passed since we set it, we have a race condition and + // the alarm may or may not have fired. + // Disarm the alarm and return `false` to indicate that. + // It is the caller's responsibility to handle this ambiguity. + r.dier().modify(|w| w.set_ccie(n + 1, false)); + + alarm.timestamp.set(u64::MAX); + + return false; + } + + // We're confident the alarm will ring in the future. true }) } diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs index 5fe7becaf..81ee1b0f5 100644 --- a/embassy-time/src/driver.rs +++ b/embassy-time/src/driver.rs @@ -108,6 +108,10 @@ pub trait Driver: Send + Sync + 'static { /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set, /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously. + /// There is a rare third possibility that the alarm was barely in the future, and by the time it was enabled, it had slipped into the + /// past. This is can be detected by double-checking that the alarm is still in the future after enabling it; if it isn't, `false` + /// should also be returned to indicate that the callback may have been called already by the alarm, but it is not guaranteed, so the + /// caller should also call the callback, just like in the more common `false` case. (Note: This requires idempotency of the callback.) /// /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. /// From 80c9d04bbd83367340a4f3a1e991df825a0b6029 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 17 Dec 2023 22:09:14 +0100 Subject: [PATCH 044/760] stm32: add some docs. --- embassy-nrf/src/gpio.rs | 25 ++++---- embassy-stm32/src/adc/mod.rs | 6 ++ embassy-stm32/src/adc/resolution.rs | 7 +++ embassy-stm32/src/adc/v4.rs | 11 ++++ embassy-stm32/src/can/fdcan.rs | 15 +---- embassy-stm32/src/crc/v2v3.rs | 13 ++++ embassy-stm32/src/dac/mod.rs | 21 ++++--- embassy-stm32/src/dac/tsel.rs | 2 + embassy-stm32/src/dcmi.rs | 24 +++++++- embassy-stm32/src/dma/bdma.rs | 62 ++++++++++++++++--- embassy-stm32/src/dma/dma.rs | 79 ++++++++++++++++++++++-- embassy-stm32/src/dma/dmamux.rs | 4 ++ embassy-stm32/src/dma/mod.rs | 7 +++ embassy-stm32/src/dma/word.rs | 10 +++ embassy-stm32/src/eth/generic_smi.rs | 1 + embassy-stm32/src/eth/mod.rs | 25 +++++++- embassy-stm32/src/eth/v2/mod.rs | 3 + embassy-stm32/src/exti.rs | 50 ++++++++++++--- embassy-stm32/src/flash/asynch.rs | 2 +- embassy-stm32/src/flash/common.rs | 33 +++++++++- embassy-stm32/src/flash/f0.rs | 4 +- embassy-stm32/src/flash/f3.rs | 4 +- embassy-stm32/src/flash/f7.rs | 4 +- embassy-stm32/src/flash/g.rs | 4 +- embassy-stm32/src/flash/h7.rs | 4 +- embassy-stm32/src/flash/l.rs | 4 +- embassy-stm32/src/flash/mod.rs | 76 +++++++++++++++++------ embassy-stm32/src/flash/other.rs | 4 +- embassy-stm32/src/gpio.rs | 81 ++++++++++++++++++++++--- embassy-stm32/src/i2c/mod.rs | 14 ++++- embassy-stm32/src/qspi/enums.rs | 41 ++++++++++--- embassy-stm32/src/qspi/mod.rs | 4 +- embassy-stm32/src/sai/mod.rs | 4 +- embassy-stm32/src/traits.rs | 6 ++ embassy-stm32/src/usart/ringbuffered.rs | 2 +- examples/stm32f4/src/bin/flash.rs | 6 +- examples/stm32f4/src/bin/flash_async.rs | 6 +- 37 files changed, 544 insertions(+), 124 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 85977a804..a47fb8350 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -50,19 +50,19 @@ impl<'d, T: Pin> Input<'d, T> { Self { pin } } - /// Test if current pin level is high. + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { self.pin.is_high() } - /// Test if current pin level is low. + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.pin.is_low() } - /// Returns current pin level + /// Get the pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.pin.get_level() @@ -158,19 +158,19 @@ impl<'d, T: Pin> Output<'d, T> { self.pin.set_level(level) } - /// Is the output pin set as high? + /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&mut self) -> bool { self.pin.is_set_high() } - /// Is the output pin set as low? + /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&mut self) -> bool { self.pin.is_set_low() } - /// What level output is set to + /// Get the current output level. #[inline] pub fn get_output_level(&mut self) -> Level { self.pin.get_output_level() @@ -275,13 +275,13 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.conf().reset(); } - /// Test if current pin level is high. + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { !self.is_low() } - /// Test if current pin level is low. + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.ref_is_low() @@ -292,7 +292,7 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 } - /// Returns current pin level + /// Get the pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.is_high().into() @@ -319,25 +319,24 @@ impl<'d, T: Pin> Flex<'d, T> { } } - /// Is the output pin set as high? + /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&mut self) -> bool { !self.is_set_low() } - /// Is the output pin set as low? + /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&mut self) -> bool { self.ref_is_set_low() } - /// Is the output pin set as low? #[inline] pub(crate) fn ref_is_set_low(&self) -> bool { self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 } - /// What level output is set to + /// Get the current output level. #[inline] pub fn get_output_level(&mut self) -> Level { self.is_set_high().into() diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index dbe53c807..2e470662d 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,3 +1,4 @@ +//! Analog to Digital (ADC) converter driver. #![macro_use] #[cfg(not(adc_f3_v2))] @@ -24,6 +25,7 @@ pub use sample_time::SampleTime; use crate::peripherals; +/// Analog to Digital driver. pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::PeripheralRef<'d, T>, @@ -75,12 +77,16 @@ pub(crate) mod sealed { } } +/// ADC instance. #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] pub trait Instance: sealed::Instance + crate::Peripheral

{} +/// ADC instance. #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} +/// ADC pin. pub trait AdcPin: sealed::AdcPin {} +/// ADC internal channel. pub trait InternalChannel: sealed::InternalChannel {} foreach_adc!( diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 383980b5a..64c25a776 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -1,3 +1,5 @@ +/// ADC resolution +#[allow(missing_docs)] #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -8,6 +10,8 @@ pub enum Resolution { SixBit, } +/// ADC resolution +#[allow(missing_docs)] #[cfg(adc_v4)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -49,6 +53,9 @@ impl From for crate::pac::adc::vals::Res { } impl Resolution { + /// Get the maximum reading value for this resolution. + /// + /// This is `2**n - 1`. pub fn to_max_count(&self) -> u32 { match self { #[cfg(adc_v4)] diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index d74617cb3..048e73184 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -32,6 +32,7 @@ const TEMP_CHANNEL: u8 = 18; 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::sealed::InternalChannel for VrefInt { @@ -40,6 +41,7 @@ impl super::sealed::InternalChannel for VrefInt { } } +/// Internal temperature channel. pub struct Temperature; impl InternalChannel for Temperature {} impl super::sealed::InternalChannel for Temperature { @@ -48,6 +50,7 @@ impl super::sealed::InternalChannel for Temperature { } } +/// Internal battery voltage channel. pub struct Vbat; impl InternalChannel for Vbat {} impl super::sealed::InternalChannel for Vbat { @@ -125,6 +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 DelayUs) -> Self { embassy_hal_internal::into_ref!(adc); T::enable_and_reset(); @@ -212,6 +216,7 @@ impl<'d, T: Instance> Adc<'d, T> { }); } + /// Enable reading the voltage reference internal channel. pub fn enable_vrefint(&self) -> VrefInt { T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); @@ -220,6 +225,7 @@ impl<'d, T: Instance> Adc<'d, T> { VrefInt {} } + /// Enable reading the temperature internal channel. pub fn enable_temperature(&self) -> Temperature { T::common_regs().ccr().modify(|reg| { reg.set_vsenseen(true); @@ -228,6 +234,7 @@ impl<'d, T: Instance> Adc<'d, T> { Temperature {} } + /// Enable reading the vbat internal channel. pub fn enable_vbat(&self) -> Vbat { T::common_regs().ccr().modify(|reg| { reg.set_vbaten(true); @@ -236,10 +243,12 @@ impl<'d, T: Instance> Adc<'d, T> { 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())); } @@ -263,6 +272,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } + /// Read an ADC pin. pub fn read

(&mut self, pin: &mut P) -> u16 where P: AdcPin, @@ -273,6 +283,7 @@ impl<'d, T: Instance> Adc<'d, T> { 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()) } diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index f77788db3..0cc2559cf 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -1,6 +1,3 @@ -pub use bxcan; -use embassy_hal_internal::PeripheralRef; - use crate::peripherals; pub(crate) mod sealed { @@ -25,27 +22,19 @@ pub(crate) mod sealed { } pub trait Instance { - const REGISTERS: *mut bxcan::RegisterBlock; - fn regs() -> &'static crate::pac::can::Fdcan; fn state() -> &'static State; } } +/// Interruptable FDCAN instance. pub trait InterruptableInstance {} +/// FDCAN instance. pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} -pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); - -unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { - const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS; -} - foreach_peripheral!( (can, $inst:ident) => { impl sealed::Instance for peripherals::$inst { - const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; - fn regs() -> &'static crate::pac::can::Fdcan { &crate::pac::$inst } diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index b36f6018c..0c4ae55ce 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -6,15 +6,19 @@ use crate::peripherals::CRC; use crate::rcc::sealed::RccPeripheral; use crate::Peripheral; +/// CRC driver. pub struct Crc<'d> { _peripheral: PeripheralRef<'d, CRC>, _config: Config, } +/// CRC configuration errlr pub enum ConfigError { + /// The selected polynomial is invalid. InvalidPolynomial, } +/// CRC configuration pub struct Config { reverse_in: InputReverseConfig, reverse_out: bool, @@ -25,14 +29,20 @@ pub struct Config { crc_poly: u32, } +/// Input reverse configuration. pub enum InputReverseConfig { + /// Don't reverse anything None, + /// Reverse bytes Byte, + /// Reverse 16-bit halfwords. Halfword, + /// Reverse 32-bit words. Word, } impl Config { + /// Create a new CRC config. pub fn new( reverse_in: InputReverseConfig, reverse_out: bool, @@ -57,7 +67,9 @@ impl Config { } } +/// Polynomial size #[cfg(crc_v3)] +#[allow(missing_docs)] pub enum PolySize { Width7, Width8, @@ -81,6 +93,7 @@ impl<'d> Crc<'d> { instance } + /// Reset the CRC engine. pub fn reset(&mut self) { PAC_CRC.cr().modify(|w| w.set_reset(true)); } diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 500eac4c1..9c670195d 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -62,11 +62,11 @@ impl Mode { /// /// 12-bit values outside the permitted range are silently truncated. pub enum Value { - // 8 bit value + /// 8 bit value Bit8(u8), - // 12 bit value stored in a u16, left-aligned + /// 12 bit value stored in a u16, left-aligned Bit12Left(u16), - // 12 bit value stored in a u16, right-aligned + /// 12 bit value stored in a u16, right-aligned Bit12Right(u16), } @@ -76,11 +76,11 @@ pub enum Value { /// /// 12-bit values outside the permitted range are silently truncated. pub enum DualValue { - // 8 bit value + /// 8 bit value Bit8(u8, u8), - // 12 bit value stored in a u16, left-aligned + /// 12 bit value stored in a u16, left-aligned Bit12Left(u16, u16), - // 12 bit value stored in a u16, right-aligned + /// 12 bit value stored in a u16, right-aligned Bit12Right(u16, u16), } @@ -88,11 +88,11 @@ pub enum DualValue { #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// Array variant of [`Value`]. pub enum ValueArray<'a> { - // 8 bit values + /// 8 bit values Bit8(&'a [u8]), - // 12 bit value stored in a u16, left-aligned + /// 12 bit value stored in a u16, left-aligned Bit12Left(&'a [u16]), - // 12 bit values stored in a u16, right-aligned + /// 12 bit values stored in a u16, right-aligned Bit12Right(&'a [u16]), } @@ -106,7 +106,9 @@ pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> { dma: PeripheralRef<'d, DMA>, } +/// DAC channel 1 type alias. pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; +/// DAC channel 2 type alias. pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { @@ -492,6 +494,7 @@ pub(crate) mod sealed { } } +/// DAC instance. pub trait Instance: sealed::Instance + RccPeripheral + 'static {} dma_trait!(DacDma1, Instance); dma_trait!(DacDma2, Instance); diff --git a/embassy-stm32/src/dac/tsel.rs b/embassy-stm32/src/dac/tsel.rs index f38dd8fd7..22d8d3dfa 100644 --- a/embassy-stm32/src/dac/tsel.rs +++ b/embassy-stm32/src/dac/tsel.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + /// Trigger selection for STM32F0. #[cfg(stm32f0)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index b12230794..139d8fd1b 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -36,6 +36,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// The level on the VSync pin when the data is not valid on the parallel interface. +#[allow(missing_docs)] #[derive(Clone, Copy, PartialEq)] pub enum VSyncDataInvalidLevel { Low, @@ -43,6 +44,7 @@ pub enum VSyncDataInvalidLevel { } /// The level on the VSync pin when the data is not valid on the parallel interface. +#[allow(missing_docs)] #[derive(Clone, Copy, PartialEq)] pub enum HSyncDataInvalidLevel { Low, @@ -50,14 +52,16 @@ pub enum HSyncDataInvalidLevel { } #[derive(Clone, Copy, PartialEq)] +#[allow(missing_docs)] pub enum PixelClockPolarity { RisingEdge, FallingEdge, } -pub struct State { +struct State { waker: AtomicWaker, } + impl State { const fn new() -> State { State { @@ -68,18 +72,25 @@ impl State { static STATE: State = State::new(); +/// DCMI error. #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { + /// Overrun error: the hardware generated data faster than we could read it. Overrun, + /// Internal peripheral error. PeripheralError, } +/// DCMI configuration. #[non_exhaustive] pub struct Config { + /// VSYNC level. pub vsync_level: VSyncDataInvalidLevel, + /// HSYNC level. pub hsync_level: HSyncDataInvalidLevel, + /// PIXCLK polarity. pub pixclk_polarity: PixelClockPolarity, } @@ -105,6 +116,7 @@ macro_rules! config_pins { }; } +/// DCMI driver. pub struct Dcmi<'d, T: Instance, Dma: FrameDma> { inner: PeripheralRef<'d, T>, dma: PeripheralRef<'d, Dma>, @@ -115,6 +127,7 @@ where T: Instance, Dma: FrameDma, { + /// Create a new DCMI driver with 8 data bits. pub fn new_8bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -139,6 +152,7 @@ where Self::new_inner(peri, dma, config, false, 0b00) } + /// Create a new DCMI driver with 10 data bits. pub fn new_10bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -165,6 +179,7 @@ where Self::new_inner(peri, dma, config, false, 0b01) } + /// Create a new DCMI driver with 12 data bits. pub fn new_12bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -193,6 +208,7 @@ where Self::new_inner(peri, dma, config, false, 0b10) } + /// Create a new DCMI driver with 14 data bits. pub fn new_14bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -223,6 +239,7 @@ where Self::new_inner(peri, dma, config, false, 0b11) } + /// Create a new DCMI driver with 8 data bits, with embedded synchronization. pub fn new_es_8bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -245,6 +262,7 @@ where Self::new_inner(peri, dma, config, true, 0b00) } + /// Create a new DCMI driver with 10 data bits, with embedded synchronization. pub fn new_es_10bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -269,6 +287,7 @@ where Self::new_inner(peri, dma, config, true, 0b01) } + /// Create a new DCMI driver with 12 data bits, with embedded synchronization. pub fn new_es_12bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -295,6 +314,7 @@ where Self::new_inner(peri, dma, config, true, 0b10) } + /// Create a new DCMI driver with 14 data bits, with embedded synchronization. pub fn new_es_14bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -538,7 +558,9 @@ mod sealed { } } +/// DCMI instance. pub trait Instance: sealed::Instance + 'static { + /// Interrupt for this instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index a7422f66b..5102330c0 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -1,4 +1,4 @@ -#![macro_use] +//! Basic Direct Memory Acccess (BDMA) use core::future::Future; use core::pin::Pin; @@ -17,6 +17,7 @@ use crate::interrupt::Priority; use crate::pac; use crate::pac::bdma::{regs, vals}; +/// BDMA transfer options. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -140,13 +141,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index STATE.ch_wakers[index].wake(); } +/// DMA request type alias. #[cfg(any(bdma_v2, dmamux))] pub type Request = u8; +/// DMA request type alias. #[cfg(not(any(bdma_v2, dmamux)))] pub type Request = (); +/// DMA channel. #[cfg(dmamux)] pub trait Channel: sealed::Channel + Peripheral

+ 'static + super::dmamux::MuxChannel {} +/// DMA channel. #[cfg(not(dmamux))] pub trait Channel: sealed::Channel + Peripheral

+ 'static {} @@ -161,12 +166,14 @@ pub(crate) mod sealed { } } +/// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a, C: Channel> { channel: PeripheralRef<'a, C>, } impl<'a, C: Channel> Transfer<'a, C> { + /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( channel: impl Peripheral

+ 'a, request: Request, @@ -177,6 +184,7 @@ impl<'a, C: Channel> Transfer<'a, C> { Self::new_read_raw(channel, request, peri_addr, buf, options) } + /// Create a new read DMA transfer (peripheral to memory), using raw pointers. pub unsafe fn new_read_raw( channel: impl Peripheral

+ 'a, request: Request, @@ -202,6 +210,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ) } + /// Create a new write DMA transfer (memory to peripheral). pub unsafe fn new_write( channel: impl Peripheral

+ 'a, request: Request, @@ -212,6 +221,7 @@ impl<'a, C: Channel> Transfer<'a, C> { Self::new_write_raw(channel, request, buf, peri_addr, options) } + /// Create a new write DMA transfer (memory to peripheral), using raw pointers. pub unsafe fn new_write_raw( channel: impl Peripheral

+ 'a, request: Request, @@ -237,6 +247,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ) } + /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. pub unsafe fn new_write_repeated( channel: impl Peripheral

+ 'a, request: Request, @@ -321,6 +332,9 @@ impl<'a, C: Channel> Transfer<'a, C> { }); } + /// Request the transfer to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); @@ -331,6 +345,10 @@ impl<'a, C: Channel> Transfer<'a, C> { }); } + /// Return whether this transfer is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().ch(self.channel.num()); let en = ch.cr().read().en(); @@ -339,13 +357,15 @@ impl<'a, C: Channel> Transfer<'a, C> { en && (circular || !tcif) } - /// Gets the total remaining transfers for the channel - /// Note: this will be zero for transfers that completed without cancellation. + /// Get the total remaining transfers for the channel. + /// + /// This will be zero for transfers that completed instead of being canceled with [`request_stop`](Self::request_stop). pub fn get_remaining_transfers(&self) -> u16 { let ch = self.channel.regs().ch(self.channel.num()); ch.ndtr().read().ndt() } + /// Blocking wait until the transfer finishes. pub fn blocking_wait(mut self) { while self.is_running() {} self.request_stop(); @@ -411,6 +431,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { } } +/// Ringbuffer for reading data using DMA circular mode. pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, channel: PeripheralRef<'a, C>, @@ -418,7 +439,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { - pub unsafe fn new_read( + /// Create a new ring buffer. + pub unsafe fn new( channel: impl Peripheral

+ 'a, _request: Request, peri_addr: *mut W, @@ -473,11 +495,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { this } + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. pub fn start(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); ch.cr().write_value(self.cr) } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } @@ -509,10 +535,11 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { } /// The capacity of the ringbuffer. - pub const fn cap(&self) -> usize { + pub const fn capacity(&self) -> usize { self.ringbuf.cap() } + /// Set a waker to be woken when at least one byte is received. pub fn set_waker(&mut self, waker: &Waker) { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } @@ -526,6 +553,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { }); } + /// Request DMA to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); @@ -539,6 +569,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { }); } + /// Return whether DMA is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().ch(self.channel.num()); ch.cr().read().en() @@ -555,6 +589,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { } } +/// Ringbuffer for writing data using DMA circular mode. pub struct WritableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, channel: PeripheralRef<'a, C>, @@ -562,7 +597,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { - pub unsafe fn new_write( + /// Create a new ring buffer. + pub unsafe fn new( channel: impl Peripheral

+ 'a, _request: Request, peri_addr: *mut W, @@ -617,11 +653,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { this } + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. pub fn start(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); ch.cr().write_value(self.cr) } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } @@ -640,10 +680,11 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { } /// The capacity of the ringbuffer. - pub const fn cap(&self) -> usize { + pub const fn capacity(&self) -> usize { self.ringbuf.cap() } + /// Set a waker to be woken when at least one byte is sent. pub fn set_waker(&mut self, waker: &Waker) { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } @@ -657,6 +698,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { }); } + /// Request DMA to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); @@ -670,6 +714,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { }); } + /// Return whether DMA is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().ch(self.channel.num()); ch.cr().read().en() diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index cce0407c1..64e492c10 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -16,6 +16,7 @@ use crate::interrupt::Priority; use crate::pac::dma::{regs, vals}; use crate::{interrupt, pac}; +/// DMA transfer options. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -69,6 +70,7 @@ impl From

for vals::Dir { } } +/// DMA transfer burst setting. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Burst { @@ -93,6 +95,7 @@ impl From for vals::Burst { } } +/// DMA flow control setting. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FlowControl { @@ -111,6 +114,7 @@ impl From for vals::Pfctrl { } } +/// DMA FIFO threshold. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FifoThreshold { @@ -208,13 +212,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: STATE.ch_wakers[index].wake(); } +/// DMA request type alias. (also known as DMA channel number in some chips) #[cfg(any(dma_v2, dmamux))] pub type Request = u8; +/// DMA request type alias. (also known as DMA channel number in some chips) #[cfg(not(any(dma_v2, dmamux)))] pub type Request = (); +/// DMA channel. #[cfg(dmamux)] pub trait Channel: sealed::Channel + Peripheral

+ 'static + super::dmamux::MuxChannel {} +/// DMA channel. #[cfg(not(dmamux))] pub trait Channel: sealed::Channel + Peripheral

+ 'static {} @@ -229,12 +237,14 @@ pub(crate) mod sealed { } } +/// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a, C: Channel> { channel: PeripheralRef<'a, C>, } impl<'a, C: Channel> Transfer<'a, C> { + /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( channel: impl Peripheral

+ 'a, request: Request, @@ -245,6 +255,7 @@ impl<'a, C: Channel> Transfer<'a, C> { Self::new_read_raw(channel, request, peri_addr, buf, options) } + /// Create a new read DMA transfer (peripheral to memory), using raw pointers. pub unsafe fn new_read_raw( channel: impl Peripheral

+ 'a, request: Request, @@ -270,6 +281,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ) } + /// Create a new write DMA transfer (memory to peripheral). pub unsafe fn new_write( channel: impl Peripheral

+ 'a, request: Request, @@ -280,6 +292,7 @@ impl<'a, C: Channel> Transfer<'a, C> { Self::new_write_raw(channel, request, buf, peri_addr, options) } + /// Create a new write DMA transfer (memory to peripheral), using raw pointers. pub unsafe fn new_write_raw( channel: impl Peripheral

+ 'a, request: Request, @@ -305,6 +318,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ) } + /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. pub unsafe fn new_write_repeated( channel: impl Peripheral

+ 'a, request: Request, @@ -407,6 +421,9 @@ impl<'a, C: Channel> Transfer<'a, C> { }); } + /// Request the transfer to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().st(self.channel.num()); @@ -417,6 +434,10 @@ impl<'a, C: Channel> Transfer<'a, C> { }); } + /// Return whether this transfer is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().st(self.channel.num()); ch.cr().read().en() @@ -429,6 +450,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ch.ndtr().read().ndt() } + /// Blocking wait until the transfer finishes. pub fn blocking_wait(mut self) { while self.is_running() {} @@ -465,12 +487,14 @@ impl<'a, C: Channel> Future for Transfer<'a, C> { // ================================== +/// Double-buffered DMA transfer. pub struct DoubleBuffered<'a, C: Channel, W: Word> { channel: PeripheralRef<'a, C>, _phantom: PhantomData, } impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { + /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( channel: impl Peripheral

+ 'a, _request: Request, @@ -554,25 +578,36 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { }); } + /// Set the first buffer address. + /// + /// You may call this while DMA is transferring the other buffer. pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { let ch = self.channel.regs().st(self.channel.num()); ch.m0ar().write_value(buffer as _); } + /// Set the second buffer address. + /// + /// You may call this while DMA is transferring the other buffer. pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { let ch = self.channel.regs().st(self.channel.num()); ch.m1ar().write_value(buffer as _); } + /// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now) pub fn is_buffer0_accessible(&mut self) -> bool { let ch = self.channel.regs().st(self.channel.num()); ch.cr().read().ct() == vals::Ct::MEMORY1 } + /// Set a waker to be woken when one of the buffers is being transferred. pub fn set_waker(&mut self, waker: &Waker) { STATE.ch_wakers[self.channel.index()].register(waker); } + /// Request the transfer to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().st(self.channel.num()); @@ -583,6 +618,10 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { }); } + /// Return whether this transfer is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().st(self.channel.num()); ch.cr().read().en() @@ -629,6 +668,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { } } +/// Ringbuffer for receiving data using DMA circular mode. pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, channel: PeripheralRef<'a, C>, @@ -636,7 +676,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { - pub unsafe fn new_read( + /// Create a new ring buffer. + pub unsafe fn new( channel: impl Peripheral

+ 'a, _request: Request, peri_addr: *mut W, @@ -706,11 +747,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { this } + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. pub fn start(&mut self) { let ch = self.channel.regs().st(self.channel.num()); ch.cr().write_value(self.cr); } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } @@ -741,11 +786,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { .await } - // The capacity of the ringbuffer - pub const fn cap(&self) -> usize { + /// The capacity of the ringbuffer + pub const fn capacity(&self) -> usize { self.ringbuf.cap() } + /// Set a waker to be woken when at least one byte is received. pub fn set_waker(&mut self, waker: &Waker) { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } @@ -763,6 +809,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { }); } + /// Request DMA to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().st(self.channel.num()); @@ -774,6 +823,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { }); } + /// Return whether DMA is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().st(self.channel.num()); ch.cr().read().en() @@ -790,6 +843,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { } } +/// Ringbuffer for writing data using DMA circular mode. pub struct WritableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, channel: PeripheralRef<'a, C>, @@ -797,7 +851,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { - pub unsafe fn new_write( + /// Create a new ring buffer. + pub unsafe fn new( channel: impl Peripheral

+ 'a, _request: Request, peri_addr: *mut W, @@ -867,11 +922,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { this } + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. pub fn start(&mut self) { let ch = self.channel.regs().st(self.channel.num()); ch.cr().write_value(self.cr); } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } @@ -889,11 +948,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { .await } - // The capacity of the ringbuffer - pub const fn cap(&self) -> usize { + /// The capacity of the ringbuffer + pub const fn capacity(&self) -> usize { self.ringbuf.cap() } + /// Set a waker to be woken when at least one byte is received. pub fn set_waker(&mut self, waker: &Waker) { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } @@ -911,6 +971,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { }); } + /// Request DMA to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().st(self.channel.num()); @@ -922,6 +985,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { }); } + /// Return whether DMA is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().st(self.channel.num()); ch.cr().read().en() diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 20601dc86..9cd494724 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -22,11 +22,15 @@ pub(crate) mod dmamux_sealed { } } +/// DMAMUX1 instance. pub struct DMAMUX1; +/// DMAMUX2 instance. #[cfg(stm32h7)] pub struct DMAMUX2; +/// DMAMUX channel trait. pub trait MuxChannel: dmamux_sealed::MuxChannel { + /// DMAMUX instance this channel is on. type Mux; } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 29fced8fc..fb40a4b5e 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -39,6 +39,13 @@ enum Dir { PeripheralToMemory, } +/// "No DMA" placeholder. +/// +/// You may pass this in place of a real DMA channel when creating a driver +/// to indicate it should not use DMA. +/// +/// This often causes async functionality to not be available on the instance, +/// leaving only blocking functionality. pub struct NoDma; impl_peripheral!(NoDma); diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs index aef6e9700..a72c4b7d9 100644 --- a/embassy-stm32/src/dma/word.rs +++ b/embassy-stm32/src/dma/word.rs @@ -1,3 +1,6 @@ +//! DMA word sizes. + +#[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum WordSize { @@ -7,6 +10,7 @@ pub enum WordSize { } impl WordSize { + /// Amount of bytes of this word size. pub fn bytes(&self) -> usize { match self { Self::OneByte => 1, @@ -20,8 +24,13 @@ mod sealed { pub trait Word {} } +/// DMA word trait. +/// +/// This is implemented for u8, u16, u32, etc. pub trait Word: sealed::Word + Default + Copy + 'static { + /// Word size fn size() -> WordSize; + /// Amount of bits of this word size. fn bits() -> usize; } @@ -40,6 +49,7 @@ macro_rules! impl_word { ($T:ident, $uX:ident, $bits:literal, $size:ident) => { #[repr(transparent)] #[derive(Copy, Clone, Default)] + #[doc = concat!(stringify!($T), " word size")] pub struct $T(pub $uX); impl_word!(_, $T, $bits, $size); }; diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs index 1e1094a1c..9c26e90f1 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_smi.rs @@ -102,6 +102,7 @@ unsafe impl PHY for GenericSMI { /// Public functions for the PHY impl GenericSMI { + /// Set the SMI polling interval. #[cfg(feature = "time")] pub fn set_poll_interval(&mut self, poll_interval: Duration) { self.poll_interval = poll_interval diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 556aadd73..dbf91eedc 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -22,6 +22,14 @@ const RX_BUFFER_SIZE: usize = 1536; #[derive(Copy, Clone)] pub(crate) struct Packet([u8; N]); +/// Ethernet packet queue. +/// +/// This struct owns the memory used for reading and writing packets. +/// +/// `TX` is the number of packets in the transmit queue, `RX` in the receive +/// queue. A bigger queue allows the hardware to receive more packets while the +/// CPU is busy doing other things, which may increase performance (especially for RX) +/// at the cost of more RAM usage. pub struct PacketQueue { tx_desc: [TDes; TX], rx_desc: [RDes; RX], @@ -30,6 +38,7 @@ pub struct PacketQueue { } impl PacketQueue { + /// Create a new packet queue. pub const fn new() -> Self { const NEW_TDES: TDes = TDes::new(); const NEW_RDES: RDes = RDes::new(); @@ -41,7 +50,18 @@ impl PacketQueue { } } - // Allow to initialize a Self without requiring it to go on the stack + /// Initialize a packet queue in-place. + /// + /// This can be helpful to avoid accidentally stack-allocating the packet queue in the stack. The + /// Rust compiler can sometimes be a bit dumb when working with large owned values: if you call `new()` + /// and then store the returned PacketQueue in its final place (like a `static`), the compiler might + /// place it temporarily on the stack then move it. Since this struct is quite big, it may result + /// in a stack overflow. + /// + /// With this function, you can create an uninitialized `static` with type `MaybeUninit>` + /// and initialize it in-place, guaranteeing no stack usage. + /// + /// After calling this function, calling `assume_init` on the MaybeUninit is guaranteed safe. pub fn init(this: &mut MaybeUninit) { unsafe { this.as_mut_ptr().write_bytes(0u8, 1); @@ -93,6 +113,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> } } +/// `embassy-net` RX token. pub struct RxToken<'a, 'd> { rx: &'a mut RDesRing<'d>, } @@ -110,6 +131,7 @@ impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> { } } +/// `embassy-net` TX token. pub struct TxToken<'a, 'd> { tx: &'a mut TDesRing<'d>, } @@ -159,6 +181,7 @@ pub(crate) mod sealed { } } +/// Ethernet instance. pub trait Instance: sealed::Instance + Send + 'static {} impl sealed::Instance for crate::peripherals::ETH { diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index c77155fea..59745cba0 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -34,6 +34,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } } +/// Ethernet driver. pub struct Ethernet<'d, T: Instance, P: PHY> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, @@ -56,6 +57,7 @@ macro_rules! config_pins { } impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { + /// Create a new Ethernet driver. pub fn new( queue: &'d mut PacketQueue, peri: impl Peripheral

+ 'd, @@ -237,6 +239,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { } } +/// Ethernet SMI driver. pub struct EthernetStationManagement { peri: PhantomData, clock_range: u8, diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index e77ac30fb..371be913e 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -39,7 +39,7 @@ fn exticr_regs() -> pac::afio::Afio { pac::AFIO } -pub unsafe fn on_irq() { +unsafe fn on_irq() { #[cfg(feature = "low-power")] crate::low_power::on_wakeup_irq(); @@ -85,7 +85,13 @@ impl Iterator for BitIter { } } -/// EXTI input driver +/// EXTI input driver. +/// +/// This driver augments a GPIO `Input` with EXTI functionality. EXTI is not +/// built into `Input` itself because it needs to take ownership of the corresponding +/// EXTI channel, which is a limited resource. +/// +/// Pins PA5, PB5, PC5... all use EXTI channel 5, so you can't use EXTI on, say, PA5 and PC5 at the same time. pub struct ExtiInput<'d, T: GpioPin> { pin: Input<'d, T>, } @@ -93,23 +99,30 @@ pub struct ExtiInput<'d, T: GpioPin> { impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} impl<'d, T: GpioPin> ExtiInput<'d, T> { + /// Create an EXTI input. pub fn new(pin: Input<'d, T>, _ch: impl Peripheral

+ 'd) -> Self { Self { pin } } + /// Get whether the pin is high. pub fn is_high(&mut self) -> bool { self.pin.is_high() } + /// Get whether the pin is low. pub fn is_low(&mut self) -> bool { self.pin.is_low() } + /// Get the pin level. pub fn get_level(&mut self) -> Level { self.pin.get_level() } - pub async fn wait_for_high<'a>(&'a mut self) { + /// Asynchronously wait until the pin is high. + /// + /// This returns immediately if the pin is already high. + pub async fn wait_for_high(&mut self) { let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); if self.is_high() { return; @@ -117,7 +130,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { fut.await } - pub async fn wait_for_low<'a>(&'a mut self) { + /// Asynchronously wait until the pin is low. + /// + /// This returns immediately if the pin is already low. + pub async fn wait_for_low(&mut self) { let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); if self.is_low() { return; @@ -125,15 +141,22 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { fut.await } - pub async fn wait_for_rising_edge<'a>(&'a mut self) { + /// Asynchronously wait until the pin sees a rising edge. + /// + /// If the pin is already high, it will wait for it to go low then back high. + pub async fn wait_for_rising_edge(&mut self) { ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await } - pub async fn wait_for_falling_edge<'a>(&'a mut self) { + /// Asynchronously wait until the pin sees a falling edge. + /// + /// If the pin is already low, it will wait for it to go high then back low. + pub async fn wait_for_falling_edge(&mut self) { ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await } - pub async fn wait_for_any_edge<'a>(&'a mut self) { + /// Asynchronously wait until the pin sees any edge (either rising or falling). + pub async fn wait_for_any_edge(&mut self) { ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await } } @@ -284,6 +307,7 @@ macro_rules! foreach_exti_irq { macro_rules! impl_irq { ($e:ident) => { + #[allow(non_snake_case)] #[cfg(feature = "rt")] #[interrupt] unsafe fn $e() { @@ -298,8 +322,16 @@ pub(crate) mod sealed { pub trait Channel {} } +/// EXTI channel trait. pub trait Channel: sealed::Channel + Sized { + /// Get the EXTI channel number. fn number(&self) -> usize; + + /// Type-erase (degrade) this channel into an `AnyChannel`. + /// + /// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of channels, or avoiding generics. fn degrade(self) -> AnyChannel { AnyChannel { number: self.number() as u8, @@ -307,9 +339,13 @@ pub trait Channel: sealed::Channel + Sized { } } +/// Type-erased (degraded) EXTI channel. +/// +/// This represents ownership over any EXTI channel, known at runtime. pub struct AnyChannel { number: u8, } + impl_peripheral!(AnyChannel); impl sealed::Channel for AnyChannel {} impl Channel for AnyChannel { diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index eae40c7ec..e3c6d4d67 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -59,7 +59,7 @@ impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_, Async> { const READ_SIZE: usize = super::READ_SIZE; async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) + self.blocking_read(offset, bytes) } fn capacity(&self) -> usize { diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 8acad1c7c..f8561edb3 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -12,12 +12,14 @@ use super::{ use crate::peripherals::FLASH; use crate::Peripheral; +/// Internal flash memory driver. pub struct Flash<'d, MODE = Async> { pub(crate) inner: PeripheralRef<'d, FLASH>, pub(crate) _mode: PhantomData, } impl<'d> Flash<'d, Blocking> { + /// Create a new flash driver, usable in blocking mode. pub fn new_blocking(p: impl Peripheral

+ 'd) -> Self { into_ref!(p); @@ -29,15 +31,26 @@ impl<'d> Flash<'d, Blocking> { } impl<'d, MODE> Flash<'d, MODE> { + /// Split this flash driver into one instance per flash memory region. + /// + /// See module-level documentation for details on how memory regions work. pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { assert!(family::is_default_layout()); FlashLayout::new(self.inner) } - pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + /// Blocking read. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to read address `0x0800_1234` you have to use offset `0x1234`. + pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } + /// Blocking write. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to write address `0x0800_1234` you have to use offset `0x1234`. pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { unsafe { blocking_write( @@ -50,6 +63,10 @@ impl<'d, MODE> Flash<'d, MODE> { } } + /// Blocking erase. + /// + /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address. + /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`. pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) } } @@ -206,7 +223,7 @@ impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_, MODE> { const READ_SIZE: usize = READ_SIZE; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) + self.blocking_read(offset, bytes) } fn capacity(&self) -> usize { @@ -230,16 +247,28 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_, MODE> { foreach_flash_region! { ($type_name:ident, $write_size:literal, $erase_size:literal) => { impl crate::_generated::flash_regions::$type_name<'_, MODE> { + /// Blocking read. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to read address `0x0800_1234` you have to use offset `0x1234`. pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { blocking_read(self.0.base, self.0.size, offset, bytes) } } impl crate::_generated::flash_regions::$type_name<'_, Blocking> { + /// Blocking write. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to write address `0x0800_1234` you have to use offset `0x1234`. pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } } + /// Blocking erase. + /// + /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address. + /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`. pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) } } diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index 80d2a8166..c0a8d7022 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 27d5281a7..817ccef4d 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 017393e80..6b3e66ac6 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index 08145e9c4..d97b4a932 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -8,11 +8,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 555f8d155..65d163d29 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -6,7 +6,7 @@ use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } @@ -14,7 +14,7 @@ const fn is_dual_bank() -> bool { FLASH_REGIONS.len() >= 2 } -pub fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index e0159a3f6..0b332dc61 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -5,11 +5,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 3e8f2830b..6b6b4d41c 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -14,50 +14,84 @@ pub use crate::_generated::flash_regions::*; pub use crate::_generated::MAX_ERASE_SIZE; pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +/// Get whether the default flash layout is being used. +/// +/// In some chips, dual-bank is not default. This will then return `false` +/// when dual-bank is enabled. +pub fn is_default_layout() -> bool { + family::is_default_layout() +} + +/// Get all flash regions. +pub fn get_flash_regions() -> &'static [&'static FlashRegion] { + family::get_flash_regions() +} + +/// Read size (always 1) pub const READ_SIZE: usize = 1; -pub struct Blocking; -pub struct Async; +/// Blocking flash mode typestate. +pub enum Blocking {} +/// Async flash mode typestate. +pub enum Async {} +/// Flash memory region #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FlashRegion { + /// Bank number. pub bank: FlashBank, + /// Absolute base address. pub base: u32, + /// Size in bytes. pub size: u32, + /// Erase size (sector size). pub erase_size: u32, + /// Minimum write size. pub write_size: u32, + /// Erase value (usually `0xFF`, but is `0x00` in some chips) pub erase_value: u8, pub(crate) _ensure_internal: (), } -#[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct FlashSector { - pub bank: FlashBank, - pub index_in_bank: u8, - pub start: u32, - pub size: u32, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum FlashBank { - Bank1 = 0, - Bank2 = 1, - Otp, -} - impl FlashRegion { + /// Absolute end address. pub const fn end(&self) -> u32 { self.base + self.size } + /// Number of sectors in the region. pub const fn sectors(&self) -> u8 { (self.size / self.erase_size) as u8 } } +/// Flash sector. +#[derive(Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct FlashSector { + /// Bank number. + pub bank: FlashBank, + /// Sector number within the bank. + pub index_in_bank: u8, + /// Absolute start address. + pub start: u32, + /// Size in bytes. + pub size: u32, +} + +/// Flash bank. +#[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum FlashBank { + /// Bank 1 + 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")] #[cfg_attr(flash_f0, path = "f0.rs")] #[cfg_attr(flash_f3, path = "f3.rs")] @@ -78,6 +112,10 @@ mod family; #[allow(unused_imports)] pub use family::*; +/// Flash error +/// +/// See STM32 Reference Manual for your chip for details. +#[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index a7e8d1d57..20f84a72f 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -2,11 +2,11 @@ use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index bb3cf2bc4..083b3237c 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -29,6 +29,11 @@ impl<'d, T: Pin> Flex<'d, T> { Self { pin } } + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] pub fn degrade(self) -> Flex<'d, AnyPin> { // Safety: We are about to drop the other copy of this pin, so @@ -141,11 +146,13 @@ impl<'d, T: Pin> Flex<'d, T> { }); } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { !self.ref_is_low() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.ref_is_low() @@ -157,17 +164,19 @@ impl<'d, T: Pin> Flex<'d, T> { state == vals::Idr::LOW } + /// Get the current pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.is_high().into() } + /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&mut self) -> bool { !self.ref_is_set_low() } - /// Is the output pin set as low? + /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&mut self) -> bool { self.ref_is_set_low() @@ -179,12 +188,13 @@ impl<'d, T: Pin> Flex<'d, T> { state == vals::Odr::LOW } - /// What level output is set to + /// Get the current output level. #[inline] pub fn get_output_level(&mut self) -> Level { self.is_set_high().into() } + /// Set the output as high. #[inline] pub fn set_high(&mut self) { self.pin.set_high(); @@ -196,6 +206,7 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.set_low(); } + /// Set the output level. #[inline] pub fn set_level(&mut self, level: Level) { match level { @@ -204,7 +215,7 @@ impl<'d, T: Pin> Flex<'d, T> { } } - /// Toggle pin output + /// Toggle the output level. #[inline] pub fn toggle(&mut self) { if self.is_set_low() { @@ -242,8 +253,11 @@ impl<'d, T: Pin> Drop for Flex<'d, T> { #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Pull { + /// No pull None, + /// Pull up Up, + /// Pull down Down, } @@ -261,6 +275,9 @@ impl From for vals::Pupdr { } /// Speed settings +/// +/// These vary dpeending on the chip, ceck the reference manual or datasheet for details. +#[allow(missing_docs)] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Speed { @@ -305,6 +322,7 @@ pub struct Input<'d, T: Pin> { } impl<'d, T: Pin> Input<'d, T> { + /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { let mut pin = Flex::new(pin); @@ -312,6 +330,11 @@ impl<'d, T: Pin> Input<'d, T> { Self { pin } } + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] pub fn degrade(self) -> Input<'d, AnyPin> { Input { @@ -319,16 +342,19 @@ impl<'d, T: Pin> Input<'d, T> { } } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { self.pin.is_high() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.pin.is_low() } + /// Get the current pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.pin.get_level() @@ -339,7 +365,9 @@ impl<'d, T: Pin> Input<'d, T> { #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Level { + /// Low Low, + /// High High, } @@ -371,6 +399,7 @@ pub struct Output<'d, T: Pin> { } impl<'d, T: Pin> Output<'d, T> { + /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration. #[inline] pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed) -> Self { let mut pin = Flex::new(pin); @@ -382,6 +411,11 @@ impl<'d, T: Pin> Output<'d, T> { Self { pin } } + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] pub fn degrade(self) -> Output<'d, AnyPin> { Output { @@ -442,6 +476,7 @@ pub struct OutputOpenDrain<'d, T: Pin> { } impl<'d, T: Pin> OutputOpenDrain<'d, T> { + /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration. #[inline] pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { let mut pin = Flex::new(pin); @@ -455,6 +490,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { Self { pin } } + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] pub fn degrade(self) -> Output<'d, AnyPin> { Output { @@ -462,17 +502,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { } } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { !self.pin.is_low() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.pin.is_low() } - /// Returns current pin level + /// Get the current pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.pin.get_level() @@ -496,19 +538,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { self.pin.set_level(level); } - /// Is the output pin set as high? + /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&mut self) -> bool { self.pin.is_set_high() } - /// Is the output pin set as low? + /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&mut self) -> bool { self.pin.is_set_low() } - /// What level output is set to + /// Get the current output level. #[inline] pub fn get_output_level(&mut self) -> Level { self.pin.get_output_level() @@ -521,8 +563,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { } } +/// GPIO output type pub enum OutputType { + /// Drive the pin both high or low. PushPull, + /// Drive the pin low, or don't drive it at all if the output level is high. OpenDrain, } @@ -535,6 +580,7 @@ impl From for sealed::AFType { } } +#[allow(missing_docs)] pub(crate) mod sealed { use super::*; @@ -542,8 +588,11 @@ pub(crate) mod sealed { #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AFType { + /// Input Input, + /// Output, drive the pin both high or low. OutputPushPull, + /// Output, drive the pin low, or don't drive it at all if the output level is high. OutputOpenDrain, } @@ -686,7 +735,11 @@ pub(crate) mod sealed { } } +/// GPIO pin trait. pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'static { + /// EXTI channel assigned to this pin. + /// + /// For example, PC4 uses EXTI4. #[cfg(feature = "exti")] type ExtiChannel: crate::exti::Channel; @@ -702,7 +755,11 @@ pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'stat self._port() } - /// Convert from concrete pin type PX_XX to type erased `AnyPin`. + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] fn degrade(self) -> AnyPin { AnyPin { @@ -711,12 +768,15 @@ pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'stat } } -// Type-erased GPIO pin +/// Type-erased GPIO pin pub struct AnyPin { pin_port: u8, } impl AnyPin { + /// Unsafely create an `AnyPin` from a pin+port number. + /// + /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... #[inline] pub unsafe fn steal(pin_port: u8) -> Self { Self { pin_port } @@ -727,6 +787,8 @@ impl AnyPin { self.pin_port / 16 } + /// Get the GPIO register block for this pin. + #[cfg(feature = "unstable-pac")] #[inline] pub fn block(&self) -> gpio::Gpio { pac::GPIO(self._port() as _) @@ -1072,6 +1134,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { } } +/// Low-level GPIO manipulation. #[cfg(feature = "unstable-pac")] pub mod low_level { pub use super::sealed::*; diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index d2a50cf7e..a8dc8e0e5 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -13,15 +13,23 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::peripherals; +/// I2C error. #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Bus error Bus, + /// Arbitration lost Arbitration, + /// ACK not received (either to the address or to a data byte) Nack, + /// Timeout Timeout, + /// CRC error Crc, + /// Overrun error Overrun, + /// Zero-length transfers are not allowed. ZeroLengthTransfer, } @@ -47,8 +55,11 @@ pub(crate) mod sealed { } } +/// I2C peripheral instance pub trait Instance: sealed::Instance + 'static { + /// Event interrupt for this instance type EventInterrupt: interrupt::typelevel::Interrupt; + /// Error interrupt for this instance type ErrorInterrupt: interrupt::typelevel::Interrupt; } @@ -57,7 +68,7 @@ pin_trait!(SdaPin, Instance); dma_trait!(RxDma, Instance); dma_trait!(TxDma, Instance); -/// Interrupt handler. +/// Event interrupt handler. pub struct EventInterruptHandler { _phantom: PhantomData, } @@ -68,6 +79,7 @@ impl interrupt::typelevel::Handler for EventInte } } +/// Error interrupt handler. pub struct ErrorInterruptHandler { _phantom: PhantomData, } diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs index 0412d991a..e9e7fd482 100644 --- a/embassy-stm32/src/qspi/enums.rs +++ b/embassy-stm32/src/qspi/enums.rs @@ -18,12 +18,17 @@ impl Into for QspiMode { } } +/// QSPI lane width #[allow(dead_code)] #[derive(Copy, Clone)] pub enum QspiWidth { + /// None NONE, + /// Single lane SING, + /// Dual lanes DUAL, + /// Quad lanes QUAD, } @@ -38,10 +43,13 @@ impl Into for QspiWidth { } } +/// Flash bank selection #[allow(dead_code)] #[derive(Copy, Clone)] pub enum FlashSelection { + /// Bank 1 Flash1, + /// Bank 2 Flash2, } @@ -54,6 +62,8 @@ impl Into for FlashSelection { } } +/// QSPI memory size. +#[allow(missing_docs)] #[derive(Copy, Clone)] pub enum MemorySize { _1KiB, @@ -113,11 +123,16 @@ impl Into for MemorySize { } } +/// QSPI Address size #[derive(Copy, Clone)] pub enum AddressSize { + /// 8-bit address _8Bit, + /// 16-bit address _16Bit, + /// 24-bit address _24bit, + /// 32-bit address _32bit, } @@ -132,8 +147,10 @@ impl Into for AddressSize { } } +/// Time the Chip Select line stays high. +#[allow(missing_docs)] #[derive(Copy, Clone)] -pub enum ChipSelectHightTime { +pub enum ChipSelectHighTime { _1Cycle, _2Cycle, _3Cycle, @@ -144,21 +161,23 @@ pub enum ChipSelectHightTime { _8Cycle, } -impl Into for ChipSelectHightTime { +impl Into for ChipSelectHighTime { fn into(self) -> u8 { match self { - ChipSelectHightTime::_1Cycle => 0, - ChipSelectHightTime::_2Cycle => 1, - ChipSelectHightTime::_3Cycle => 2, - ChipSelectHightTime::_4Cycle => 3, - ChipSelectHightTime::_5Cycle => 4, - ChipSelectHightTime::_6Cycle => 5, - ChipSelectHightTime::_7Cycle => 6, - ChipSelectHightTime::_8Cycle => 7, + ChipSelectHighTime::_1Cycle => 0, + ChipSelectHighTime::_2Cycle => 1, + ChipSelectHighTime::_3Cycle => 2, + ChipSelectHighTime::_4Cycle => 3, + ChipSelectHighTime::_5Cycle => 4, + ChipSelectHighTime::_6Cycle => 5, + ChipSelectHighTime::_7Cycle => 6, + ChipSelectHighTime::_8Cycle => 7, } } } +/// FIFO threshold. +#[allow(missing_docs)] #[derive(Copy, Clone)] pub enum FIFOThresholdLevel { _1Bytes, @@ -234,6 +253,8 @@ impl Into for FIFOThresholdLevel { } } +/// Dummy cycle count +#[allow(missing_docs)] #[derive(Copy, Clone)] pub enum DummyCycles { _0, diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 1153455c7..bac91f300 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -54,7 +54,7 @@ pub struct Config { /// Number of bytes to trigger FIFO threshold flag. pub fifo_threshold: FIFOThresholdLevel, /// Minimum number of cycles that chip select must be high between issued commands - pub cs_high_time: ChipSelectHightTime, + pub cs_high_time: ChipSelectHighTime, } impl Default for Config { @@ -64,7 +64,7 @@ impl Default for Config { address_size: AddressSize::_24bit, prescaler: 128, fifo_threshold: FIFOThresholdLevel::_17Bytes, - cs_high_time: ChipSelectHightTime::_5Cycle, + cs_high_time: ChipSelectHighTime::_5Cycle, } } } diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index a16d38af1..3d7f65996 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -583,10 +583,10 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( }; match tx_rx { TxRx::Transmitter => RingBuffer::Writable(unsafe { - WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts) + WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts) }), TxRx::Receiver => RingBuffer::Readable(unsafe { - ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts) + ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts) }), } } diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs index ffce7bd42..b4166e71a 100644 --- a/embassy-stm32/src/traits.rs +++ b/embassy-stm32/src/traits.rs @@ -2,7 +2,9 @@ macro_rules! pin_trait { ($signal:ident, $instance:path) => { + #[doc = concat!(stringify!($signal), " pin trait")] pub trait $signal: crate::gpio::Pin { + #[doc = concat!("Get the AF number needed to use this pin as", stringify!($signal))] fn af_num(&self) -> u8; } }; @@ -22,7 +24,11 @@ macro_rules! pin_trait_impl { macro_rules! dma_trait { ($signal:ident, $instance:path) => { + #[doc = concat!(stringify!($signal), " DMA request trait")] pub trait $signal: crate::dma::Channel { + #[doc = concat!("Get the DMA request number needed to use this channel as", stringify!($signal))] + /// Note: in some chips, ST calls this the "channel", and calls channels "streams". + /// `embassy-stm32` always uses the "channel" and "request number" names. fn request(&self) -> crate::dma::Request; } }; diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index b8d17e4e4..f8ada3926 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -39,7 +39,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; let _peri = unsafe { self._peri.clone_unchecked() }; - let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; + let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; // Don't disable the clock mem::forget(self); diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs index 93c54e943..56a35ddee 100644 --- a/examples/stm32f4/src/bin/flash.rs +++ b/examples/stm32f4/src/bin/flash.rs @@ -31,7 +31,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); @@ -39,7 +39,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); @@ -53,7 +53,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!( &buf[..], diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs index f0a65a725..1624d842e 100644 --- a/examples/stm32f4/src/bin/flash_async.rs +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -48,7 +48,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); @@ -56,7 +56,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); @@ -73,7 +73,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!( &buf[..], From 2a542bc1437dcaa62914b82ae496b1e19e8fee91 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 18 Dec 2023 13:58:12 +0100 Subject: [PATCH 045/760] feat: support multiwrite flash traits if configured --- embassy-nrf/Cargo.toml | 5 +++++ embassy-nrf/src/qspi.rs | 3 +++ 2 files changed, 8 insertions(+) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 6d7440519..970f62b0c 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -64,6 +64,11 @@ nfc-pins-as-gpio = [] # nrf52820, nrf52833, nrf52840: P0_18 reset-pin-as-gpio = [] +# Implements the MultiwriteNorFlash trait for QSPI. Should only be enabled if your external +# flash supports the semantics described in +# https://docs.rs/embedded-storage/0.3.1/embedded_storage/nor_flash/trait.MultiwriteNorFlash.html +qspi-multiwrite-flash = [] + # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 5e1a4e842..f35b83628 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -605,6 +605,9 @@ impl<'d, T: Instance> NorFlash for Qspi<'d, T> { } } +#[cfg(feature = "qspi-multiwrite-flash")] +impl<'d, T: Instance> embedded_storage::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {} + mod _eh1 { use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; From 7044e53af45e472d52d6e523bddf5632f0375487 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Dec 2023 18:24:55 +0100 Subject: [PATCH 046/760] stm32/i2c: remove _timeout public API, share more code between v1/v2. --- embassy-stm32/src/i2c/mod.rs | 164 +++++++++++- embassy-stm32/src/i2c/v1.rs | 145 +++-------- embassy-stm32/src/i2c/v2.rs | 470 +++++++---------------------------- 3 files changed, 268 insertions(+), 511 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index a8dc8e0e5..0af291e9c 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -1,17 +1,23 @@ #![macro_use] -use core::marker::PhantomData; - -use crate::dma::NoDma; -use crate::interrupt; - #[cfg_attr(i2c_v1, path = "v1.rs")] #[cfg_attr(i2c_v2, path = "v2.rs")] mod _version; -pub use _version::*; -use embassy_sync::waitqueue::AtomicWaker; -use crate::peripherals; +use core::future::Future; +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +#[cfg(feature = "time")] +use embassy_time::{Duration, Instant}; + +use crate::dma::NoDma; +use crate::gpio::sealed::AFType; +use crate::gpio::Pull; +use crate::interrupt::typelevel::Interrupt; +use crate::time::Hertz; +use crate::{interrupt, peripherals}; /// I2C error. #[derive(Debug, PartialEq, Eq)] @@ -33,6 +39,148 @@ pub enum Error { ZeroLengthTransfer, } +/// I2C config +#[non_exhaustive] +#[derive(Copy, Clone)] +pub struct Config { + /// Enable internal pullup on SDA. + /// + /// Using external pullup resistors is recommended for I2C. If you do + /// have external pullups you should not enable this. + pub sda_pullup: bool, + /// Enable internal pullup on SCL. + /// + /// Using external pullup resistors is recommended for I2C. If you do + /// have external pullups you should not enable this. + pub scl_pullup: bool, + /// Timeout. + #[cfg(feature = "time")] + pub timeout: embassy_time::Duration, +} + +impl Default for Config { + fn default() -> Self { + Self { + sda_pullup: false, + scl_pullup: false, + #[cfg(feature = "time")] + timeout: embassy_time::Duration::from_millis(1000), + } + } +} + +/// I2C driver. +pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { + _peri: PeripheralRef<'d, T>, + #[allow(dead_code)] + tx_dma: PeripheralRef<'d, TXDMA>, + #[allow(dead_code)] + rx_dma: PeripheralRef<'d, RXDMA>, + #[cfg(feature = "time")] + timeout: Duration, +} + +impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { + /// Create a new I2C driver. + pub fn new( + peri: impl Peripheral

+ 'd, + scl: impl Peripheral

> + 'd, + sda: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + 'd, + tx_dma: impl Peripheral

+ 'd, + rx_dma: impl Peripheral

+ 'd, + freq: Hertz, + config: Config, + ) -> Self { + into_ref!(peri, scl, sda, tx_dma, rx_dma); + + T::enable_and_reset(); + + scl.set_as_af_pull( + scl.af_num(), + AFType::OutputOpenDrain, + match config.scl_pullup { + true => Pull::Up, + false => Pull::None, + }, + ); + sda.set_as_af_pull( + sda.af_num(), + AFType::OutputOpenDrain, + match config.sda_pullup { + true => Pull::Up, + false => Pull::None, + }, + ); + + unsafe { T::EventInterrupt::enable() }; + unsafe { T::ErrorInterrupt::enable() }; + + let mut this = Self { + _peri: peri, + tx_dma, + rx_dma, + #[cfg(feature = "time")] + timeout: config.timeout, + }; + + this.init(freq, config); + + this + } + + fn timeout(&self) -> Timeout { + Timeout { + #[cfg(feature = "time")] + deadline: Instant::now() + self.timeout, + } + } +} + +#[derive(Copy, Clone)] +struct Timeout { + #[cfg(feature = "time")] + deadline: Instant, +} + +#[allow(dead_code)] +impl Timeout { + #[cfg(not(feature = "time"))] + #[inline] + fn check(self) -> Result<(), Error> { + Ok(()) + } + + #[cfg(feature = "time")] + #[inline] + fn check(self) -> Result<(), Error> { + if Instant::now() > self.deadline { + Err(Error::Timeout) + } else { + Ok(()) + } + } + + #[cfg(not(feature = "time"))] + #[inline] + fn with(self, fut: impl Future>) -> impl Future> { + fut + } + + #[cfg(feature = "time")] + #[inline] + fn with(self, fut: impl Future>) -> impl Future> { + use futures::FutureExt; + + embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r { + embassy_futures::select::Either::First(_) => Err(Error::Timeout), + embassy_futures::select::Either::Second(r) => r, + }) + } +} + pub(crate) mod sealed { use super::*; diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index b62ee8246..84802d129 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -1,20 +1,14 @@ use core::future::poll_fn; -use core::marker::PhantomData; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_futures::select::{select, Either}; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; use super::*; -use crate::dma::{NoDma, Transfer}; -use crate::gpio::sealed::AFType; -use crate::gpio::Pull; -use crate::interrupt::typelevel::Interrupt; +use crate::dma::Transfer; use crate::pac::i2c; use crate::time::Hertz; -use crate::{interrupt, Peripheral}; pub unsafe fn on_interrupt() { let regs = T::regs(); @@ -30,55 +24,8 @@ pub unsafe fn on_interrupt() { }); } -#[non_exhaustive] -#[derive(Copy, Clone, Default)] -pub struct Config { - pub sda_pullup: bool, - pub scl_pullup: bool, -} - -pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { - phantom: PhantomData<&'d mut T>, - #[allow(dead_code)] - tx_dma: PeripheralRef<'d, TXDMA>, - #[allow(dead_code)] - rx_dma: PeripheralRef<'d, RXDMA>, -} - impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { - pub fn new( - _peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, - _irq: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, - tx_dma: impl Peripheral

+ 'd, - rx_dma: impl Peripheral

+ 'd, - freq: Hertz, - config: Config, - ) -> Self { - into_ref!(scl, sda, tx_dma, rx_dma); - - T::enable_and_reset(); - - scl.set_as_af_pull( - scl.af_num(), - AFType::OutputOpenDrain, - match config.scl_pullup { - true => Pull::Up, - false => Pull::None, - }, - ); - sda.set_as_af_pull( - sda.af_num(), - AFType::OutputOpenDrain, - match config.sda_pullup { - true => Pull::Up, - false => Pull::None, - }, - ); - + pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { T::regs().cr1().modify(|reg| { reg.set_pe(false); //reg.set_anfoff(false); @@ -101,15 +48,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { T::regs().cr1().modify(|reg| { reg.set_pe(true); }); - - unsafe { T::EventInterrupt::enable() }; - unsafe { T::ErrorInterrupt::enable() }; - - Self { - phantom: PhantomData, - tx_dma, - rx_dma, - } } fn check_and_clear_error_flags() -> Result { @@ -169,12 +107,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(sr1) } - fn write_bytes( - &mut self, - addr: u8, - bytes: &[u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { + fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> { // Send a START condition T::regs().cr1().modify(|reg| { @@ -183,7 +116,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Wait until START condition was generated while !Self::check_and_clear_error_flags()?.start() { - check_timeout()?; + timeout.check()?; } // Also wait until signalled we're master and everything is waiting for us @@ -193,7 +126,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let sr2 = T::regs().sr2().read(); !sr2.msl() && !sr2.busy() } { - check_timeout()?; + timeout.check()?; } // Set up current address, we're trying to talk to @@ -203,7 +136,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Wait for the address to be acknowledged // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. while !Self::check_and_clear_error_flags()?.addr() { - check_timeout()?; + timeout.check()?; } // Clear condition by reading SR2 @@ -211,20 +144,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Send bytes for c in bytes { - self.send_byte(*c, &check_timeout)?; + self.send_byte(*c, timeout)?; } // Fallthrough is success Ok(()) } - fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { + fn send_byte(&self, byte: u8, timeout: Timeout) -> Result<(), Error> { // Wait until we're ready for sending while { // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. !Self::check_and_clear_error_flags()?.txe() } { - check_timeout()?; + timeout.check()?; } // Push out a byte of data @@ -235,32 +168,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Check for any potential error conditions. !Self::check_and_clear_error_flags()?.btf() } { - check_timeout()?; + timeout.check()?; } Ok(()) } - fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result { + fn recv_byte(&self, timeout: Timeout) -> Result { while { // Check for any potential error conditions. Self::check_and_clear_error_flags()?; !T::regs().sr1().read().rxne() } { - check_timeout()?; + timeout.check()?; } let value = T::regs().dr().read().dr(); Ok(value) } - pub fn blocking_read_timeout( - &mut self, - addr: u8, - buffer: &mut [u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { + fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> { if let Some((last, buffer)) = buffer.split_last_mut() { // Send a START condition and set ACK bit T::regs().cr1().modify(|reg| { @@ -270,7 +198,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Wait until START condition was generated while !Self::check_and_clear_error_flags()?.start() { - check_timeout()?; + timeout.check()?; } // Also wait until signalled we're master and everything is waiting for us @@ -278,7 +206,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let sr2 = T::regs().sr2().read(); !sr2.msl() && !sr2.busy() } { - check_timeout()?; + timeout.check()?; } // Set up current address, we're trying to talk to @@ -287,7 +215,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Wait until address was sent // Wait for the address to be acknowledged while !Self::check_and_clear_error_flags()?.addr() { - check_timeout()?; + timeout.check()?; } // Clear condition by reading SR2 @@ -295,7 +223,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Receive bytes into buffer for c in buffer { - *c = self.recv_byte(&check_timeout)?; + *c = self.recv_byte(timeout)?; } // Prepare to send NACK then STOP after next byte @@ -305,11 +233,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { }); // Receive last byte - *last = self.recv_byte(&check_timeout)?; + *last = self.recv_byte(timeout)?; // Wait for the STOP to be sent. while T::regs().cr1().read().stop() { - check_timeout()?; + timeout.check()?; } // Fallthrough is success @@ -320,48 +248,33 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(addr, read, || Ok(())) + self.blocking_read_timeout(addr, read, self.timeout()) } - pub fn blocking_write_timeout( - &mut self, - addr: u8, - write: &[u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { - self.write_bytes(addr, write, &check_timeout)?; + pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { + let timeout = self.timeout(); + + self.write_bytes(addr, write, timeout)?; // Send a STOP condition T::regs().cr1().modify(|reg| reg.set_stop(true)); // Wait for STOP condition to transmit. while T::regs().cr1().read().stop() { - check_timeout()?; + timeout.check()?; } // Fallthrough is success Ok(()) } - pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { - self.blocking_write_timeout(addr, write, || Ok(())) - } + pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + let timeout = self.timeout(); - pub fn blocking_write_read_timeout( - &mut self, - addr: u8, - write: &[u8], - read: &mut [u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { - self.write_bytes(addr, write, &check_timeout)?; - self.blocking_read_timeout(addr, read, &check_timeout)?; + self.write_bytes(addr, write, timeout)?; + self.blocking_read_timeout(addr, read, timeout)?; Ok(()) } - pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { - self.blocking_write_read_timeout(addr, write, read, || Ok(())) - } - // Async #[inline] // pretty sure this should always be inlined diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 8c20e1c54..bd3abaac1 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -4,37 +4,13 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; -#[cfg(feature = "time")] -use embassy_time::{Duration, Instant}; use super::*; -use crate::dma::{NoDma, Transfer}; -use crate::gpio::sealed::AFType; -use crate::gpio::Pull; -use crate::interrupt::typelevel::Interrupt; +use crate::dma::Transfer; use crate::pac::i2c; use crate::time::Hertz; -use crate::{interrupt, Peripheral}; -#[cfg(feature = "time")] -fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { - let deadline = Instant::now() + timeout; - move || { - if Instant::now() > deadline { - Err(Error::Timeout) - } else { - Ok(()) - } - } -} - -#[cfg(not(feature = "time"))] -pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> { - move || Ok(()) -} - -pub unsafe fn on_interrupt() { +pub(crate) unsafe fn on_interrupt() { let regs = T::regs(); let isr = regs.isr().read(); @@ -48,70 +24,8 @@ pub unsafe fn on_interrupt() { }); } -#[non_exhaustive] -#[derive(Copy, Clone)] -pub struct Config { - pub sda_pullup: bool, - pub scl_pullup: bool, - #[cfg(feature = "time")] - pub transaction_timeout: Duration, -} - -impl Default for Config { - fn default() -> Self { - Self { - sda_pullup: false, - scl_pullup: false, - #[cfg(feature = "time")] - transaction_timeout: Duration::from_millis(100), - } - } -} - -pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { - _peri: PeripheralRef<'d, T>, - #[allow(dead_code)] - tx_dma: PeripheralRef<'d, TXDMA>, - #[allow(dead_code)] - rx_dma: PeripheralRef<'d, RXDMA>, - #[cfg(feature = "time")] - timeout: Duration, -} - impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { - pub fn new( - peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, - _irq: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, - tx_dma: impl Peripheral

+ 'd, - rx_dma: impl Peripheral

+ 'd, - freq: Hertz, - config: Config, - ) -> Self { - into_ref!(peri, scl, sda, tx_dma, rx_dma); - - T::enable_and_reset(); - - scl.set_as_af_pull( - scl.af_num(), - AFType::OutputOpenDrain, - match config.scl_pullup { - true => Pull::Up, - false => Pull::None, - }, - ); - sda.set_as_af_pull( - sda.af_num(), - AFType::OutputOpenDrain, - match config.sda_pullup { - true => Pull::Up, - false => Pull::None, - }, - ); - + pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { T::regs().cr1().modify(|reg| { reg.set_pe(false); reg.set_anfoff(false); @@ -130,17 +44,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { T::regs().cr1().modify(|reg| { reg.set_pe(true); }); - - unsafe { T::EventInterrupt::enable() }; - unsafe { T::ErrorInterrupt::enable() }; - - Self { - _peri: peri, - tx_dma, - rx_dma, - #[cfg(feature = "time")] - timeout: config.transaction_timeout, - } } fn master_stop(&mut self) { @@ -153,7 +56,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { stop: Stop, reload: bool, restart: bool, - check_timeout: impl Fn() -> Result<(), Error>, + timeout: Timeout, ) -> Result<(), Error> { assert!(length < 256); @@ -162,7 +65,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // automatically. This could be up to 50% of a bus // cycle (ie. up to 0.5/freq) while T::regs().cr2().read().start() { - check_timeout()?; + timeout.check()?; } } @@ -189,20 +92,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } - fn master_write( - address: u8, - length: usize, - stop: Stop, - reload: bool, - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { + fn master_write(address: u8, length: usize, stop: Stop, reload: bool, timeout: Timeout) -> Result<(), Error> { assert!(length < 256); // Wait for any previous address sequence to end // automatically. This could be up to 50% of a bus // cycle (ie. up to 0.5/freq) while T::regs().cr2().read().start() { - check_timeout()?; + timeout.check()?; } let reload = if reload { @@ -227,15 +124,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } - fn master_continue( - length: usize, - reload: bool, - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { + fn master_continue(length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> { assert!(length < 256 && length > 0); while !T::regs().isr().read().tcr() { - check_timeout()?; + timeout.check()?; } let reload = if reload { @@ -261,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } - fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { + fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> { loop { let isr = T::regs().isr().read(); if isr.txe() { @@ -278,11 +171,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { return Err(Error::Nack); } - check_timeout()?; + timeout.check()?; } } - fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { + fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> { loop { let isr = T::regs().isr().read(); if isr.rxne() { @@ -299,11 +192,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { return Err(Error::Nack); } - check_timeout()?; + timeout.check()?; } } - fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { + fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { loop { let isr = T::regs().isr().read(); if isr.tc() { @@ -320,17 +213,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { return Err(Error::Nack); } - check_timeout()?; + timeout.check()?; } } - fn read_internal( - &mut self, - address: u8, - read: &mut [u8], - restart: bool, - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { + fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> { let completed_chunks = read.len() / 255; let total_chunks = if completed_chunks * 255 == read.len() { completed_chunks @@ -345,17 +232,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Stop::Automatic, last_chunk_idx != 0, restart, - &check_timeout, + timeout, )?; for (number, chunk) in read.chunks_mut(255).enumerate() { if number != 0 { - Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; + Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?; } for byte in chunk { // Wait until we have received something - self.wait_rxne(&check_timeout)?; + self.wait_rxne(timeout)?; *byte = T::regs().rxdr().read().rxdata(); } @@ -363,13 +250,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } - fn write_internal( - &mut self, - address: u8, - write: &[u8], - send_stop: bool, - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { + fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> { let completed_chunks = write.len() / 255; let total_chunks = if completed_chunks * 255 == write.len() { completed_chunks @@ -386,7 +267,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { write.len().min(255), Stop::Software, last_chunk_idx != 0, - &check_timeout, + timeout, ) { if send_stop { self.master_stop(); @@ -396,14 +277,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { for (number, chunk) in write.chunks(255).enumerate() { if number != 0 { - Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; + Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?; } for byte in chunk { // Wait until we are allowed to send data // (START has been ACKed or last byte when // through) - if let Err(err) = self.wait_txe(&check_timeout) { + if let Err(err) = self.wait_txe(timeout) { if send_stop { self.master_stop(); } @@ -414,7 +295,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } // Wait until the write finishes - let result = self.wait_tc(&check_timeout); + let result = self.wait_tc(timeout); if send_stop { self.master_stop(); } @@ -427,7 +308,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { write: &[u8], first_slice: bool, last_slice: bool, - check_timeout: impl Fn() -> Result<(), Error>, + timeout: Timeout, ) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, @@ -473,10 +354,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { total_len.min(255), Stop::Software, (total_len > 255) || !last_slice, - &check_timeout, + timeout, )?; } else { - Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; + Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, timeout)?; T::regs().cr1().modify(|w| w.set_tcie(true)); } } else if !(isr.tcr() || isr.tc()) { @@ -487,7 +368,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } else { let last_piece = (remaining_len <= 255) && last_slice; - if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { + if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) { return Poll::Ready(Err(e)); } T::regs().cr1().modify(|w| w.set_tcie(true)); @@ -502,7 +383,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if last_slice { // This should be done already - self.wait_tc(&check_timeout)?; + self.wait_tc(timeout)?; self.master_stop(); } @@ -516,7 +397,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { address: u8, buffer: &mut [u8], restart: bool, - check_timeout: impl Fn() -> Result<(), Error>, + timeout: Timeout, ) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, @@ -558,7 +439,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Stop::Software, total_len > 255, restart, - &check_timeout, + timeout, )?; } else if !(isr.tcr() || isr.tc()) { // poll_fn was woken without an interrupt present @@ -568,7 +449,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } else { let last_piece = remaining_len <= 255; - if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { + if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) { return Poll::Ready(Err(e)); } T::regs().cr1().modify(|w| w.set_tcie(true)); @@ -582,7 +463,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { dma_transfer.await; // This should be done already - self.wait_tc(&check_timeout)?; + self.wait_tc(timeout)?; self.master_stop(); drop(on_drop); @@ -592,41 +473,31 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // ========================= // Async public API - #[cfg(feature = "time")] - pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - if write.is_empty() { - self.write_internal(address, write, true, timeout_fn(self.timeout)) - } else { - embassy_time::with_timeout( - self.timeout, - self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)), - ) - .await - .unwrap_or(Err(Error::Timeout)) - } - } - #[cfg(not(feature = "time"))] + /// Write. pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { + let timeout = self.timeout(); if write.is_empty() { - self.write_internal(address, write, true, no_timeout_fn()) + self.write_internal(address, write, true, timeout) } else { - self.write_dma_internal(address, write, true, true, no_timeout_fn()) + timeout + .with(self.write_dma_internal(address, write, true, true, timeout)) .await } } - #[cfg(feature = "time")] + /// Write multiple buffers. + /// + /// The buffers are concatenated in a single write transaction. pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { + let timeout = self.timeout(); + if write.is_empty() { return Err(Error::ZeroLengthTransfer); } @@ -638,123 +509,49 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let next = iter.next(); let is_last = next.is_none(); - embassy_time::with_timeout( - self.timeout, - self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)), - ) - .await - .unwrap_or(Err(Error::Timeout))?; + let fut = self.write_dma_internal(address, c, first, is_last, timeout); + timeout.with(fut).await?; first = false; current = next; } Ok(()) } - #[cfg(not(feature = "time"))] - pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - if write.is_empty() { - return Err(Error::ZeroLengthTransfer); - } - let mut iter = write.iter(); - - let mut first = true; - let mut current = iter.next(); - while let Some(c) = current { - let next = iter.next(); - let is_last = next.is_none(); - - self.write_dma_internal(address, c, first, is_last, no_timeout_fn()) - .await?; - first = false; - current = next; - } - Ok(()) - } - - #[cfg(feature = "time")] + /// Read. pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, { + let timeout = self.timeout(); + if buffer.is_empty() { - self.read_internal(address, buffer, false, timeout_fn(self.timeout)) + self.read_internal(address, buffer, false, timeout) } else { - embassy_time::with_timeout( - self.timeout, - self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)), - ) - .await - .unwrap_or(Err(Error::Timeout)) + let fut = self.read_dma_internal(address, buffer, false, timeout); + timeout.with(fut).await } } - #[cfg(not(feature = "time"))] - pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> - where - RXDMA: crate::i2c::RxDma, - { - if buffer.is_empty() { - self.read_internal(address, buffer, false, no_timeout_fn()) - } else { - self.read_dma_internal(address, buffer, false, no_timeout_fn()).await - } - } - - #[cfg(feature = "time")] + /// Write, restart, read. pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> where TXDMA: super::TxDma, RXDMA: super::RxDma, { - let start_instant = Instant::now(); - let check_timeout = timeout_fn(self.timeout); + let timeout = self.timeout(); + if write.is_empty() { - self.write_internal(address, write, false, &check_timeout)?; + self.write_internal(address, write, false, timeout)?; } else { - embassy_time::with_timeout( - self.timeout, - self.write_dma_internal(address, write, true, true, &check_timeout), - ) - .await - .unwrap_or(Err(Error::Timeout))?; - } - - let time_left_until_timeout = self.timeout - Instant::now().duration_since(start_instant); - - if read.is_empty() { - self.read_internal(address, read, true, &check_timeout)?; - } else { - embassy_time::with_timeout( - time_left_until_timeout, - self.read_dma_internal(address, read, true, &check_timeout), - ) - .await - .unwrap_or(Err(Error::Timeout))?; - } - - Ok(()) - } - - #[cfg(not(feature = "time"))] - pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> - where - TXDMA: super::TxDma, - RXDMA: super::RxDma, - { - let no_timeout = no_timeout_fn(); - if write.is_empty() { - self.write_internal(address, write, false, &no_timeout)?; - } else { - self.write_dma_internal(address, write, true, true, &no_timeout).await?; + let fut = self.write_dma_internal(address, write, true, true, timeout); + timeout.with(fut).await?; } if read.is_empty() { - self.read_internal(address, read, true, &no_timeout)?; + self.read_internal(address, read, true, timeout)?; } else { - self.read_dma_internal(address, read, true, &no_timeout).await?; + let fut = self.read_dma_internal(address, read, true, timeout); + timeout.with(fut).await?; } Ok(()) @@ -763,105 +560,35 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // ========================= // Blocking public API - #[cfg(feature = "time")] - pub fn blocking_read_timeout(&mut self, address: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> { - self.read_internal(address, read, false, timeout_fn(timeout)) - // Automatic Stop - } - - #[cfg(not(feature = "time"))] - pub fn blocking_read_timeout( - &mut self, - address: u8, - read: &mut [u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { - self.read_internal(address, read, false, check_timeout) - // Automatic Stop - } - - #[cfg(feature = "time")] + /// Blocking read. pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(address, read, self.timeout) - } - - #[cfg(not(feature = "time"))] - pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(address, read, || Ok(())) - } - - #[cfg(feature = "time")] - pub fn blocking_write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> { - self.write_internal(address, write, true, timeout_fn(timeout)) - } - - #[cfg(not(feature = "time"))] - pub fn blocking_write_timeout( - &mut self, - address: u8, - write: &[u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { - self.write_internal(address, write, true, check_timeout) - } - - #[cfg(feature = "time")] - pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { - self.blocking_write_timeout(address, write, self.timeout) - } - - #[cfg(not(feature = "time"))] - pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { - self.blocking_write_timeout(address, write, || Ok(())) - } - - #[cfg(feature = "time")] - pub fn blocking_write_read_timeout( - &mut self, - address: u8, - write: &[u8], - read: &mut [u8], - timeout: Duration, - ) -> Result<(), Error> { - let check_timeout = timeout_fn(timeout); - self.write_internal(address, write, false, &check_timeout)?; - self.read_internal(address, read, true, &check_timeout) + self.read_internal(address, read, false, self.timeout()) // Automatic Stop } - #[cfg(not(feature = "time"))] - pub fn blocking_write_read_timeout( - &mut self, - address: u8, - write: &[u8], - read: &mut [u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { - self.write_internal(address, write, false, &check_timeout)?; - self.read_internal(address, read, true, &check_timeout) + /// Blocking write. + pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { + self.write_internal(address, write, true, self.timeout()) + } + + /// Blocking write, restart, read. + pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + let timeout = self.timeout(); + self.write_internal(address, write, false, timeout)?; + self.read_internal(address, read, true, timeout) // Automatic Stop } - #[cfg(feature = "time")] - pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { - self.blocking_write_read_timeout(address, write, read, self.timeout) - } - - #[cfg(not(feature = "time"))] - pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { - self.blocking_write_read_timeout(address, write, read, || Ok(())) - } - - fn blocking_write_vectored_with_timeout( - &mut self, - address: u8, - write: &[&[u8]], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { + /// Blocking write multiple buffers. + /// + /// The buffers are concatenated in a single write transaction. + pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { if write.is_empty() { return Err(Error::ZeroLengthTransfer); } + let timeout = self.timeout(); + let first_length = write[0].len(); let last_slice_index = write.len() - 1; @@ -870,7 +597,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { first_length.min(255), Stop::Software, (first_length > 255) || (last_slice_index != 0), - &check_timeout, + timeout, ) { self.master_stop(); return Err(err); @@ -890,7 +617,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if let Err(err) = Self::master_continue( slice_len.min(255), (idx != last_slice_index) || (slice_len > 255), - &check_timeout, + timeout, ) { self.master_stop(); return Err(err); @@ -902,7 +629,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if let Err(err) = Self::master_continue( chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index), - &check_timeout, + timeout, ) { self.master_stop(); return Err(err); @@ -913,7 +640,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Wait until we are allowed to send data // (START has been ACKed or last byte when // through) - if let Err(err) = self.wait_txe(&check_timeout) { + if let Err(err) = self.wait_txe(timeout) { self.master_stop(); return Err(err); } @@ -925,41 +652,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } // Wait until the write finishes - let result = self.wait_tc(&check_timeout); + let result = self.wait_tc(timeout); self.master_stop(); result } - - #[cfg(feature = "time")] - pub fn blocking_write_vectored_timeout( - &mut self, - address: u8, - write: &[&[u8]], - timeout: Duration, - ) -> Result<(), Error> { - let check_timeout = timeout_fn(timeout); - self.blocking_write_vectored_with_timeout(address, write, check_timeout) - } - - #[cfg(not(feature = "time"))] - pub fn blocking_write_vectored_timeout( - &mut self, - address: u8, - write: &[&[u8]], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> { - self.blocking_write_vectored_with_timeout(address, write, check_timeout) - } - - #[cfg(feature = "time")] - pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { - self.blocking_write_vectored_timeout(address, write, self.timeout) - } - - #[cfg(not(feature = "time"))] - pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { - self.blocking_write_vectored_timeout(address, write, || Ok(())) - } } impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { From 2b497c1e578bd08166bee89de8ae824041fbbc70 Mon Sep 17 00:00:00 2001 From: James Munns Date: Mon, 18 Dec 2023 18:38:13 +0100 Subject: [PATCH 047/760] Fix nb on rp uart --- embassy-rp/src/uart/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 18705b141..f82b9036b 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -820,6 +820,10 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { fn read(&mut self) -> nb::Result { let r = T::regs(); + if r.uartfr().read().rxfe() { + return Err(nb::Error::WouldBlock); + } + let dr = r.uartdr().read(); if dr.oe() { @@ -830,10 +834,8 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M Err(nb::Error::Other(Error::Parity)) } else if dr.fe() { Err(nb::Error::Other(Error::Framing)) - } else if dr.fe() { - Ok(dr.data()) } else { - Err(nb::Error::WouldBlock) + Ok(dr.data()) } } } From 21fce1e19501171cfd3a5ddd32556961410bd024 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Dec 2023 18:43:01 +0100 Subject: [PATCH 048/760] stm32/can: cleanup interrupt traits. --- embassy-stm32/src/can/bxcan.rs | 52 +++++++--------------------------- 1 file changed, 10 insertions(+), 42 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 2f7417340..788360249 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -585,30 +585,18 @@ pub(crate) mod sealed { pub trait Instance { const REGISTERS: *mut bxcan::RegisterBlock; - fn regs() -> &'static crate::pac::can::Can; + fn regs() -> crate::pac::can::Can; fn state() -> &'static State; } } -pub trait TXInstance { +pub trait Instance: sealed::Instance + RccPeripheral + 'static { type TXInterrupt: crate::interrupt::typelevel::Interrupt; -} - -pub trait RX0Instance { type RX0Interrupt: crate::interrupt::typelevel::Interrupt; -} - -pub trait RX1Instance { type RX1Interrupt: crate::interrupt::typelevel::Interrupt; -} - -pub trait SCEInstance { type SCEInterrupt: crate::interrupt::typelevel::Interrupt; } -pub trait InterruptableInstance: TXInstance + RX0Instance + RX1Instance + SCEInstance {} -pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {} - pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { @@ -620,8 +608,8 @@ foreach_peripheral!( impl sealed::Instance for peripherals::$inst { const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; - fn regs() -> &'static crate::pac::can::Can { - &crate::pac::$inst + fn regs() -> crate::pac::can::Can { + crate::pac::$inst } fn state() -> &'static sealed::State { @@ -630,32 +618,12 @@ foreach_peripheral!( } } - impl Instance for peripherals::$inst {} - - foreach_interrupt!( - ($inst,can,CAN,TX,$irq:ident) => { - impl TXInstance for peripherals::$inst { - type TXInterrupt = crate::interrupt::typelevel::$irq; - } - }; - ($inst,can,CAN,RX0,$irq:ident) => { - impl RX0Instance for peripherals::$inst { - type RX0Interrupt = crate::interrupt::typelevel::$irq; - } - }; - ($inst,can,CAN,RX1,$irq:ident) => { - impl RX1Instance for peripherals::$inst { - type RX1Interrupt = crate::interrupt::typelevel::$irq; - } - }; - ($inst,can,CAN,SCE,$irq:ident) => { - impl SCEInstance for peripherals::$inst { - type SCEInterrupt = crate::interrupt::typelevel::$irq; - } - }; - ); - - impl InterruptableInstance for peripherals::$inst {} + impl Instance for peripherals::$inst { + type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX; + type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0; + type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1; + type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE; + } }; ); From 87c8d9df94d222d772013fbb3f8ec60054cde039 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Dec 2023 18:44:41 +0100 Subject: [PATCH 049/760] stm32/can: docs. --- embassy-stm32/src/can/bxcan.rs | 45 +++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 788360249..3c663b452 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -21,8 +21,10 @@ use crate::{interrupt, peripherals, Peripheral}; #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Envelope { + /// Reception time. #[cfg(feature = "time")] pub ts: embassy_time::Instant, + /// The actual CAN frame. pub frame: bxcan::Frame, } @@ -43,6 +45,7 @@ impl interrupt::typelevel::Handler for TxInterruptH } } +/// RX0 interrupt handler. pub struct Rx0InterruptHandler { _phantom: PhantomData, } @@ -54,6 +57,7 @@ impl interrupt::typelevel::Handler for Rx0Interrup } } +/// RX1 interrupt handler. pub struct Rx1InterruptHandler { _phantom: PhantomData, } @@ -65,6 +69,7 @@ impl interrupt::typelevel::Handler for Rx1Interrup } } +/// SCE interrupt handler. pub struct SceInterruptHandler { _phantom: PhantomData, } @@ -82,10 +87,13 @@ impl interrupt::typelevel::Handler for SceInterrup } } +/// CAN driver pub struct Can<'d, T: Instance> { - pub can: bxcan::Can>, + can: bxcan::Can>, } +/// CAN bus error +#[allow(missing_docs)] #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum BusError { @@ -101,6 +109,7 @@ pub enum BusError { BusWarning, } +/// Error returned by `try_read` #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum TryReadError { @@ -110,6 +119,7 @@ pub enum TryReadError { Empty, } +/// Error returned by `try_write` #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum TryWriteError { @@ -177,6 +187,7 @@ impl<'d, T: Instance> Can<'d, T> { Self { can } } + /// Set CAN bit rate. pub fn set_bitrate(&mut self, bitrate: u32) { let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); @@ -194,7 +205,9 @@ impl<'d, T: Instance> Can<'d, T> { } } - /// Queues the message to be sent but exerts backpressure + /// Queues the message to be sent. + /// + /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { self.split().0.write(frame).await } @@ -221,12 +234,16 @@ impl<'d, T: Instance> Can<'d, T> { CanTx::::flush_all_inner().await } + /// Read a CAN frame. + /// + /// If no CAN frame is in the RX buffer, this will wait until there is one. + /// /// Returns a tuple of the time the message was received and the message frame pub async fn read(&mut self) -> Result { self.split().1.read().await } - /// Attempts to read a can frame without blocking. + /// Attempts to read a CAN frame without blocking. /// /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. pub fn try_read(&mut self) -> Result { @@ -288,7 +305,7 @@ impl<'d, T: Instance> Can<'d, T> { } } - pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option { + const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option { const BS1_MAX: u8 = 16; const BS2_MAX: u8 = 8; const MAX_SAMPLE_POINT_PERMILL: u16 = 900; @@ -379,21 +396,29 @@ impl<'d, T: Instance> Can<'d, T> { Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) } + /// Split the CAN driver into transmit and receive halves. + /// + /// Useful for doing separate transmit/receive tasks. pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { let (tx, rx0, rx1) = self.can.split_by_ref(); (CanTx { tx }, CanRx { rx0, rx1 }) } + /// Get mutable access to the lower-level driver from the `bxcan` crate. pub fn as_mut(&mut self) -> &mut bxcan::Can> { &mut self.can } } +/// CAN driver, transmit half. pub struct CanTx<'c, 'd, T: Instance> { tx: &'c mut bxcan::Tx>, } impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { + /// Queues the message to be sent. + /// + /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { poll_fn(|cx| { T::state().tx_waker.register(cx.waker()); @@ -475,6 +500,7 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { } } +/// CAN driver, receive half. #[allow(dead_code)] pub struct CanRx<'c, 'd, T: Instance> { rx0: &'c mut bxcan::Rx0>, @@ -482,6 +508,11 @@ pub struct CanRx<'c, 'd, T: Instance> { } impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { + /// Read a CAN frame. + /// + /// If no CAN frame is in the RX buffer, this will wait until there is one. + /// + /// Returns a tuple of the time the message was received and the message frame pub async fn read(&mut self) -> Result { poll_fn(|cx| { T::state().err_waker.register(cx.waker()); @@ -590,13 +621,19 @@ pub(crate) mod sealed { } } +/// CAN instance trait. pub trait Instance: sealed::Instance + RccPeripheral + 'static { + /// TX interrupt for this instance. type TXInterrupt: crate::interrupt::typelevel::Interrupt; + /// RX0 interrupt for this instance. type RX0Interrupt: crate::interrupt::typelevel::Interrupt; + /// RX1 interrupt for this instance. type RX1Interrupt: crate::interrupt::typelevel::Interrupt; + /// SCE interrupt for this instance. type SCEInterrupt: crate::interrupt::typelevel::Interrupt; } +/// BXCAN instance newtype. pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { From 124478c5e9df16f0930d019c6f0db358666b3249 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Dec 2023 19:11:13 +0100 Subject: [PATCH 050/760] stm32: more docs. --- embassy-stm32/src/adc/mod.rs | 1 + embassy-stm32/src/crc/v1.rs | 4 +++ embassy-stm32/src/dma/mod.rs | 2 ++ embassy-stm32/src/eth/v1/mod.rs | 2 ++ embassy-stm32/src/flash/asynch.rs | 17 ++++++++++ embassy-stm32/src/flash/f4.rs | 2 +- embassy-stm32/src/fmc.rs | 4 +++ embassy-stm32/src/gpio.rs | 2 ++ embassy-stm32/src/i2c/v1.rs | 6 ++++ embassy-stm32/src/i2s.rs | 35 +++++++++++++++++--- embassy-stm32/src/rcc/mod.rs | 3 ++ embassy-stm32/src/rng.rs | 15 ++++++++- embassy-stm32/src/rtc/datetime.rs | 12 +++++-- embassy-stm32/src/rtc/mod.rs | 12 ++++--- embassy-stm32/src/timer/complementary_pwm.rs | 2 ++ embassy-stm32/src/timer/mod.rs | 3 ++ embassy-stm32/src/timer/qei.rs | 2 ++ embassy-stm32/src/timer/simple_pwm.rs | 2 ++ 18 files changed, 112 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 2e470662d..ff523ca3b 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,5 +1,6 @@ //! Analog to Digital (ADC) converter driver. #![macro_use] +#![allow(missing_docs)] // TODO #[cfg(not(adc_f3_v2))] #[cfg_attr(adc_f1, path = "f1.rs")] diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index c0f580830..0166ab819 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -5,6 +5,7 @@ use crate::peripherals::CRC; use crate::rcc::sealed::RccPeripheral; use crate::Peripheral; +/// CRC driver. pub struct Crc<'d> { _peri: PeripheralRef<'d, CRC>, } @@ -34,6 +35,7 @@ impl<'d> Crc<'d> { PAC_CRC.dr().write_value(word); self.read() } + /// 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 { @@ -42,6 +44,8 @@ impl<'d> Crc<'d> { self.read() } + + /// Read the CRC result value. pub fn read(&self) -> u32 { PAC_CRC.dr().read() } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index fb40a4b5e..38945ac33 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -1,3 +1,5 @@ +//! Direct Memory Access (DMA) + #[cfg(dma)] pub(crate) mod dma; #[cfg(dma)] diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 13e53f687..2ce5b3927 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -43,6 +43,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } } +/// Ethernet driver. pub struct Ethernet<'d, T: Instance, P: PHY> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, @@ -266,6 +267,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { } } +/// Ethernet station management interface. pub struct EthernetStationManagement { peri: PhantomData, clock_range: Cr, diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index e3c6d4d67..97eaece81 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -17,6 +17,7 @@ use crate::{interrupt, Peripheral}; pub(super) static REGION_ACCESS: Mutex = Mutex::new(()); impl<'d> Flash<'d, Async> { + /// Create a new flash driver with async capabilities. pub fn new( p: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding + 'd, @@ -32,15 +33,26 @@ impl<'d> Flash<'d, Async> { } } + /// Split this flash driver into one instance per flash memory region. + /// + /// See module-level documentation for details on how memory regions work. pub fn into_regions(self) -> FlashLayout<'d, Async> { assert!(family::is_default_layout()); FlashLayout::new(self.inner) } + /// Async write. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to write address `0x0800_1234` you have to use offset `0x1234`. pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } } + /// Async erase. + /// + /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address. + /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`. pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } } @@ -141,15 +153,20 @@ pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Resu foreach_flash_region! { ($type_name:ident, $write_size:literal, $erase_size:literal) => { impl crate::_generated::flash_regions::$type_name<'_, Async> { + /// Async read. + /// + /// Note: reading from flash can't actually block, so this is the same as `blocking_read`. pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { blocking_read(self.0.base, self.0.size, offset, bytes) } + /// Async write. pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { let _guard = REGION_ACCESS.lock().await; unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } } + /// Async erase. pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { let _guard = REGION_ACCESS.lock().await; unsafe { erase_sectored(self.0.base, from, to).await } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index f442c5894..2671dfb04 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -9,7 +9,7 @@ use pac::FLASH_SIZE; use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; - +#[allow(missing_docs)] // TODO #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] mod alt_regions { use core::marker::PhantomData; diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index dd0d27217..23ac82f63 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -6,6 +6,7 @@ use crate::gpio::sealed::AFType; use crate::gpio::{Pull, Speed}; use crate::Peripheral; +/// FMC driver pub struct Fmc<'d, T: Instance> { peri: PhantomData<&'d mut T>, } @@ -38,6 +39,7 @@ where T::REGS.bcr1().modify(|r| r.set_fmcen(true)); } + /// Get the kernel clock currently in use for this FMC instance. pub fn source_clock_hz(&self) -> u32 { ::frequency().0 } @@ -85,6 +87,7 @@ macro_rules! fmc_sdram_constructor { nbl: [$(($nbl_pin_name:ident: $nbl_signal:ident)),*], ctrl: [$(($ctrl_pin_name:ident: $ctrl_signal:ident)),*] )) => { + /// Create a new FMC instance. pub fn $name( _instance: impl Peripheral

+ 'd, $($addr_pin_name: impl Peripheral

> + 'd),*, @@ -199,6 +202,7 @@ pub(crate) mod sealed { } } +/// FMC instance trait. pub trait Instance: sealed::Instance + 'static {} foreach_peripheral!( diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 083b3237c..c300a079e 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -1,3 +1,5 @@ +//! General-purpose Input/Output (GPIO) + #![macro_use] use core::convert::Infallible; diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 84802d129..df5b44c2d 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -247,10 +247,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } + /// Blocking read. pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { self.blocking_read_timeout(addr, read, self.timeout()) } + /// Blocking write. pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { let timeout = self.timeout(); @@ -266,6 +268,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } + /// Blocking write, restart, read. pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { let timeout = self.timeout(); @@ -435,6 +438,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } + /// Write. pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, @@ -457,6 +461,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } + /// Read. pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, @@ -616,6 +621,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } + /// Write, restart, read. pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 67d40c479..372c86db3 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -8,30 +8,42 @@ use crate::spi::{Config as SpiConfig, *}; use crate::time::Hertz; use crate::{Peripheral, PeripheralRef}; +/// I2S mode #[derive(Copy, Clone)] pub enum Mode { + /// Master mode Master, + /// Slave mode Slave, } +/// I2S function #[derive(Copy, Clone)] pub enum Function { + /// Transmit audio data Transmit, + /// Receive audio data Receive, } +/// I2C standard #[derive(Copy, Clone)] pub enum Standard { + /// Philips Philips, + /// Most significant bit first. MsbFirst, + /// Least significant bit first. LsbFirst, + /// PCM with long sync. PcmLongSync, + /// PCM with short sync. PcmShortSync, } impl Standard { #[cfg(any(spi_v1, spi_f1))] - pub const fn i2sstd(&self) -> vals::I2sstd { + const fn i2sstd(&self) -> vals::I2sstd { match self { Standard::Philips => vals::I2sstd::PHILIPS, Standard::MsbFirst => vals::I2sstd::MSB, @@ -42,7 +54,7 @@ impl Standard { } #[cfg(any(spi_v1, spi_f1))] - pub const fn pcmsync(&self) -> vals::Pcmsync { + const fn pcmsync(&self) -> vals::Pcmsync { match self { Standard::PcmLongSync => vals::Pcmsync::LONG, _ => vals::Pcmsync::SHORT, @@ -50,6 +62,7 @@ impl Standard { } } +/// I2S data format. #[derive(Copy, Clone)] pub enum Format { /// 16 bit data length on 16 bit wide channel @@ -64,7 +77,7 @@ pub enum Format { impl Format { #[cfg(any(spi_v1, spi_f1))] - pub const fn datlen(&self) -> vals::Datlen { + const fn datlen(&self) -> vals::Datlen { match self { Format::Data16Channel16 => vals::Datlen::SIXTEENBIT, Format::Data16Channel32 => vals::Datlen::SIXTEENBIT, @@ -74,7 +87,7 @@ impl Format { } #[cfg(any(spi_v1, spi_f1))] - pub const fn chlen(&self) -> vals::Chlen { + const fn chlen(&self) -> vals::Chlen { match self { Format::Data16Channel16 => vals::Chlen::SIXTEENBIT, Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT, @@ -84,15 +97,18 @@ impl Format { } } +/// Clock polarity #[derive(Copy, Clone)] pub enum ClockPolarity { + /// Low on idle. IdleLow, + /// High on idle. IdleHigh, } impl ClockPolarity { #[cfg(any(spi_v1, spi_f1))] - pub const fn ckpol(&self) -> vals::Ckpol { + const fn ckpol(&self) -> vals::Ckpol { match self { ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH, ClockPolarity::IdleLow => vals::Ckpol::IDLELOW, @@ -109,11 +125,17 @@ impl ClockPolarity { #[non_exhaustive] #[derive(Copy, Clone)] pub struct Config { + /// Mode pub mode: Mode, + /// Function (transmit, receive) pub function: Function, + /// Which I2S standard to use. pub standard: Standard, + /// Data format. pub format: Format, + /// Clock polarity. pub clock_polarity: ClockPolarity, + /// True to eanble master clock output from this instance. pub master_clock: bool, } @@ -130,6 +152,7 @@ impl Default for Config { } } +/// I2S driver. pub struct I2S<'d, T: Instance, Tx, Rx> { _peri: Spi<'d, T, Tx, Rx>, sd: Option>, @@ -242,6 +265,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { } } + /// Write audio data. pub async fn write(&mut self, data: &[W]) -> Result<(), Error> where Tx: TxDma, @@ -249,6 +273,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { self._peri.write(data).await } + /// Read audio data. pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> where Tx: TxDma, diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index dc829a9ad..04a51110c 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,4 +1,7 @@ +//! Reset and Clock Control (RCC) + #![macro_use] +#![allow(missing_docs)] // TODO use core::mem::MaybeUninit; diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 5e6922e9b..b2196b0d5 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -13,13 +13,19 @@ use crate::{interrupt, pac, peripherals, Peripheral}; static RNG_WAKER: AtomicWaker = AtomicWaker::new(); +/// RNG error #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Seed error. SeedError, + /// Clock error. Double-check the RCC configuration, + /// see the Reference Manual for details on restrictions + /// on RNG clocks. ClockError, } +/// RNG interrupt handler. pub struct InterruptHandler { _phantom: PhantomData, } @@ -34,11 +40,13 @@ impl interrupt::typelevel::Handler for InterruptHandl } } +/// RNG driver. pub struct Rng<'d, T: Instance> { _inner: PeripheralRef<'d, T>, } impl<'d, T: Instance> Rng<'d, T> { + /// Create a new RNG driver. pub fn new( inner: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -54,6 +62,7 @@ impl<'d, T: Instance> Rng<'d, T> { random } + /// Reset the RNG. #[cfg(rng_v1)] pub fn reset(&mut self) { T::regs().cr().write(|reg| { @@ -106,7 +115,8 @@ impl<'d, T: Instance> Rng<'d, T> { while T::regs().cr().read().condrst() {} } - pub fn recover_seed_error(&mut self) -> () { + /// Try to recover from a seed error. + pub fn recover_seed_error(&mut self) { self.reset(); // reset should also clear the SEIS flag if T::regs().sr().read().seis() { @@ -117,6 +127,7 @@ impl<'d, T: Instance> Rng<'d, T> { while T::regs().sr().read().secs() {} } + /// Fill the given slice with random values. pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(4) { let mut bits = T::regs().sr().read(); @@ -217,7 +228,9 @@ pub(crate) mod sealed { } } +/// RNG instance trait. pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { + /// Interrupt for this RNG instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index f4e86dd87..ef92fa4bb 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -104,45 +104,51 @@ pub struct DateTime { } impl DateTime { + /// Get the year (0..=4095) pub const fn year(&self) -> u16 { self.year } + /// Get the month (1..=12, 1 is January) pub const fn month(&self) -> u8 { self.month } + /// Get the day (1..=31) pub const fn day(&self) -> u8 { self.day } + /// Get the day of week pub const fn day_of_week(&self) -> DayOfWeek { self.day_of_week } + /// Get the hour (0..=23) pub const fn hour(&self) -> u8 { self.hour } + /// Get the minute (0..=59) pub const fn minute(&self) -> u8 { self.minute } + /// Get the second (0..=59) pub const fn second(&self) -> u8 { self.second } + /// Create a new DateTime with the given information. pub fn from( year: u16, month: u8, day: u8, - day_of_week: u8, + day_of_week: DayOfWeek, hour: u8, minute: u8, second: u8, ) -> Result { - let day_of_week = day_of_week_from_u8(day_of_week)?; - if year > 4095 { Err(Error::InvalidYear) } else if month < 1 || month > 12 { diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index b4315f535..fa359cdae 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -9,9 +9,9 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; #[cfg(feature = "low-power")] use embassy_sync::blocking_mutex::Mutex; -use self::datetime::day_of_week_to_u8; #[cfg(not(rtc_v2f2))] use self::datetime::RtcInstant; +use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; use crate::pac::rtc::regs::{Dr, Tr}; use crate::time::Hertz; @@ -102,7 +102,7 @@ pub enum RtcError { NotRunning, } -pub struct RtcTimeProvider { +pub(crate) struct RtcTimeProvider { _private: (), } @@ -127,7 +127,7 @@ impl RtcTimeProvider { let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); let hour = bcd2_to_byte((tr.ht(), tr.hu())); - let weekday = dr.wdu(); + let weekday = day_of_week_from_u8(dr.wdu()).map_err(RtcError::InvalidDateTime)?; let day = bcd2_to_byte((dr.dt(), dr.du())); let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; @@ -171,6 +171,7 @@ pub struct Rtc { _private: (), } +/// RTC configuration. #[non_exhaustive] #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { @@ -188,6 +189,7 @@ impl Default for RtcConfig { } } +/// Calibration cycle period. #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] pub enum RtcCalibrationCyclePeriod { @@ -206,6 +208,7 @@ impl Default for RtcCalibrationCyclePeriod { } impl Rtc { + /// Create a new RTC instance. pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] ::enable_and_reset(); @@ -240,7 +243,7 @@ impl Rtc { } /// Acquire a [`RtcTimeProvider`] instance. - pub const fn time_provider(&self) -> RtcTimeProvider { + pub(crate) const fn time_provider(&self) -> RtcTimeProvider { RtcTimeProvider { _private: () } } @@ -315,6 +318,7 @@ impl Rtc { }) } + /// Number of backup registers of this instance. pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; /// Read content of the backup register. diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 6654366cd..e543a5b43 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -1,3 +1,5 @@ +//! PWM driver with complementary output support. + use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9f93c6425..42ef878f7 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,3 +1,5 @@ +//! Timers, PWM, quadrature decoder. + pub mod complementary_pwm; pub mod qei; pub mod simple_pwm; @@ -8,6 +10,7 @@ use crate::interrupt; use crate::rcc::RccPeripheral; use crate::time::Hertz; +/// Low-level timer access. #[cfg(feature = "unstable-pac")] pub mod low_level { pub use super::sealed::*; diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 01d028bf9..9f9379c20 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -1,3 +1,5 @@ +//! Quadrature decoder using a timer. + use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1cf0ad728..234bbaff0 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -1,3 +1,5 @@ +//! Simple PWM driver. + use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; From c952ae0f49a21ade19758e4f6f1e2bec503e413e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Dec 2023 23:48:17 +0100 Subject: [PATCH 051/760] stm32/sai: remove unimplemented SetConfig. --- embassy-stm32/src/sai/mod.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 3d7f65996..96acd9e48 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1,6 +1,5 @@ #![macro_use] -use embassy_embedded_hal::SetConfig; use embassy_hal_internal::{into_ref, PeripheralRef}; pub use crate::dma::word; @@ -988,14 +987,6 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { ch.cr2().modify(|w| w.set_mute(value)); } - #[allow(dead_code)] - /// Reconfigures it with the supplied config. - fn reconfigure(&mut self, _config: Config) {} - - pub fn get_current_config(&self) -> Config { - Config::default() - } - pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { match &mut self.ring_buffer { RingBuffer::Writable(buffer) => { @@ -1060,13 +1051,3 @@ foreach_peripheral!( impl Instance for peripherals::$inst {} }; ); - -impl<'d, T: Instance> SetConfig for Sai<'d, T> { - type Config = Config; - type ConfigError = (); - fn set_config(&mut self, _config: &Self::Config) -> Result<(), ()> { - // self.reconfigure(*config); - - Ok(()) - } -} From 4deae51e656e46e18840bf30e68a976aaaf8ad20 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Dec 2023 23:49:37 +0100 Subject: [PATCH 052/760] stm32/sai: deduplicate code for subblocks A/B. --- embassy-stm32/build.rs | 20 +-- embassy-stm32/src/sai/mod.rs | 339 ++++++++++++----------------------- embassy-stm32/src/traits.rs | 26 +-- 3 files changed, 135 insertions(+), 250 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index bb60d244f..058b8a0fc 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -672,14 +672,14 @@ fn main() { (("lpuart", "RTS"), quote!(crate::usart::RtsPin)), (("lpuart", "CK"), quote!(crate::usart::CkPin)), (("lpuart", "DE"), quote!(crate::usart::DePin)), - (("sai", "SCK_A"), quote!(crate::sai::SckAPin)), - (("sai", "SCK_B"), quote!(crate::sai::SckBPin)), - (("sai", "FS_A"), quote!(crate::sai::FsAPin)), - (("sai", "FS_B"), quote!(crate::sai::FsBPin)), - (("sai", "SD_A"), quote!(crate::sai::SdAPin)), - (("sai", "SD_B"), quote!(crate::sai::SdBPin)), - (("sai", "MCLK_A"), quote!(crate::sai::MclkAPin)), - (("sai", "MCLK_B"), quote!(crate::sai::MclkBPin)), + (("sai", "SCK_A"), quote!(crate::sai::SckPin)), + (("sai", "SCK_B"), quote!(crate::sai::SckPin)), + (("sai", "FS_A"), quote!(crate::sai::FsPin)), + (("sai", "FS_B"), quote!(crate::sai::FsPin)), + (("sai", "SD_A"), quote!(crate::sai::SdPin)), + (("sai", "SD_B"), quote!(crate::sai::SdPin)), + (("sai", "MCLK_A"), quote!(crate::sai::MclkPin)), + (("sai", "MCLK_B"), quote!(crate::sai::MclkPin)), (("sai", "WS"), quote!(crate::sai::WsPin)), (("spi", "SCK"), quote!(crate::spi::SckPin)), (("spi", "MOSI"), quote!(crate::spi::MosiPin)), @@ -995,8 +995,8 @@ fn main() { (("usart", "TX"), quote!(crate::usart::TxDma)), (("lpuart", "RX"), quote!(crate::usart::RxDma)), (("lpuart", "TX"), quote!(crate::usart::TxDma)), - (("sai", "A"), quote!(crate::sai::DmaA)), - (("sai", "B"), quote!(crate::sai::DmaB)), + (("sai", "A"), quote!(crate::sai::Dma)), + (("sai", "B"), quote!(crate::sai::Dma)), (("spi", "RX"), quote!(crate::spi::RxDma)), (("spi", "TX"), quote!(crate::spi::TxDma)), (("i2c", "RX"), quote!(crate::i2c::RxDma)), diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 96acd9e48..e03497529 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1,7 +1,10 @@ #![macro_use] +use core::marker::PhantomData; + use embassy_hal_internal::{into_ref, PeripheralRef}; +use self::sealed::WhichSubBlock; pub use crate::dma::word; use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; use crate::gpio::sealed::{AFType, Pin as _}; @@ -500,23 +503,10 @@ impl Default for Config { } impl Config { - pub fn new_i2s() -> Self { + /// Create a new config with all default values. + pub fn new() -> Self { return Default::default(); } - - pub fn new_msb_first() -> Self { - Self { - bit_order: BitOrder::MsbFirst, - frame_sync_offset: FrameSyncOffset::OnFirstBit, - ..Default::default() - } - } -} - -#[derive(Copy, Clone)] -enum WhichSubBlock { - A = 0, - B = 1, } enum RingBuffer<'d, C: Channel, W: word::Word> { @@ -530,28 +520,6 @@ fn dr(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut ch.dr().as_ptr() as _ } -pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> { - _peri: PeripheralRef<'d, T>, - sd: Option>, - fs: Option>, - sck: Option>, - mclk: Option>, - ring_buffer: RingBuffer<'d, C, W>, - sub_block: WhichSubBlock, -} - -pub struct SubBlockA {} -pub struct SubBlockB {} - -pub struct SubBlockAPeripheral<'d, T>(PeripheralRef<'d, T>); -pub struct SubBlockBPeripheral<'d, T>(PeripheralRef<'d, T>); - -pub struct Sai<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, - sub_block_a_peri: Option>, - sub_block_b_peri: Option>, -} - // return the type for (sd, sck) fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { ( @@ -590,34 +558,6 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( } } -impl<'d, T: Instance> Sai<'d, T> { - pub fn new(peri: impl Peripheral

+ 'd) -> Self { - T::enable_and_reset(); - - Self { - _peri: unsafe { peri.clone_unchecked().into_ref() }, - sub_block_a_peri: Some(SubBlockAPeripheral(unsafe { peri.clone_unchecked().into_ref() })), - sub_block_b_peri: Some(SubBlockBPeripheral(peri.into_ref())), - } - } - - pub fn take_sub_block_a(self: &mut Self) -> Option> { - if self.sub_block_a_peri.is_some() { - self.sub_block_a_peri.take() - } else { - None - } - } - - pub fn take_sub_block_b(self: &mut Self) -> Option> { - if self.sub_block_b_peri.is_some() { - self.sub_block_b_peri.take() - } else { - None - } - } -} - fn update_synchronous_config(config: &mut Config) { config.mode = Mode::Slave; config.sync_output = false; @@ -635,19 +575,51 @@ fn update_synchronous_config(config: &mut Config) { } } -impl SubBlockA { - pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockAPeripheral<'d, T>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - mclk: impl Peripheral

> + 'd, +pub struct SubBlock<'d, T, S: SubBlockInstance> { + peri: PeripheralRef<'d, T>, + _phantom: PhantomData, +} + +pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { + into_ref!(peri); + T::enable_and_reset(); + + ( + SubBlock { + peri: unsafe { peri.clone_unchecked() }, + _phantom: PhantomData, + }, + SubBlock { + peri, + _phantom: PhantomData, + }, + ) +} + +/// SAI sub-block driver +pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { + _peri: PeripheralRef<'d, T>, + sd: Option>, + fs: Option>, + sck: Option>, + mclk: Option>, + ring_buffer: RingBuffer<'d, C, W>, + sub_block: WhichSubBlock, +} + +impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { + pub fn new_asynchronous_with_mclk( + peri: SubBlock<'d, T, S>, + sck: impl Peripheral

> + 'd, + sd: impl Peripheral

> + 'd, + fs: impl Peripheral

> + 'd, + mclk: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> SubBlock<'d, T, C, W> + ) -> Self where - C: Channel + DmaA, + C: Channel + Dma, { into_ref!(mclk); @@ -663,19 +635,19 @@ impl SubBlockA { Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) } - pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockAPeripheral<'d, T>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, + pub fn new_asynchronous( + peri: SubBlock<'d, T, S>, + sck: impl Peripheral

> + 'd, + sd: impl Peripheral

> + 'd, + fs: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], config: Config, - ) -> SubBlock<'d, T, C, W> + ) -> Self where - C: Channel + DmaA, + C: Channel + Dma, { - let peri = peri.0; + let peri = peri.peri; into_ref!(peri, dma, sck, sd, fs); let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -687,10 +659,10 @@ impl SubBlockA { fs.set_as_af(fs.af_num(), ck_af_type); fs.set_speed(crate::gpio::Speed::VeryHigh); - let sub_block = WhichSubBlock::A; + let sub_block = S::WHICH; let request = dma.request(); - SubBlock::new_inner( + Self::new_inner( peri, sub_block, Some(sck.map_into()), @@ -702,19 +674,19 @@ impl SubBlockA { ) } - pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockAPeripheral<'d, T>, - sd: impl Peripheral

> + 'd, + pub fn new_synchronous( + peri: SubBlock<'d, T, S>, + sd: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> SubBlock<'d, T, C, W> + ) -> Self where - C: Channel + DmaA, + C: Channel + Dma, { update_synchronous_config(&mut config); - let peri = peri.0; + let peri = peri.peri; into_ref!(dma, peri, sd); let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -722,10 +694,10 @@ impl SubBlockA { sd.set_as_af(sd.af_num(), sd_af_type); sd.set_speed(crate::gpio::Speed::VeryHigh); - let sub_block = WhichSubBlock::A; + let sub_block = S::WHICH; let request = dma.request(); - SubBlock::new_inner( + Self::new_inner( peri, sub_block, None, @@ -736,129 +708,6 @@ impl SubBlockA { config, ) } -} - -impl SubBlockB { - pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockBPeripheral<'d, T>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - mclk: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - dma_buf: &'d mut [W], - mut config: Config, - ) -> SubBlock<'d, T, C, W> - where - C: Channel + DmaB, - { - into_ref!(mclk); - - let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); - - mclk.set_as_af(mclk.af_num(), ck_af_type); - mclk.set_speed(crate::gpio::Speed::VeryHigh); - - if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { - config.master_clock_divider = MasterClockDivider::Div1; - } - - Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) - } - - pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockBPeripheral<'d, T>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - dma_buf: &'d mut [W], - config: Config, - ) -> SubBlock<'d, T, C, W> - where - C: Channel + DmaB, - { - let peri = peri.0; - into_ref!(dma, peri, sck, sd, fs); - - let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); - - sd.set_as_af(sd.af_num(), sd_af_type); - sd.set_speed(crate::gpio::Speed::VeryHigh); - - sck.set_as_af(sck.af_num(), ck_af_type); - sck.set_speed(crate::gpio::Speed::VeryHigh); - fs.set_as_af(fs.af_num(), ck_af_type); - fs.set_speed(crate::gpio::Speed::VeryHigh); - - let sub_block = WhichSubBlock::B; - let request = dma.request(); - - SubBlock::new_inner( - peri, - sub_block, - Some(sck.map_into()), - None, - Some(sd.map_into()), - Some(fs.map_into()), - get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), - config, - ) - } - - pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockBPeripheral<'d, T>, - sd: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - dma_buf: &'d mut [W], - mut config: Config, - ) -> SubBlock<'d, T, C, W> - where - C: Channel + DmaB, - { - update_synchronous_config(&mut config); - let peri = peri.0; - into_ref!(dma, peri, sd); - - let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); - - sd.set_as_af(sd.af_num(), sd_af_type); - sd.set_speed(crate::gpio::Speed::VeryHigh); - - let sub_block = WhichSubBlock::B; - let request = dma.request(); - - SubBlock::new_inner( - peri, - sub_block, - None, - None, - Some(sd.map_into()), - None, - get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), - config, - ) - } -} - -impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { - pub fn start(self: &mut Self) { - match self.ring_buffer { - RingBuffer::Writable(ref mut rb) => { - rb.start(); - } - RingBuffer::Readable(ref mut rb) => { - rb.start(); - } - } - } - - fn is_transmitter(ring_buffer: &RingBuffer) -> bool { - match ring_buffer { - RingBuffer::Writable(_) => true, - _ => false, - } - } fn new_inner( peri: impl Peripheral

+ 'd, @@ -964,6 +813,24 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } } + pub fn start(&mut self) { + match self.ring_buffer { + RingBuffer::Writable(ref mut rb) => { + rb.start(); + } + RingBuffer::Readable(ref mut rb) => { + rb.start(); + } + } + } + + fn is_transmitter(ring_buffer: &RingBuffer) -> bool { + match ring_buffer { + RingBuffer::Writable(_) => true, + _ => false, + } + } + pub fn reset() { T::enable_and_reset(); } @@ -1008,7 +875,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } } -impl<'d, T: Instance, C: Channel, W: word::Word> Drop for SubBlock<'d, T, C, W> { +impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> { fn drop(&mut self) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); @@ -1025,22 +892,40 @@ pub(crate) mod sealed { pub trait Instance { const REGS: Regs; } + + #[derive(Copy, Clone)] + pub enum WhichSubBlock { + A = 0, + B = 1, + } + + pub trait SubBlock { + const WHICH: WhichSubBlock; + } } pub trait Word: word::Word {} -pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} -pin_trait!(SckAPin, Instance); -pin_trait!(SckBPin, Instance); -pin_trait!(FsAPin, Instance); -pin_trait!(FsBPin, Instance); -pin_trait!(SdAPin, Instance); -pin_trait!(SdBPin, Instance); -pin_trait!(MclkAPin, Instance); -pin_trait!(MclkBPin, Instance); +pub trait SubBlockInstance: sealed::SubBlock {} -dma_trait!(DmaA, Instance); -dma_trait!(DmaB, Instance); +pub enum A {} +impl sealed::SubBlock for A { + const WHICH: WhichSubBlock = WhichSubBlock::A; +} +impl SubBlockInstance for A {} +pub enum B {} +impl sealed::SubBlock for B { + const WHICH: WhichSubBlock = WhichSubBlock::B; +} +impl SubBlockInstance for B {} + +pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} +pin_trait!(SckPin, Instance, SubBlockInstance); +pin_trait!(FsPin, Instance, SubBlockInstance); +pin_trait!(SdPin, Instance, SubBlockInstance); +pin_trait!(MclkPin, Instance, SubBlockInstance); + +dma_trait!(Dma, Instance, SubBlockInstance); foreach_peripheral!( (sai, $inst:ident) => { diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs index b4166e71a..13f695821 100644 --- a/embassy-stm32/src/traits.rs +++ b/embassy-stm32/src/traits.rs @@ -1,18 +1,18 @@ #![macro_use] macro_rules! pin_trait { - ($signal:ident, $instance:path) => { + ($signal:ident, $instance:path $(, $mode:path)?) => { #[doc = concat!(stringify!($signal), " pin trait")] - pub trait $signal: crate::gpio::Pin { - #[doc = concat!("Get the AF number needed to use this pin as", stringify!($signal))] + pub trait $signal: crate::gpio::Pin { + #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))] fn af_num(&self) -> u8; } }; } macro_rules! pin_trait_impl { - (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, $af:expr) => { - impl crate::$mod::$trait for crate::peripherals::$pin { + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => { + impl crate::$mod::$trait for crate::peripherals::$pin { fn af_num(&self) -> u8 { $af } @@ -23,9 +23,9 @@ macro_rules! pin_trait_impl { // ==================== macro_rules! dma_trait { - ($signal:ident, $instance:path) => { + ($signal:ident, $instance:path$(, $mode:path)?) => { #[doc = concat!(stringify!($signal), " DMA request trait")] - pub trait $signal: crate::dma::Channel { + pub trait $signal: crate::dma::Channel { #[doc = concat!("Get the DMA request number needed to use this channel as", stringify!($signal))] /// Note: in some chips, ST calls this the "channel", and calls channels "streams". /// `embassy-stm32` always uses the "channel" and "request number" names. @@ -37,8 +37,8 @@ macro_rules! dma_trait { #[allow(unused)] macro_rules! dma_trait_impl { // DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { - impl crate::$mod::$trait for T + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { + impl crate::$mod::$trait for T where T: crate::dma::Channel + crate::dma::MuxChannel, { @@ -49,8 +49,8 @@ macro_rules! dma_trait_impl { }; // DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { - impl crate::$mod::$trait for T + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dma: $dma:ident}, $request:expr) => { + impl crate::$mod::$trait for T where T: crate::dma::Channel, { @@ -61,8 +61,8 @@ macro_rules! dma_trait_impl { }; // DMA/GPDMA, without DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { - impl crate::$mod::$trait for crate::peripherals::$channel { + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {channel: $channel:ident}, $request:expr) => { + impl crate::$mod::$trait for crate::peripherals::$channel { fn request(&self) -> crate::dma::Request { $request } From c45418787c03a348273591355a1e3e0362696e80 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 00:01:36 +0100 Subject: [PATCH 053/760] stm32/sai: remove unused Word trait. --- embassy-stm32/src/sai/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index e03497529..43c912157 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -904,8 +904,6 @@ pub(crate) mod sealed { } } -pub trait Word: word::Word {} - pub trait SubBlockInstance: sealed::SubBlock {} pub enum A {} From 138318f6118322af199888bcbd53ef49114f89bd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 00:02:19 +0100 Subject: [PATCH 054/760] stm32/sai: docs, remove unused enums. --- embassy-stm32/src/sai/mod.rs | 182 ++++++++++++++++++++--------------- 1 file changed, 104 insertions(+), 78 deletions(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 43c912157..af936bc7f 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1,3 +1,4 @@ +//! Serial Audio Interface (SAI) #![macro_use] use core::marker::PhantomData; @@ -13,48 +14,32 @@ use crate::pac::sai::{vals, Sai as Regs}; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; +/// SAI error #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// `write` called on a SAI in receive mode. NotATransmitter, + /// `read` called on a SAI in transmit mode. NotAReceiver, - OverrunError, + /// Overrun + Overrun, } impl From for Error { fn from(_: ringbuffer::OverrunError) -> Self { - Self::OverrunError + Self::Overrun } } +/// Master/slave mode. #[derive(Copy, Clone)] -pub enum SyncBlock { - None, - Sai1BlockA, - Sai1BlockB, - Sai2BlockA, - Sai2BlockB, -} - -#[derive(Copy, Clone)] -pub enum SyncIn { - None, - ChannelZero, - ChannelOne, -} - -#[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum Mode { Master, Slave, } -#[derive(Copy, Clone)] -pub enum TxRx { - Transmitter, - Receiver, -} - impl Mode { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] const fn mode(&self, tx_rx: TxRx) -> vals::Mode { @@ -71,7 +56,17 @@ impl Mode { } } +/// Direction: transmit or receive #[derive(Copy, Clone)] +#[allow(missing_docs)] +pub enum TxRx { + Transmitter, + Receiver, +} + +/// Data slot size. +#[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum SlotSize { DataSize, /// 16 bit data length on 16 bit wide channel @@ -82,7 +77,7 @@ pub enum SlotSize { impl SlotSize { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn slotsz(&self) -> vals::Slotsz { + const fn slotsz(&self) -> vals::Slotsz { match self { SlotSize::DataSize => vals::Slotsz::DATASIZE, SlotSize::Channel16 => vals::Slotsz::BIT16, @@ -91,7 +86,9 @@ impl SlotSize { } } +/// Data size. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum DataSize { Data8, Data10, @@ -103,7 +100,7 @@ pub enum DataSize { impl DataSize { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn ds(&self) -> vals::Ds { + const fn ds(&self) -> vals::Ds { match self { DataSize::Data8 => vals::Ds::BIT8, DataSize::Data10 => vals::Ds::BIT10, @@ -115,7 +112,9 @@ impl DataSize { } } +/// FIFO threshold level. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum FifoThreshold { Empty, Quarter, @@ -126,7 +125,7 @@ pub enum FifoThreshold { impl FifoThreshold { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn fth(&self) -> vals::Fth { + const fn fth(&self) -> vals::Fth { match self { FifoThreshold::Empty => vals::Fth::EMPTY, FifoThreshold::Quarter => vals::Fth::QUARTER1, @@ -137,38 +136,9 @@ impl FifoThreshold { } } +/// Output value on mute. #[derive(Copy, Clone)] -pub enum FifoLevel { - Empty, - FirstQuarter, - SecondQuarter, - ThirdQuarter, - FourthQuarter, - Full, -} - -#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] -impl From for FifoLevel { - fn from(flvl: vals::Flvl) -> Self { - match flvl { - vals::Flvl::EMPTY => FifoLevel::Empty, - vals::Flvl::QUARTER1 => FifoLevel::FirstQuarter, - vals::Flvl::QUARTER2 => FifoLevel::SecondQuarter, - vals::Flvl::QUARTER3 => FifoLevel::ThirdQuarter, - vals::Flvl::QUARTER4 => FifoLevel::FourthQuarter, - vals::Flvl::FULL => FifoLevel::Full, - _ => FifoLevel::Empty, - } - } -} - -#[derive(Copy, Clone)] -pub enum MuteDetection { - NoMute, - Mute, -} - -#[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum MuteValue { Zero, LastValue, @@ -176,7 +146,7 @@ pub enum MuteValue { impl MuteValue { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn muteval(&self) -> vals::Muteval { + const fn muteval(&self) -> vals::Muteval { match self { MuteValue::Zero => vals::Muteval::SENDZERO, MuteValue::LastValue => vals::Muteval::SENDLAST, @@ -184,13 +154,9 @@ impl MuteValue { } } +/// Protocol variant to use. #[derive(Copy, Clone)] -pub enum OverUnderStatus { - NoError, - OverUnderRunDetected, -} - -#[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum Protocol { Free, Spdif, @@ -199,7 +165,7 @@ pub enum Protocol { impl Protocol { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn prtcfg(&self) -> vals::Prtcfg { + const fn prtcfg(&self) -> vals::Prtcfg { match self { Protocol::Free => vals::Prtcfg::FREE, Protocol::Spdif => vals::Prtcfg::SPDIF, @@ -208,7 +174,9 @@ impl Protocol { } } +/// Sync input between SAI units/blocks. #[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] pub enum SyncInput { /// Not synced to any other SAI unit. None, @@ -220,7 +188,7 @@ pub enum SyncInput { } impl SyncInput { - pub const fn syncen(&self) -> vals::Syncen { + const fn syncen(&self) -> vals::Syncen { match self { SyncInput::None => vals::Syncen::ASYNCHRONOUS, SyncInput::Internal => vals::Syncen::INTERNAL, @@ -230,8 +198,10 @@ impl SyncInput { } } +/// SAI instance to sync from. #[cfg(sai_v4)] #[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] pub enum SyncInputInstance { #[cfg(peri_sai1)] Sai1 = 0, @@ -243,7 +213,9 @@ pub enum SyncInputInstance { Sai4 = 3, } +/// Channels (stereo or mono). #[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] pub enum StereoMono { Stereo, Mono, @@ -251,7 +223,7 @@ pub enum StereoMono { impl StereoMono { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn mono(&self) -> vals::Mono { + const fn mono(&self) -> vals::Mono { match self { StereoMono::Stereo => vals::Mono::STEREO, StereoMono::Mono => vals::Mono::MONO, @@ -259,15 +231,18 @@ impl StereoMono { } } +/// Bit order #[derive(Copy, Clone)] pub enum BitOrder { + /// Least significant bit first. LsbFirst, + /// Most significant bit first. MsbFirst, } impl BitOrder { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn lsbfirst(&self) -> vals::Lsbfirst { + const fn lsbfirst(&self) -> vals::Lsbfirst { match self { BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, @@ -275,6 +250,7 @@ impl BitOrder { } } +/// Frame sync offset. #[derive(Copy, Clone)] pub enum FrameSyncOffset { /// This is used in modes other than standard I2S phillips mode @@ -285,7 +261,7 @@ pub enum FrameSyncOffset { impl FrameSyncOffset { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn fsoff(&self) -> vals::Fsoff { + const fn fsoff(&self) -> vals::Fsoff { match self { FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, @@ -293,15 +269,18 @@ impl FrameSyncOffset { } } +/// Frame sync polarity #[derive(Copy, Clone)] pub enum FrameSyncPolarity { + /// Sync signal is active low. ActiveLow, + /// Sync signal is active high ActiveHigh, } impl FrameSyncPolarity { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn fspol(&self) -> vals::Fspol { + const fn fspol(&self) -> vals::Fspol { match self { FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, @@ -309,7 +288,9 @@ impl FrameSyncPolarity { } } +/// Sync definition. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum FrameSyncDefinition { StartOfFrame, ChannelIdentification, @@ -317,7 +298,7 @@ pub enum FrameSyncDefinition { impl FrameSyncDefinition { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn fsdef(&self) -> bool { + const fn fsdef(&self) -> bool { match self { FrameSyncDefinition::StartOfFrame => false, FrameSyncDefinition::ChannelIdentification => true, @@ -325,7 +306,9 @@ impl FrameSyncDefinition { } } +/// Clock strobe. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum ClockStrobe { Falling, Rising, @@ -333,7 +316,7 @@ pub enum ClockStrobe { impl ClockStrobe { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn ckstr(&self) -> vals::Ckstr { + const fn ckstr(&self) -> vals::Ckstr { match self { ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, @@ -341,7 +324,9 @@ impl ClockStrobe { } } +/// Complements format for negative samples. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum ComplementFormat { OnesComplement, TwosComplement, @@ -349,7 +334,7 @@ pub enum ComplementFormat { impl ComplementFormat { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn cpl(&self) -> vals::Cpl { + const fn cpl(&self) -> vals::Cpl { match self { ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, @@ -357,7 +342,9 @@ impl ComplementFormat { } } +/// Companding setting. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum Companding { None, MuLaw, @@ -366,7 +353,7 @@ pub enum Companding { impl Companding { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn comp(&self) -> vals::Comp { + const fn comp(&self) -> vals::Comp { match self { Companding::None => vals::Comp::NOCOMPANDING, Companding::MuLaw => vals::Comp::MULAW, @@ -375,7 +362,9 @@ impl Companding { } } +/// Output drive #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum OutputDrive { OnStart, Immediately, @@ -383,7 +372,7 @@ pub enum OutputDrive { impl OutputDrive { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn outdriv(&self) -> vals::Outdriv { + const fn outdriv(&self) -> vals::Outdriv { match self { OutputDrive::OnStart => vals::Outdriv::ONSTART, OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, @@ -391,7 +380,9 @@ impl OutputDrive { } } +/// Master clock divider. #[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] pub enum MasterClockDivider { MasterClockDisabled, Div1, @@ -414,7 +405,7 @@ pub enum MasterClockDivider { impl MasterClockDivider { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn mckdiv(&self) -> u8 { + const fn mckdiv(&self) -> u8 { match self { MasterClockDivider::MasterClockDisabled => 0, MasterClockDivider::Div1 => 0, @@ -438,6 +429,7 @@ impl MasterClockDivider { } /// [`SAI`] configuration. +#[allow(missing_docs)] #[non_exhaustive] #[derive(Copy, Clone)] pub struct Config { @@ -575,11 +567,15 @@ fn update_synchronous_config(config: &mut Config) { } } +/// SAI subblock instance. pub struct SubBlock<'d, T, S: SubBlockInstance> { peri: PeripheralRef<'d, T>, _phantom: PhantomData, } +/// Split the main SAIx peripheral into the two subblocks. +/// +/// You can then create a [`Sai`] driver for each each half. pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { into_ref!(peri); T::enable_and_reset(); @@ -596,7 +592,7 @@ pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (S ) } -/// SAI sub-block driver +/// SAI sub-block driver. pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { _peri: PeripheralRef<'d, T>, sd: Option>, @@ -608,6 +604,9 @@ pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { } impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { + /// Create a new SAI driver in asynchronous mode with MCLK. + /// + /// You can obtain the [`SubBlock`] with [`split_subblocks`]. pub fn new_asynchronous_with_mclk( peri: SubBlock<'d, T, S>, sck: impl Peripheral

> + 'd, @@ -635,6 +634,9 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) } + /// Create a new SAI driver in asynchronous mode without MCLK. + /// + /// You can obtain the [`SubBlock`] with [`split_subblocks`]. pub fn new_asynchronous( peri: SubBlock<'d, T, S>, sck: impl Peripheral

> + 'd, @@ -674,6 +676,9 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { ) } + /// Create a new SAI driver in synchronous mode. + /// + /// You can obtain the [`SubBlock`] with [`split_subblocks`]. pub fn new_synchronous( peri: SubBlock<'d, T, S>, sd: impl Peripheral

> + 'd, @@ -813,6 +818,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { } } + /// Start the SAI driver. pub fn start(&mut self) { match self.ring_buffer { RingBuffer::Writable(ref mut rb) => { @@ -831,10 +837,12 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { } } + /// Reset SAI operation. pub fn reset() { T::enable_and_reset(); } + /// Flush. pub fn flush(&mut self) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); @@ -849,11 +857,18 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { ch.cr1().modify(|w| w.set_saien(true)); } + /// Enable or disable mute. pub fn set_mute(&mut self, value: bool) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr2().modify(|w| w.set_mute(value)); } + /// Write data to the SAI ringbuffer. + /// + /// This appends the data to the buffer and returns immediately. The + /// data will be transmitted in the background. + /// + /// If there's no space in the buffer, this waits until there is. pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { match &mut self.ring_buffer { RingBuffer::Writable(buffer) => { @@ -864,6 +879,12 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { } } + /// Read data from the SAI ringbuffer. + /// + /// SAI is always receiving data in the background. This function pops already-received + /// data from the buffer. + /// + /// If there's less than `data.len()` data in the buffer, this waits until there is. pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { match &mut self.ring_buffer { RingBuffer::Readable(buffer) => { @@ -904,19 +925,24 @@ pub(crate) mod sealed { } } +/// Sub-block instance trait. pub trait SubBlockInstance: sealed::SubBlock {} +/// Sub-block A. pub enum A {} impl sealed::SubBlock for A { const WHICH: WhichSubBlock = WhichSubBlock::A; } impl SubBlockInstance for A {} + +/// Sub-block B. pub enum B {} impl sealed::SubBlock for B { const WHICH: WhichSubBlock = WhichSubBlock::B; } impl SubBlockInstance for B {} +/// SAI instance trait. pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} pin_trait!(SckPin, Instance, SubBlockInstance); pin_trait!(FsPin, Instance, SubBlockInstance); From 49534cd4056f20bdf5fa6058b0865afc5fcf38ee Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 00:05:54 +0100 Subject: [PATCH 055/760] stm32: more docs. --- embassy-nrf/src/lib.rs | 6 +++++- embassy-stm32/src/adc/mod.rs | 3 ++- embassy-stm32/src/can/mod.rs | 1 + embassy-stm32/src/crc/mod.rs | 1 + embassy-stm32/src/dac/mod.rs | 2 +- embassy-stm32/src/dcmi.rs | 1 + embassy-stm32/src/eth/mod.rs | 1 + embassy-stm32/src/exti.rs | 1 + embassy-stm32/src/flash/mod.rs | 1 + embassy-stm32/src/fmc.rs | 1 + embassy-stm32/src/hrtim/mod.rs | 2 ++ embassy-stm32/src/i2c/mod.rs | 1 + embassy-stm32/src/i2s.rs | 1 + embassy-stm32/src/lib.rs | 24 +++++++++++++++++++++++- embassy-stm32/src/qspi/mod.rs | 2 ++ embassy-stm32/src/rng.rs | 1 + embassy-stm32/src/rtc/mod.rs | 4 ++-- embassy-stm32/src/sdmmc/mod.rs | 1 + embassy-stm32/src/spi/mod.rs | 1 + embassy-stm32/src/uid.rs | 2 ++ embassy-stm32/src/usart/mod.rs | 1 + embassy-stm32/src/usb_otg/mod.rs | 2 ++ embassy-stm32/src/wdg/mod.rs | 1 + 23 files changed, 55 insertions(+), 6 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 9093ad919..e3458e2de 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -354,7 +354,11 @@ unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteRe WriteResult::Written } -/// Initialize peripherals with the provided configuration. This should only be called once at startup. +/// Initialize the `embassy-nrf` HAL with the provided configuration. +/// +/// This returns the peripheral singletons that can be used for creating drivers. +/// +/// This should only be called once at startup, otherwise it panics. pub fn init(config: config::Config) -> Peripherals { // Do this first, so that it panics if user is calling `init` a second time // before doing anything important. diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index ff523ca3b..e4dd35c34 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,4 +1,5 @@ -//! Analog to Digital (ADC) converter driver. +//! Analog to Digital Converter (ADC) + #![macro_use] #![allow(missing_docs)] // TODO diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs index 425f9ac2e..915edb3a6 100644 --- a/embassy-stm32/src/can/mod.rs +++ b/embassy-stm32/src/can/mod.rs @@ -1,3 +1,4 @@ +//! Controller Area Network (CAN) #![macro_use] #[cfg_attr(can_bxcan, path = "bxcan.rs")] diff --git a/embassy-stm32/src/crc/mod.rs b/embassy-stm32/src/crc/mod.rs index 63f7ad9ba..29523b92d 100644 --- a/embassy-stm32/src/crc/mod.rs +++ b/embassy-stm32/src/crc/mod.rs @@ -1,3 +1,4 @@ +//! Cyclic Redundancy Check (CRC) #[cfg_attr(crc_v1, path = "v1.rs")] #[cfg_attr(crc_v2, path = "v2v3.rs")] #[cfg_attr(crc_v3, path = "v2v3.rs")] diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 9c670195d..31dedf06e 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -1,4 +1,4 @@ -//! Provide access to the STM32 digital-to-analog converter (DAC). +//! Digital to Analog Converter (DAC) #![macro_use] use core::marker::PhantomData; diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 139d8fd1b..4d02284b2 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -1,3 +1,4 @@ +//! Digital Camera Interface (DCMI) use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index dbf91eedc..448405507 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -1,3 +1,4 @@ +//! Ethernet (ETH) #![macro_use] #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 371be913e..f83bae3ff 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -1,3 +1,4 @@ +//! External Interrupts (EXTI) use core::convert::Infallible; use core::future::Future; use core::marker::PhantomData; diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 6b6b4d41c..cbf5c25b2 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,3 +1,4 @@ +//! Flash memory (FLASH) use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; #[cfg(flash_f4)] diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 23ac82f63..873c8a70c 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -1,3 +1,4 @@ +//! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC) use core::marker::PhantomData; use embassy_hal_internal::into_ref; diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 17096d48c..6539326b4 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -1,3 +1,5 @@ +//! High Resolution Timer (HRTIM) + mod traits; use core::marker::PhantomData; diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 0af291e9c..9b0b35eca 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -1,3 +1,4 @@ +//! Inter-Integrated-Circuit (I2C) #![macro_use] #[cfg_attr(i2c_v1, path = "v1.rs")] diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 372c86db3..1f85c0bc5 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -1,3 +1,4 @@ +//! Inter-IC Sound (I2S) use embassy_hal_internal::into_ref; use crate::gpio::sealed::{AFType, Pin as _}; diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 5d9b4e6a0..fd691a732 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -149,15 +149,33 @@ use crate::interrupt::Priority; pub use crate::pac::NVIC_PRIO_BITS; use crate::rcc::sealed::RccPeripheral; +/// `embassy-stm32` global configuration. #[non_exhaustive] pub struct Config { + /// RCC config. pub rcc: rcc::Config, + + /// Enable debug during sleep. + /// + /// May incrase power consumption. Defaults to true. #[cfg(dbgmcu)] pub enable_debug_during_sleep: bool, + + /// BDMA interrupt priority. + /// + /// Defaults to P0 (highest). #[cfg(bdma)] pub bdma_interrupt_priority: Priority, + + /// DMA interrupt priority. + /// + /// Defaults to P0 (highest). #[cfg(dma)] pub dma_interrupt_priority: Priority, + + /// GPDMA interrupt priority. + /// + /// Defaults to P0 (highest). #[cfg(gpdma)] pub gpdma_interrupt_priority: Priority, } @@ -178,7 +196,11 @@ impl Default for Config { } } -/// Initialize embassy. +/// Initialize the `embassy-stm32` HAL with the provided configuration. +/// +/// This returns the peripheral singletons that can be used for creating drivers. +/// +/// This should only be called once at startup, otherwise it panics. pub fn init(config: Config) -> Peripherals { critical_section::with(|cs| { let p = Peripherals::take_with_cs(cs); diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index bac91f300..9ea0a726c 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -1,3 +1,5 @@ +//! Quad Serial Peripheral Interface (QSPI) + #![macro_use] pub mod enums; diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index b2196b0d5..6ee89a922 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -1,3 +1,4 @@ +//! Random Number Generator (RNG) #![macro_use] use core::future::poll_fn; diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index fa359cdae..11b252139 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -1,4 +1,4 @@ -//! RTC peripheral abstraction +//! Real Time Clock (RTC) mod datetime; #[cfg(feature = "low-power")] @@ -163,7 +163,7 @@ impl RtcTimeProvider { } } -/// RTC Abstraction +/// RTC driver. pub struct Rtc { #[cfg(feature = "low-power")] stop_time: Mutex>>, diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 27a12062c..6099b9f43 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1,3 +1,4 @@ +//! Secure Digital / MultiMedia Card (SDMMC) #![macro_use] use core::default::Default; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 92599c75e..5a1ad3e91 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -1,3 +1,4 @@ +//! Serial Peripheral Interface (SPI) #![macro_use] use core::ptr; diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs index 6dcfcb96e..aa13586f8 100644 --- a/embassy-stm32/src/uid.rs +++ b/embassy-stm32/src/uid.rs @@ -1,3 +1,5 @@ +//! Unique ID (UID) + /// Get this device's unique 96-bit ID. pub fn uid() -> &'static [u8; 12] { unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index dfa1f3a6a..e2e3bd3eb 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,3 +1,4 @@ +//! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART) #![macro_use] use core::future::poll_fn; diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs index be54a3d10..1abd031dd 100644 --- a/embassy-stm32/src/usb_otg/mod.rs +++ b/embassy-stm32/src/usb_otg/mod.rs @@ -1,3 +1,5 @@ +//! USB On The Go (OTG) + use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals}; diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index c7c2694e0..5751a9ff3 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -1,3 +1,4 @@ +//! Watchdog Timer (IWDG, WWDG) use core::marker::PhantomData; use embassy_hal_internal::{into_ref, Peripheral}; From e1f588f520c76c6f08a01b2d61c0e980401c19f1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 00:36:50 +0100 Subject: [PATCH 056/760] stm32/sai: fix typo. --- embassy-stm32/src/sai/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index af936bc7f..ef8802184 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -453,7 +453,7 @@ pub struct Config { pub clock_strobe: ClockStrobe, pub output_drive: OutputDrive, pub master_clock_divider: MasterClockDivider, - pub is_high_impedenane_on_inactive_slot: bool, + pub is_high_impedance_on_inactive_slot: bool, pub fifo_threshold: FifoThreshold, pub companding: Companding, pub complement_format: ComplementFormat, @@ -484,7 +484,7 @@ impl Default for Config { master_clock_divider: MasterClockDivider::MasterClockDisabled, clock_strobe: ClockStrobe::Rising, output_drive: OutputDrive::Immediately, - is_high_impedenane_on_inactive_slot: false, + is_high_impedance_on_inactive_slot: false, fifo_threshold: FifoThreshold::ThreeQuarters, companding: Companding::None, complement_format: ComplementFormat::TwosComplement, @@ -782,7 +782,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { w.set_cpl(config.complement_format.cpl()); w.set_muteval(config.mute_value.muteval()); w.set_mutecnt(config.mute_detection_counter.0 as u8); - w.set_tris(config.is_high_impedenane_on_inactive_slot); + w.set_tris(config.is_high_impedance_on_inactive_slot); }); ch.frcr().modify(|w| { From 254d5873855535b97f29592b369f5b2ae3097880 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 19 Dec 2023 17:12:34 +0800 Subject: [PATCH 057/760] match up with metapac change --- embassy-stm32/src/dma/bdma.rs | 20 +++++++------------- embassy-stm32/src/dma/dma.rs | 27 +++++++++++---------------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 5102330c0..2f37b1edf 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -303,20 +303,14 @@ impl<'a, C: Channel> Transfer<'a, C> { ch.cr().write(|w| { w.set_psize(data_size.into()); w.set_msize(data_size.into()); - if incr_mem { - w.set_minc(vals::Inc::ENABLED); - } else { - w.set_minc(vals::Inc::DISABLED); - } + w.set_minc(incr_mem); w.set_dir(dir.into()); w.set_teie(true); w.set_tcie(options.complete_transfer_ir); w.set_htie(options.half_transfer_ir); + w.set_circ(options.circular); if options.circular { - w.set_circ(vals::Circ::ENABLED); debug!("Setting circular mode"); - } else { - w.set_circ(vals::Circ::DISABLED); } w.set_pl(vals::Pl::VERYHIGH); w.set_en(true); @@ -352,7 +346,7 @@ impl<'a, C: Channel> Transfer<'a, C> { pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().ch(self.channel.num()); let en = ch.cr().read().en(); - let circular = ch.cr().read().circ() == vals::Circ::ENABLED; + let circular = ch.cr().read().circ(); let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; en && (circular || !tcif) } @@ -467,12 +461,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { let mut w = regs::Cr(0); w.set_psize(data_size.into()); w.set_msize(data_size.into()); - w.set_minc(vals::Inc::ENABLED); + w.set_minc(true); w.set_dir(dir.into()); w.set_teie(true); w.set_htie(true); w.set_tcie(true); - w.set_circ(vals::Circ::ENABLED); + w.set_circ(true); w.set_pl(vals::Pl::VERYHIGH); w.set_en(true); @@ -625,12 +619,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { let mut w = regs::Cr(0); w.set_psize(data_size.into()); w.set_msize(data_size.into()); - w.set_minc(vals::Inc::ENABLED); + w.set_minc(true); w.set_dir(dir.into()); w.set_teie(true); w.set_htie(true); w.set_tcie(true); - w.set_circ(vals::Circ::ENABLED); + w.set_circ(true); w.set_pl(vals::Pl::VERYHIGH); w.set_en(true); diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 64e492c10..9b47ca5c3 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -382,18 +382,13 @@ impl<'a, C: Channel> Transfer<'a, C> { w.set_msize(data_size.into()); w.set_psize(data_size.into()); w.set_pl(vals::Pl::VERYHIGH); - w.set_minc(match incr_mem { - true => vals::Inc::INCREMENTED, - false => vals::Inc::FIXED, - }); - w.set_pinc(vals::Inc::FIXED); + w.set_minc(incr_mem); + w.set_pinc(false); w.set_teie(true); w.set_tcie(options.complete_transfer_ir); + w.set_circ(options.circular); if options.circular { - w.set_circ(vals::Circ::ENABLED); debug!("Setting circular mode"); - } else { - w.set_circ(vals::Circ::DISABLED); } #[cfg(dma_v1)] w.set_trbuff(true); @@ -545,8 +540,8 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { w.set_msize(data_size.into()); w.set_psize(data_size.into()); w.set_pl(vals::Pl::VERYHIGH); - w.set_minc(vals::Inc::INCREMENTED); - w.set_pinc(vals::Inc::FIXED); + w.set_minc(true); + w.set_pinc(false); w.set_teie(true); w.set_tcie(true); #[cfg(dma_v1)] @@ -703,12 +698,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { w.set_msize(data_size.into()); w.set_psize(data_size.into()); w.set_pl(vals::Pl::VERYHIGH); - w.set_minc(vals::Inc::INCREMENTED); - w.set_pinc(vals::Inc::FIXED); + w.set_minc(true); + w.set_pinc(false); w.set_teie(true); w.set_htie(options.half_transfer_ir); w.set_tcie(true); - w.set_circ(vals::Circ::ENABLED); + w.set_circ(true); #[cfg(dma_v1)] w.set_trbuff(true); #[cfg(dma_v2)] @@ -878,12 +873,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { w.set_msize(data_size.into()); w.set_psize(data_size.into()); w.set_pl(vals::Pl::VERYHIGH); - w.set_minc(vals::Inc::INCREMENTED); - w.set_pinc(vals::Inc::FIXED); + w.set_minc(true); + w.set_pinc(false); w.set_teie(true); w.set_htie(options.half_transfer_ir); w.set_tcie(true); - w.set_circ(vals::Circ::ENABLED); + w.set_circ(true); #[cfg(dma_v1)] w.set_trbuff(true); #[cfg(dma_v2)] From fc724dd7075fd833bac3f2a25a96aac76a771ec3 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 19 Dec 2023 11:48:58 +0200 Subject: [PATCH 058/760] stm32: i2c: Clean up conditional code a bit By moving conditional code inside the functions, we can reduce duplication and in one case we can even eliminate one... --- embassy-stm32/src/i2c/mod.rs | 37 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 9b0b35eca..2416005b5 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -148,38 +148,31 @@ struct Timeout { #[allow(dead_code)] impl Timeout { - #[cfg(not(feature = "time"))] #[inline] fn check(self) -> Result<(), Error> { + #[cfg(feature = "time")] + if Instant::now() > self.deadline { + return Err(Error::Timeout); + } + Ok(()) } - #[cfg(feature = "time")] #[inline] - fn check(self) -> Result<(), Error> { - if Instant::now() > self.deadline { - Err(Error::Timeout) - } else { - Ok(()) + fn with(self, fut: impl Future>) -> impl Future> { + #[cfg(feature = "time")] + { + use futures::FutureExt; + + embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r { + embassy_futures::select::Either::First(_) => Err(Error::Timeout), + embassy_futures::select::Either::Second(r) => r, + }) } - } - #[cfg(not(feature = "time"))] - #[inline] - fn with(self, fut: impl Future>) -> impl Future> { + #[cfg(not(feature = "time"))] fut } - - #[cfg(feature = "time")] - #[inline] - fn with(self, fut: impl Future>) -> impl Future> { - use futures::FutureExt; - - embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r { - embassy_futures::select::Either::First(_) => Err(Error::Timeout), - embassy_futures::select::Either::Second(r) => r, - }) - } } pub(crate) mod sealed { From e45e3e76b564b0589a24c1ca56599640238fd672 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 10:11:19 +0100 Subject: [PATCH 059/760] docs: embassy-rp rustdoc and refactoring --- cyw43-pio/src/lib.rs | 20 +-- embassy-nrf/README.md | 2 + embassy-rp/README.md | 23 +++ embassy-rp/src/clocks.rs | 26 +++ embassy-rp/src/lib.rs | 12 +- .../src/{pio_instr_util.rs => pio/instr.rs} | 11 ++ embassy-rp/src/{pio.rs => pio/mod.rs} | 151 ++++++++++++++++-- embassy-rp/src/uart/buffered.rs | 20 +++ embassy-rp/src/uart/mod.rs | 4 + embassy-rp/src/usb.rs | 10 ++ 10 files changed, 253 insertions(+), 26 deletions(-) create mode 100644 embassy-rp/README.md rename embassy-rp/src/{pio_instr_util.rs => pio/instr.rs} (86%) rename embassy-rp/src/{pio.rs => pio/mod.rs} (85%) diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 41b670324..8304740b3 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -6,8 +6,8 @@ use core::slice; use cyw43::SpiBusCyw43; use embassy_rp::dma::Channel; use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate}; -use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::{pio_instr_util, Peripheral, PeripheralRef}; +use embassy_rp::pio::{instr, Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::{Peripheral, PeripheralRef}; use fixed::FixedU32; use pio_proc::pio_asm; @@ -152,10 +152,10 @@ where defmt::trace!("write={} read={}", write_bits, read_bits); unsafe { - pio_instr_util::set_x(&mut self.sm, write_bits as u32); - pio_instr_util::set_y(&mut self.sm, read_bits as u32); - pio_instr_util::set_pindir(&mut self.sm, 0b1); - pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target); + instr::set_x(&mut self.sm, write_bits as u32); + instr::set_y(&mut self.sm, read_bits as u32); + instr::set_pindir(&mut self.sm, 0b1); + instr::exec_jmp(&mut self.sm, self.wrap_target); } self.sm.set_enable(true); @@ -179,10 +179,10 @@ where defmt::trace!("write={} read={}", write_bits, read_bits); unsafe { - pio_instr_util::set_y(&mut self.sm, read_bits as u32); - pio_instr_util::set_x(&mut self.sm, write_bits as u32); - pio_instr_util::set_pindir(&mut self.sm, 0b1); - pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target); + instr::set_y(&mut self.sm, read_bits as u32); + instr::set_x(&mut self.sm, write_bits as u32); + instr::set_pindir(&mut self.sm, 0b1); + instr::exec_jmp(&mut self.sm, self.wrap_target); } // self.cs.set_low(); diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md index 129ec0c01..39de3854b 100644 --- a/embassy-nrf/README.md +++ b/embassy-nrf/README.md @@ -6,6 +6,8 @@ The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to complete operations in low power mod and handling interrupts, so that applications can focus on more important matters. +NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use. + ## EasyDMA considerations On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting diff --git a/embassy-rp/README.md b/embassy-rp/README.md new file mode 100644 index 000000000..cd79fe501 --- /dev/null +++ b/embassy-rp/README.md @@ -0,0 +1,23 @@ +# Embassy RP HAL + +HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. + +The Embassy RP HAL targets the Raspberry Pi 2040 family of hardware. The HAL implements both blocking and async APIs +for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to +complete operations in low power mod and handling interrupts, so that applications can focus on more important matters. + +NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use. + +## Minimum supported Rust version (MSRV) + +Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 220665462..2f0645615 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1,3 +1,4 @@ +//! Clock configuration for the RP2040 use core::arch::asm; use core::marker::PhantomData; use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; @@ -44,6 +45,7 @@ static CLOCKS: Clocks = Clocks { rtc: AtomicU16::new(0), }; +/// Enumeration of supported clock sources. #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -57,15 +59,24 @@ pub enum PeriClkSrc { // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , } +/// CLock configuration. #[non_exhaustive] pub struct ClockConfig { + /// Ring oscillator configuration. pub rosc: Option, + /// External oscillator configuration. pub xosc: Option, + /// Reference clock configuration. pub ref_clk: RefClkConfig, + /// System clock configuration. pub sys_clk: SysClkConfig, + /// Peripheral clock source configuration. pub peri_clk_src: Option, + /// USB clock configuration. pub usb_clk: Option, + /// ADC clock configuration. pub adc_clk: Option, + /// RTC clock configuration. pub rtc_clk: Option, // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, @@ -189,31 +200,46 @@ pub enum RoscRange { TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0, } +/// On-chip ring oscillator configuration. pub struct RoscConfig { /// Final frequency of the oscillator, after the divider has been applied. /// The oscillator has a nominal frequency of 6.5MHz at medium range with /// divider 16 and all drive strengths set to 0, other values should be /// measured in situ. pub hz: u32, + /// Oscillator range. pub range: RoscRange, + /// Drive strength for oscillator. pub drive_strength: [u8; 8], + /// Output divider. pub div: u16, } +/// Crystal oscillator configuration. pub struct XoscConfig { + /// Final frequency of the oscillator. pub hz: u32, + /// Configuring PLL for the system clock. pub sys_pll: Option, + /// Configuring PLL for the USB clock. pub usb_pll: Option, + /// Multiplier for the startup delay. pub delay_multiplier: u32, } +/// PLL configuration. pub struct PllConfig { + /// Reference divisor. pub refdiv: u8, + /// Feedback divisor. pub fbdiv: u16, + /// Output divisor 1. pub post_div1: u8, + /// Output divisor 2. pub post_div2: u8, } +/// Reference pub struct RefClkConfig { pub src: RefClkSrc, pub div: u8, diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 5151323a9..2c49787df 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![doc = include_str!("../README.md")] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -31,9 +32,7 @@ pub mod usb; pub mod watchdog; // PIO -// TODO: move `pio_instr_util` and `relocate` to inside `pio` pub mod pio; -pub mod pio_instr_util; pub(crate) mod relocate; // Reexports @@ -302,11 +301,14 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) } +/// HAL configuration for RP. pub mod config { use crate::clocks::ClockConfig; + /// HAL configuration passed when initializing. #[non_exhaustive] pub struct Config { + /// Clock configuration. pub clocks: ClockConfig, } @@ -319,12 +321,18 @@ pub mod config { } impl Config { + /// Create a new configuration with the provided clock config. pub fn new(clocks: ClockConfig) -> Self { Self { clocks } } } } +/// Initialize the `embassy-rp` HAL with the provided configuration. +/// +/// This returns the peripheral singletons that can be used for creating drivers. +/// +/// This should only be called once at startup, otherwise it panics. pub fn init(config: config::Config) -> Peripherals { // Do this first, so that it panics if user is calling `init` a second time // before doing anything important. diff --git a/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio/instr.rs similarity index 86% rename from embassy-rp/src/pio_instr_util.rs rename to embassy-rp/src/pio/instr.rs index 25393b476..9a44088c6 100644 --- a/embassy-rp/src/pio_instr_util.rs +++ b/embassy-rp/src/pio/instr.rs @@ -1,7 +1,9 @@ +//! Instructions controlling the PIO. use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination}; use crate::pio::{Instance, StateMachine}; +/// Set value of scratch register X. pub unsafe fn set_x(sm: &mut StateMachine, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::X, @@ -12,6 +14,7 @@ pub unsafe fn set_x(sm: &mut StateMachine(sm: &mut StateMachine) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::X, @@ -22,6 +25,7 @@ pub unsafe fn get_x(sm: &mut StateMachine(sm: &mut StateMachine, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::Y, @@ -32,6 +36,7 @@ pub unsafe fn set_y(sm: &mut StateMachine(sm: &mut StateMachine) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::Y, @@ -43,6 +48,7 @@ pub unsafe fn get_y(sm: &mut StateMachine(sm: &mut StateMachine, data: u8) { let set: u16 = InstructionOperands::SET { destination: SetDestination::PINDIRS, @@ -52,6 +58,7 @@ pub unsafe fn set_pindir(sm: &mut StateMachine

(sm: &mut StateMachine, data: u8) { let set: u16 = InstructionOperands::SET { destination: SetDestination::PINS, @@ -61,6 +68,7 @@ pub unsafe fn set_pin(sm: &mut StateMachine(sm: &mut StateMachine, data: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::PINS, @@ -70,6 +78,8 @@ pub unsafe fn set_out_pin(sm: &mut StateMachine< sm.tx().push(data); sm.exec_instr(OUT); } + +/// Out instruction for pindir destination. pub unsafe fn set_out_pindir(sm: &mut StateMachine, data: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::PINDIRS, @@ -80,6 +90,7 @@ pub unsafe fn set_out_pindir(sm: &mut StateMachi sm.exec_instr(OUT); } +/// Jump instruction to address. pub unsafe fn exec_jmp(sm: &mut StateMachine, to_addr: u8) { let jmp: u16 = InstructionOperands::JMP { address: to_addr, diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio/mod.rs similarity index 85% rename from embassy-rp/src/pio.rs rename to embassy-rp/src/pio/mod.rs index 97dfce2e6..ae91d1e83 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio/mod.rs @@ -19,8 +19,11 @@ use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate}; use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; use crate::pac::dma::vals::TreqSel; use crate::relocate::RelocatedProgram; -use crate::{pac, peripherals, pio_instr_util, RegExt}; +use crate::{pac, peripherals, RegExt}; +pub mod instr; + +/// Wakers for interrupts and FIFOs. pub struct Wakers([AtomicWaker; 12]); impl Wakers { @@ -38,6 +41,7 @@ impl Wakers { } } +/// FIFO config. #[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] @@ -51,6 +55,8 @@ pub enum FifoJoin { TxOnly, } +/// Shift direction. +#[allow(missing_docs)] #[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] @@ -60,6 +66,8 @@ pub enum ShiftDirection { Left = 0, } +/// Pin direction. +#[allow(missing_docs)] #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] @@ -68,12 +76,15 @@ pub enum Direction { Out = 1, } +/// Which fifo level to use in status check. #[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum StatusSource { #[default] + /// All-ones if TX FIFO level < N, otherwise all-zeroes. TxFifoLevel = 0, + /// All-ones if RX FIFO level < N, otherwise all-zeroes. RxFifoLevel = 1, } @@ -81,6 +92,7 @@ const RXNEMPTY_MASK: u32 = 1 << 0; const TXNFULL_MASK: u32 = 1 << 4; const SMIRQ_MASK: u32 = 1 << 8; +/// Interrupt handler for PIO. pub struct InterruptHandler { _pio: PhantomData, } @@ -105,6 +117,7 @@ pub struct FifoOutFuture<'a, 'd, PIO: Instance, const SM: usize> { } impl<'a, 'd, PIO: Instance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> { + /// Create a new future waiting for TX-FIFO to become writable. pub fn new(sm: &'a mut StateMachineTx<'d, PIO, SM>, value: u32) -> Self { FifoOutFuture { sm_tx: sm, value } } @@ -136,13 +149,14 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, } } -/// Future that waits for RX-FIFO to become readable +/// Future that waits for RX-FIFO to become readable. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct FifoInFuture<'a, 'd, PIO: Instance, const SM: usize> { sm_rx: &'a mut StateMachineRx<'d, PIO, SM>, } impl<'a, 'd, PIO: Instance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> { + /// Create future that waits for RX-FIFO to become readable. pub fn new(sm: &'a mut StateMachineRx<'d, PIO, SM>) -> Self { FifoInFuture { sm_rx: sm } } @@ -207,6 +221,7 @@ impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { } } +/// Type representing a PIO pin. pub struct Pin<'l, PIO: Instance> { pin: PeripheralRef<'l, AnyPin>, pio: PhantomData, @@ -226,7 +241,7 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { }); } - // Set the pin's slew rate. + /// Set the pin's slew rate. #[inline] pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { self.pin.pad_ctrl().modify(|w| { @@ -251,6 +266,7 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { }); } + /// Set the pin's input sync bypass. pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { let mask = 1 << self.pin(); if bypass { @@ -260,28 +276,34 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { } } + /// Get the underlying pin number. pub fn pin(&self) -> u8 { self.pin._pin() } } +/// Type representing a state machine RX FIFO. pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> { pio: PhantomData<&'d mut PIO>, } impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { + /// Check if RX FIFO is empty. pub fn empty(&self) -> bool { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } + /// Check if RX FIFO is full. pub fn full(&self) -> bool { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } + /// Check RX FIFO level. pub fn level(&self) -> u8 { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f } + /// Check if state machine has stalled on full RX FIFO. pub fn stalled(&self) -> bool { let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().rxstall() & (1 << SM) != 0; @@ -291,6 +313,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { ret } + /// Check if RX FIFO underflow (i.e. read-on-empty by the system) has occurred. pub fn underflowed(&self) -> bool { let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().rxunder() & (1 << SM) != 0; @@ -300,10 +323,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { ret } + /// Pull data from RX FIFO. pub fn pull(&mut self) -> u32 { PIO::PIO.rxf(SM).read() } + /// Attempt pulling data from RX FIFO. pub fn try_pull(&mut self) -> Option { if self.empty() { return None; @@ -311,10 +336,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { Some(self.pull()) } + /// Wait for RX FIFO readable. pub fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, 'd, PIO, SM> { FifoInFuture::new(self) } + /// Prepare DMA transfer from RX FIFO. pub fn dma_pull<'a, C: Channel, W: Word>( &'a mut self, ch: PeripheralRef<'a, C>, @@ -340,22 +367,28 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { } } +/// Type representing a state machine TX FIFO. pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> { pio: PhantomData<&'d mut PIO>, } impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { + /// Check if TX FIFO is empty. pub fn empty(&self) -> bool { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } + + /// Check if TX FIFO is full. pub fn full(&self) -> bool { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } + /// Check TX FIFO level. pub fn level(&self) -> u8 { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f } + /// Check state machine has stalled on empty TX FIFO. pub fn stalled(&self) -> bool { let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().txstall() & (1 << SM) != 0; @@ -365,6 +398,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { ret } + /// Check if FIFO overflowed. pub fn overflowed(&self) -> bool { let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().txover() & (1 << SM) != 0; @@ -374,10 +408,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { ret } + /// Force push data to TX FIFO. pub fn push(&mut self, v: u32) { PIO::PIO.txf(SM).write_value(v); } + /// Attempt to push data to TX FIFO. pub fn try_push(&mut self, v: u32) -> bool { if self.full() { return false; @@ -386,10 +422,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { true } + /// Wait until FIFO is ready for writing. pub fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, 'd, PIO, SM> { FifoOutFuture::new(self, value) } + /// Prepare a DMA transfer to TX FIFO. pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { let pio_no = PIO::PIO_NO; let p = ch.regs(); @@ -411,6 +449,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { } } +/// A type representing a single PIO state machine. pub struct StateMachine<'d, PIO: Instance, const SM: usize> { rx: StateMachineRx<'d, PIO, SM>, tx: StateMachineTx<'d, PIO, SM>, @@ -430,52 +469,78 @@ fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) { } } +/// PIO Execution config. #[derive(Clone, Copy, Default, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub struct ExecConfig { + /// If true, the MSB of the Delay/Side-set instruction field is used as side-set enable, rather than a side-set data bit. pub side_en: bool, + /// If true, side-set data is asserted to pin directions, instead of pin values. pub side_pindir: bool, + /// Pin to trigger jump. pub jmp_pin: u8, + /// After reaching this address, execution is wrapped to wrap_bottom. pub wrap_top: u8, + /// After reaching wrap_top, execution is wrapped to this address. pub wrap_bottom: u8, } +/// PIO shift register config for input or output. #[derive(Clone, Copy, Default, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ShiftConfig { + /// Number of bits shifted out of OSR before autopull. pub threshold: u8, + /// Shift direction. pub direction: ShiftDirection, + /// For output: Pull automatically output shift register is emptied. + /// For input: Push automatically when the input shift register is filled. pub auto_fill: bool, } +/// PIO pin config. #[derive(Clone, Copy, Default, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PinConfig { + /// The number of MSBs of the Delay/Side-set instruction field which are used for side-set. pub sideset_count: u8, + /// The number of pins asserted by a SET. In the range 0 to 5 inclusive. pub set_count: u8, + /// The number of pins asserted by an OUT PINS, OUT PINDIRS or MOV PINS instruction. In the range 0 to 32 inclusive. pub out_count: u8, + /// The pin which is mapped to the least-significant bit of a state machine's IN data bus. pub in_base: u8, + /// The lowest-numbered pin that will be affected by a side-set operation. pub sideset_base: u8, + /// The lowest-numbered pin that will be affected by a SET PINS or SET PINDIRS instruction. pub set_base: u8, + /// The lowest-numbered pin that will be affected by an OUT PINS, OUT PINDIRS or MOV PINS instruction. pub out_base: u8, } +/// PIO config. #[derive(Clone, Copy, Debug)] pub struct Config<'d, PIO: Instance> { - // CLKDIV + /// Clock divisor register for state machines. pub clock_divider: FixedU32, - // EXECCTRL + /// Which data bit to use for inline OUT enable. pub out_en_sel: u8, + /// Use a bit of OUT data as an auxiliary write enable When used in conjunction with OUT_STICKY. pub inline_out_en: bool, + /// Continuously assert the most recent OUT/SET to the pins. pub out_sticky: bool, + /// Which source to use for checking status. pub status_sel: StatusSource, + /// Status comparison level. pub status_n: u8, exec: ExecConfig, origin: Option, - // SHIFTCTRL + /// Configure FIFO allocation. pub fifo_join: FifoJoin, + /// Input shifting config. pub shift_in: ShiftConfig, + /// Output shifting config. pub shift_out: ShiftConfig, // PINCTRL pins: PinConfig, @@ -505,16 +570,22 @@ impl<'d, PIO: Instance> Default for Config<'d, PIO> { } impl<'d, PIO: Instance> Config<'d, PIO> { + /// Get execution configuration. pub fn get_exec(&self) -> ExecConfig { self.exec } + + /// Update execution configuration. pub unsafe fn set_exec(&mut self, e: ExecConfig) { self.exec = e; } + /// Get pin configuration. pub fn get_pins(&self) -> PinConfig { self.pins } + + /// Update pin configuration. pub unsafe fn set_pins(&mut self, p: PinConfig) { self.pins = p; } @@ -537,6 +608,7 @@ impl<'d, PIO: Instance> Config<'d, PIO> { self.origin = Some(prog.origin); } + /// Set pin used to signal jump. pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) { self.exec.jmp_pin = pin.pin(); } @@ -571,6 +643,7 @@ impl<'d, PIO: Instance> Config<'d, PIO> { } impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { + /// Set the config for a given PIO state machine. pub fn set_config(&mut self, config: &Config<'d, PIO>) { // sm expects 0 for 65536, truncation makes that happen assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536"); @@ -617,7 +690,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_out_base(config.pins.out_base); }); if let Some(origin) = config.origin { - unsafe { pio_instr_util::exec_jmp(self, origin) } + unsafe { instr::exec_jmp(self, origin) } } } @@ -626,10 +699,13 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { PIO::PIO.sm(SM) } + /// Restart this state machine. pub fn restart(&mut self) { let mask = 1u8 << SM; PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); } + + /// Enable state machine. pub fn set_enable(&mut self, enable: bool) { let mask = 1u8 << SM; if enable { @@ -639,10 +715,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } } + /// Check if state machine is enabled. pub fn is_enabled(&self) -> bool { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } + /// Restart a state machine's clock divider from an initial phase of 0. pub fn clkdiv_restart(&mut self) { let mask = 1u8 << SM; PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); @@ -690,6 +768,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { }); } + /// Flush FIFOs for state machine. pub fn clear_fifos(&mut self) { // Toggle FJOIN_RX to flush FIFOs let shiftctrl = Self::this_sm().shiftctrl(); @@ -701,21 +780,31 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { }); } + /// Instruct state machine to execute a given instructions + /// + /// SAFETY: The state machine must be in a state where executing + /// an arbitrary instruction does not crash it. pub unsafe fn exec_instr(&mut self, instr: u16) { Self::this_sm().instr().write(|w| w.set_instr(instr)); } + /// Return a read handle for reading state machine outputs. pub fn rx(&mut self) -> &mut StateMachineRx<'d, PIO, SM> { &mut self.rx } + + /// Return a handle for writing to inputs. pub fn tx(&mut self) -> &mut StateMachineTx<'d, PIO, SM> { &mut self.tx } + + /// Return both read and write handles for the state machine. pub fn rx_tx(&mut self) -> (&mut StateMachineRx<'d, PIO, SM>, &mut StateMachineTx<'d, PIO, SM>) { (&mut self.rx, &mut self.tx) } } +/// PIO handle. pub struct Common<'d, PIO: Instance> { instructions_used: u32, pio: PhantomData<&'d mut PIO>, @@ -727,18 +816,25 @@ impl<'d, PIO: Instance> Drop for Common<'d, PIO> { } } +/// Memory of PIO instance. pub struct InstanceMemory<'d, PIO: Instance> { used_mask: u32, pio: PhantomData<&'d mut PIO>, } +/// A loaded PIO program. pub struct LoadedProgram<'d, PIO: Instance> { + /// Memory used by program. pub used_memory: InstanceMemory<'d, PIO>, + /// Program origin for loading. pub origin: u8, + /// Wrap controls what to do once program is done executing. pub wrap: Wrap, + /// Data for 'side' set instruction parameters. pub side_set: SideSet, } +/// Errors loading a PIO program. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum LoadError { @@ -834,6 +930,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { self.instructions_used &= !instrs.used_mask; } + /// Bypass flipflop synchronizer on GPIO inputs. pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { // this can interfere with per-pin bypass functions. splitting the // modification is going to be fine since nothing that relies on @@ -842,6 +939,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); } + /// Get bypass configuration. pub fn get_input_sync_bypass(&self) -> u32 { PIO::PIO.input_sync_bypass().read() } @@ -861,6 +959,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { } } + /// Apply changes to all state machines in a batch. pub fn apply_sm_batch(&mut self, f: impl FnOnce(&mut PioBatch<'d, PIO>)) { let mut batch = PioBatch { clkdiv_restart: 0, @@ -878,6 +977,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { } } +/// Represents multiple state machines in a single type. pub struct PioBatch<'a, PIO: Instance> { clkdiv_restart: u8, sm_restart: u8, @@ -887,25 +987,25 @@ pub struct PioBatch<'a, PIO: Instance> { } impl<'a, PIO: Instance> PioBatch<'a, PIO> { - pub fn restart_clockdiv(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) { - self.clkdiv_restart |= 1 << SM; - } - + /// Restart a state machine's clock divider from an initial phase of 0. pub fn restart(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) { self.clkdiv_restart |= 1 << SM; } + /// Enable a specific state machine. pub fn set_enable(&mut self, _sm: &mut StateMachine<'a, PIO, SM>, enable: bool) { self.sm_enable_mask |= 1 << SM; self.sm_enable |= (enable as u8) << SM; } } +/// Type representing a PIO interrupt. pub struct Irq<'d, PIO: Instance, const N: usize> { pio: PhantomData<&'d mut PIO>, } impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> { + /// Wait for an IRQ to fire. pub fn wait<'a>(&'a mut self) -> IrqFuture<'a, 'd, PIO> { IrqFuture { pio: PhantomData, @@ -914,59 +1014,79 @@ impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> { } } +/// Interrupt flags for a PIO instance. #[derive(Clone)] pub struct IrqFlags<'d, PIO: Instance> { pio: PhantomData<&'d mut PIO>, } impl<'d, PIO: Instance> IrqFlags<'d, PIO> { + /// Check if interrupt fired. pub fn check(&self, irq_no: u8) -> bool { assert!(irq_no < 8); self.check_any(1 << irq_no) } + /// Check if any of the interrupts in the bitmap fired. pub fn check_any(&self, irqs: u8) -> bool { PIO::PIO.irq().read().irq() & irqs != 0 } + /// Check if all interrupts have fired. pub fn check_all(&self, irqs: u8) -> bool { PIO::PIO.irq().read().irq() & irqs == irqs } + /// Clear interrupt for interrupt number. pub fn clear(&self, irq_no: usize) { assert!(irq_no < 8); self.clear_all(1 << irq_no); } + /// Clear all interrupts set in the bitmap. pub fn clear_all(&self, irqs: u8) { PIO::PIO.irq().write(|w| w.set_irq(irqs)) } + /// Fire a given interrupt. pub fn set(&self, irq_no: usize) { assert!(irq_no < 8); self.set_all(1 << irq_no); } + /// Fire all interrupts. pub fn set_all(&self, irqs: u8) { PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) } } +/// An instance of the PIO driver. pub struct Pio<'d, PIO: Instance> { + /// PIO handle. pub common: Common<'d, PIO>, + /// PIO IRQ flags. pub irq_flags: IrqFlags<'d, PIO>, + /// IRQ0 configuration. pub irq0: Irq<'d, PIO, 0>, + /// IRQ1 configuration. pub irq1: Irq<'d, PIO, 1>, + /// IRQ2 configuration. pub irq2: Irq<'d, PIO, 2>, + /// IRQ3 configuration. pub irq3: Irq<'d, PIO, 3>, + /// State machine 0 handle. pub sm0: StateMachine<'d, PIO, 0>, + /// State machine 1 handle. pub sm1: StateMachine<'d, PIO, 1>, + /// State machine 2 handle. pub sm2: StateMachine<'d, PIO, 2>, + /// State machine 3 handle. pub sm3: StateMachine<'d, PIO, 3>, _pio: PhantomData<&'d mut PIO>, } impl<'d, PIO: Instance> Pio<'d, PIO> { + /// Create a new instance of a PIO peripheral. pub fn new(_pio: impl Peripheral

+ 'd, _irq: impl Binding>) -> Self { PIO::state().users.store(5, Ordering::Release); PIO::state().used_pins.store(0, Ordering::Release); @@ -1003,9 +1123,10 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { } } -// we need to keep a record of which pins are assigned to each PIO. make_pio_pin -// notionally takes ownership of the pin it is given, but the wrapped pin cannot -// be treated as an owned resource since dropping it would have to deconfigure +/// Representation of the PIO state keeping a record of which pins are assigned to +/// each PIO. +// make_pio_pin notionally takes ownership of the pin it is given, but the wrapped pin +// cannot be treated as an owned resource since dropping it would have to deconfigure // the pin, breaking running state machines in the process. pins are also shared // between all state machines, which makes ownership even messier to track any // other way. @@ -1059,6 +1180,7 @@ mod sealed { } } +/// PIO instance. pub trait Instance: sealed::Instance + Sized + Unpin {} macro_rules! impl_pio { @@ -1076,6 +1198,7 @@ macro_rules! impl_pio { impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0); impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); +/// PIO pin. pub trait PioPin: sealed::PioPin + gpio::Pin {} macro_rules! impl_pio_pin { diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index ca030f560..f14e08525 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -38,15 +38,18 @@ impl State { } } +/// Buffered UART driver. pub struct BufferedUart<'d, T: Instance> { pub(crate) rx: BufferedUartRx<'d, T>, pub(crate) tx: BufferedUartTx<'d, T>, } +/// Buffered UART RX handle. pub struct BufferedUartRx<'d, T: Instance> { pub(crate) phantom: PhantomData<&'d mut T>, } +/// Buffered UART TX handle. pub struct BufferedUartTx<'d, T: Instance> { pub(crate) phantom: PhantomData<&'d mut T>, } @@ -84,6 +87,7 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>( } impl<'d, T: Instance> BufferedUart<'d, T> { + /// Create a buffered UART instance. pub fn new( _uart: impl Peripheral

+ 'd, irq: impl Binding>, @@ -104,6 +108,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> { } } + /// Create a buffered UART instance with flow control. pub fn new_with_rtscts( _uart: impl Peripheral

+ 'd, irq: impl Binding>, @@ -132,32 +137,39 @@ impl<'d, T: Instance> BufferedUart<'d, T> { } } + /// Write to UART TX buffer blocking execution until done. pub fn blocking_write(&mut self, buffer: &[u8]) -> Result { self.tx.blocking_write(buffer) } + /// Flush UART TX blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { self.tx.blocking_flush() } + /// Read from UART RX buffer blocking execution until done. pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result { self.rx.blocking_read(buffer) } + /// Check if UART is busy transmitting. pub fn busy(&self) -> bool { self.tx.busy() } + /// Wait until TX is empty and send break condition. pub async fn send_break(&mut self, bits: u32) { self.tx.send_break(bits).await } + /// Split into separate RX and TX handles. pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { (self.rx, self.tx) } } impl<'d, T: Instance> BufferedUartRx<'d, T> { + /// Create a new buffered UART RX. pub fn new( _uart: impl Peripheral

+ 'd, irq: impl Binding>, @@ -173,6 +185,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { Self { phantom: PhantomData } } + /// Create a new buffered UART RX with flow control. pub fn new_with_rts( _uart: impl Peripheral

+ 'd, irq: impl Binding>, @@ -253,6 +266,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { Poll::Ready(result) } + /// Read from UART RX buffer blocking execution until done. pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result { loop { match Self::try_read(buf) { @@ -303,6 +317,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { } impl<'d, T: Instance> BufferedUartTx<'d, T> { + /// Create a new buffered UART TX. pub fn new( _uart: impl Peripheral

+ 'd, irq: impl Binding>, @@ -318,6 +333,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { Self { phantom: PhantomData } } + /// Create a new buffered UART TX with flow control. pub fn new_with_cts( _uart: impl Peripheral

+ 'd, irq: impl Binding>, @@ -373,6 +389,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { }) } + /// Write to UART TX buffer blocking execution until done. pub fn blocking_write(&mut self, buf: &[u8]) -> Result { if buf.is_empty() { return Ok(0); @@ -398,6 +415,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { } } + /// Flush UART TX blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { loop { let state = T::buffered_state(); @@ -407,6 +425,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { } } + /// Check if UART is busy. pub fn busy(&self) -> bool { T::regs().uartfr().read().busy() } @@ -466,6 +485,7 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { } } +/// Interrupt handler. pub struct BufferedInterruptHandler { _uart: PhantomData, } diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index f82b9036b..26f21193a 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -938,9 +938,13 @@ macro_rules! impl_instance { impl_instance!(UART0, UART0_IRQ, 20, 21); impl_instance!(UART1, UART1_IRQ, 22, 23); +/// Trait for TX pins. pub trait TxPin: sealed::TxPin + crate::gpio::Pin {} +/// Trait for RX pins. pub trait RxPin: sealed::RxPin + crate::gpio::Pin {} +/// Trait for Clear To Send (CTS) pins. pub trait CtsPin: sealed::CtsPin + crate::gpio::Pin {} +/// Trait for Request To Send (RTS) pins. pub trait RtsPin: sealed::RtsPin + crate::gpio::Pin {} macro_rules! impl_pin { diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 4a74ee6f7..bcd848222 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -20,7 +20,9 @@ pub(crate) mod sealed { } } +/// USB peripheral instance. pub trait Instance: sealed::Instance + 'static { + /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } @@ -96,6 +98,7 @@ impl EndpointData { } } +/// RP2040 USB driver handle. pub struct Driver<'d, T: Instance> { phantom: PhantomData<&'d mut T>, ep_in: [EndpointData; EP_COUNT], @@ -104,6 +107,7 @@ pub struct Driver<'d, T: Instance> { } impl<'d, T: Instance> Driver<'d, T> { + /// Create a new USB driver. pub fn new(_usb: impl Peripheral

+ 'd, _irq: impl Binding>) -> Self { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -240,6 +244,7 @@ impl<'d, T: Instance> Driver<'d, T> { } } +/// USB interrupt handler. pub struct InterruptHandler { _uart: PhantomData, } @@ -342,6 +347,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { } } +/// Type representing the RP USB bus. pub struct Bus<'d, T: Instance> { phantom: PhantomData<&'d mut T>, ep_out: [EndpointData; EP_COUNT], @@ -461,6 +467,7 @@ trait Dir { fn waker(i: usize) -> &'static AtomicWaker; } +/// Type for In direction. pub enum In {} impl Dir for In { fn dir() -> Direction { @@ -473,6 +480,7 @@ impl Dir for In { } } +/// Type for Out direction. pub enum Out {} impl Dir for Out { fn dir() -> Direction { @@ -485,6 +493,7 @@ impl Dir for Out { } } +/// Endpoint for RP USB driver. pub struct Endpoint<'d, T: Instance, D> { _phantom: PhantomData<(&'d mut T, D)>, info: EndpointInfo, @@ -616,6 +625,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { } } +/// Control pipe for RP USB driver. pub struct ControlPipe<'d, T: Instance> { _phantom: PhantomData<&'d mut T>, max_packet_size: u16, From 486b67e89522d7e36f6b1078ff8018d64447b39e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 11:26:08 +0100 Subject: [PATCH 060/760] docs: document spi, rtc and rest of uart for embassy-rp --- embassy-rp/src/pwm.rs | 5 ++++ embassy-rp/src/rtc/mod.rs | 1 + embassy-rp/src/spi.rs | 31 ++++++++++++++++++++++++ embassy-rp/src/uart/mod.rs | 48 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 516b8254b..5b96557a3 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -61,9 +61,13 @@ impl Default for Config { } } +/// PWM input mode. pub enum InputMode { + /// Level mode. Level, + /// Rising edge mode. RisingEdge, + /// Falling edge mode. FallingEdge, } @@ -77,6 +81,7 @@ impl From for Divmode { } } +/// PWM driver. pub struct Pwm<'d, T: Channel> { inner: PeripheralRef<'d, T>, pin_a: Option>, diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 60ca8627b..c3df3ee57 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -194,6 +194,7 @@ mod sealed { } } +/// RTC peripheral instance. pub trait Instance: sealed::Instance {} impl sealed::Instance for crate::peripherals::RTC { diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 6ba985a65..a2a22ffe5 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -11,6 +11,7 @@ use crate::gpio::sealed::Pin as _; use crate::gpio::{AnyPin, Pin as GpioPin}; use crate::{pac, peripherals, Peripheral}; +/// SPI errors. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -18,11 +19,15 @@ pub enum Error { // No errors for now } +/// SPI configuration. #[non_exhaustive] #[derive(Clone)] pub struct Config { + /// Frequency. pub frequency: u32, + /// Phase. pub phase: Phase, + /// Polarity. pub polarity: Polarity, } @@ -36,6 +41,7 @@ impl Default for Config { } } +/// SPI driver. pub struct Spi<'d, T: Instance, M: Mode> { inner: PeripheralRef<'d, T>, tx_dma: Option>, @@ -119,6 +125,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { } } + /// Write data to SPI blocking execution until done. pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { let p = self.inner.regs(); for &b in data { @@ -131,6 +138,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { Ok(()) } + /// Transfer data in place to SPI blocking execution until done. pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { let p = self.inner.regs(); for b in data { @@ -143,6 +151,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { Ok(()) } + /// Read data from SPI blocking execution until done. pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { let p = self.inner.regs(); for b in data { @@ -155,6 +164,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { Ok(()) } + /// Transfer data to SPI blocking execution until done. pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { let p = self.inner.regs(); let len = read.len().max(write.len()); @@ -172,12 +182,14 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { Ok(()) } + /// Block execution until SPI is done. pub fn flush(&mut self) -> Result<(), Error> { let p = self.inner.regs(); while p.sr().read().bsy() {} Ok(()) } + /// Set SPI frequency. pub fn set_frequency(&mut self, freq: u32) { let (presc, postdiv) = calc_prescs(freq); let p = self.inner.regs(); @@ -196,6 +208,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { } impl<'d, T: Instance> Spi<'d, T, Blocking> { + /// Create an SPI driver in blocking mode. pub fn new_blocking( inner: impl Peripheral

+ 'd, clk: impl Peripheral

+ 'd> + 'd, @@ -216,6 +229,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { ) } + /// Create an SPI driver in blocking mode supporting writes only. pub fn new_blocking_txonly( inner: impl Peripheral

+ 'd, clk: impl Peripheral

+ 'd> + 'd, @@ -235,6 +249,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { ) } + /// Create an SPI driver in blocking mode supporting reads only. pub fn new_blocking_rxonly( inner: impl Peripheral

+ 'd, clk: impl Peripheral

+ 'd> + 'd, @@ -256,6 +271,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { } impl<'d, T: Instance> Spi<'d, T, Async> { + /// Create an SPI driver in async mode supporting DMA operations. pub fn new( inner: impl Peripheral

+ 'd, clk: impl Peripheral

+ 'd> + 'd, @@ -278,6 +294,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { ) } + /// Create an SPI driver in async mode supporting DMA write operations only. pub fn new_txonly( inner: impl Peripheral

+ 'd, clk: impl Peripheral

+ 'd> + 'd, @@ -298,6 +315,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { ) } + /// Create an SPI driver in async mode supporting DMA read operations only. pub fn new_rxonly( inner: impl Peripheral

+ 'd, clk: impl Peripheral

+ 'd> + 'd, @@ -318,6 +336,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { ) } + /// Write data to SPI using DMA. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { let tx_ch = self.tx_dma.as_mut().unwrap(); let tx_transfer = unsafe { @@ -340,6 +359,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { Ok(()) } + /// Read data from SPI using DMA. pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { // Start RX first. Transfer starts when TX starts, if RX // is not started yet we might lose bytes. @@ -365,10 +385,12 @@ impl<'d, T: Instance> Spi<'d, T, Async> { Ok(()) } + /// Transfer data to SPI using DMA. pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> { self.transfer_inner(rx_buffer, tx_buffer).await } + /// Transfer data in place to SPI using DMA. pub async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> { self.transfer_inner(words, words).await } @@ -434,7 +456,10 @@ mod sealed { } } +/// Mode. pub trait Mode: sealed::Mode {} + +/// SPI instance trait. pub trait Instance: sealed::Instance {} macro_rules! impl_instance { @@ -454,9 +479,13 @@ macro_rules! impl_instance { impl_instance!(SPI0, Spi0, 16, 17); impl_instance!(SPI1, Spi1, 18, 19); +/// CLK pin. pub trait ClkPin: GpioPin {} +/// CS pin. pub trait CsPin: GpioPin {} +/// MOSI pin. pub trait MosiPin: GpioPin {} +/// MISO pin. pub trait MisoPin: GpioPin {} macro_rules! impl_pin { @@ -503,7 +532,9 @@ macro_rules! impl_mode { }; } +/// Blocking mode. pub struct Blocking; +/// Async mode. pub struct Async; impl_mode!(Blocking); diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 26f21193a..32be7661d 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -20,11 +20,16 @@ use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; mod buffered; pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx}; +/// Word length. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum DataBits { + /// 5 bits. DataBits5, + /// 6 bits. DataBits6, + /// 7 bits. DataBits7, + /// 8 bits. DataBits8, } @@ -39,13 +44,18 @@ impl DataBits { } } +/// Parity bit. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Parity { + /// No parity. ParityNone, + /// Even parity. ParityEven, + /// Odd parity. ParityOdd, } +/// Stop bits. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum StopBits { #[doc = "1 stop bit"] @@ -54,20 +64,25 @@ pub enum StopBits { STOP2, } +/// UART config. #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Config { + /// Baud rate. pub baudrate: u32, + /// Word length. pub data_bits: DataBits, + /// Stop bits. pub stop_bits: StopBits, + /// Parity bit. pub parity: Parity, /// Invert the tx pin output pub invert_tx: bool, /// Invert the rx pin input pub invert_rx: bool, - // Invert the rts pin + /// Invert the rts pin pub invert_rts: bool, - // Invert the cts pin + /// Invert the cts pin pub invert_cts: bool, } @@ -102,21 +117,25 @@ pub enum Error { Framing, } +/// Internal DMA state of UART RX. pub struct DmaState { rx_err_waker: AtomicWaker, rx_errs: AtomicU16, } +/// UART driver. pub struct Uart<'d, T: Instance, M: Mode> { tx: UartTx<'d, T, M>, rx: UartRx<'d, T, M>, } +/// UART TX driver. pub struct UartTx<'d, T: Instance, M: Mode> { tx_dma: Option>, phantom: PhantomData<(&'d mut T, M)>, } +/// UART RX driver. pub struct UartRx<'d, T: Instance, M: Mode> { rx_dma: Option>, phantom: PhantomData<(&'d mut T, M)>, @@ -142,6 +161,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { } } + /// Transmit the provided buffer blocking execution until done. pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { let r = T::regs(); for &b in buffer { @@ -151,12 +171,14 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { Ok(()) } + /// Flush UART TX blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { let r = T::regs(); while !r.uartfr().read().txfe() {} Ok(()) } + /// Check if UART is busy transmitting. pub fn busy(&self) -> bool { T::regs().uartfr().read().busy() } @@ -191,6 +213,8 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { } impl<'d, T: Instance> UartTx<'d, T, Blocking> { + /// Convert this uart TX instance into a buffered uart using the provided + /// irq and transmit buffer. pub fn into_buffered( self, irq: impl Binding>, @@ -203,6 +227,7 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> { } impl<'d, T: Instance> UartTx<'d, T, Async> { + /// Write to UART TX from the provided buffer using DMA. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { let ch = self.tx_dma.as_mut().unwrap(); let transfer = unsafe { @@ -246,6 +271,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { } } + /// Read from UART RX blocking execution until done. pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { while buffer.len() > 0 { let received = self.drain_fifo(buffer)?; @@ -294,6 +320,7 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { } impl<'d, T: Instance> UartRx<'d, T, Blocking> { + /// Create a new UART RX instance for blocking mode operations. pub fn new_blocking( _uart: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, @@ -304,6 +331,8 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> { Self::new_inner(false, None) } + /// Convert this uart RX instance into a buffered uart using the provided + /// irq and receive buffer. pub fn into_buffered( self, irq: impl Binding>, @@ -315,6 +344,7 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> { } } +/// Interrupt handler. pub struct InterruptHandler { _uart: PhantomData, } @@ -338,6 +368,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } impl<'d, T: Instance> UartRx<'d, T, Async> { + /// Read from UART RX into the provided buffer. pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { // clear error flags before we drain the fifo. errors that have accumulated // in the flags will also be present in the fifo. @@ -458,6 +489,8 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> { ) } + /// Convert this uart instance into a buffered uart using the provided + /// irq, transmit and receive buffers. pub fn into_buffered( self, irq: impl Binding>, @@ -667,22 +700,27 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { } impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { + /// Transmit the provided buffer blocking execution until done. pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.blocking_write(buffer) } + /// Flush UART TX blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { self.tx.blocking_flush() } + /// Read from UART RX blocking execution until done. pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.blocking_read(buffer) } + /// Check if UART is busy transmitting. pub fn busy(&self) -> bool { self.tx.busy() } + /// Wait until TX is empty and send break condition. pub async fn send_break(&mut self, bits: u32) { self.tx.send_break(bits).await } @@ -695,10 +733,12 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { } impl<'d, T: Instance> Uart<'d, T, Async> { + /// Write to UART TX from the provided buffer. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.write(buffer).await } + /// Read from UART RX into the provided buffer. pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.read(buffer).await } @@ -889,6 +929,7 @@ mod sealed { pub trait RtsPin {} } +/// UART mode. pub trait Mode: sealed::Mode {} macro_rules! impl_mode { @@ -898,12 +939,15 @@ macro_rules! impl_mode { }; } +/// Blocking mode. pub struct Blocking; +/// Async mode. pub struct Async; impl_mode!(Blocking); impl_mode!(Async); +/// UART instance trait. pub trait Instance: sealed::Instance {} macro_rules! impl_instance { From 3e2e109437d8f5f4bcdd59dac5fe9f3a7bf9f047 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 19 Dec 2023 19:09:06 +0800 Subject: [PATCH 061/760] update metapac dep --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4a7a2f2c9..7f2cf6bfb 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-91cee0d1fdcb4e447b65a09756b506f4af91b7e2" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2234f380f51d16d0398b8e547088b33ea623cc7c" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-91cee0d1fdcb4e447b65a09756b506f4af91b7e2", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2234f380f51d16d0398b8e547088b33ea623cc7c", default-features = false, features = ["metadata"]} [features] From f4b77c967fec9edacc6818aa8d935fda60bc743f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 14:19:46 +0100 Subject: [PATCH 062/760] docs: document all embassy-rp public apis Enable missing doc warnings. --- embassy-rp/src/adc.rs | 24 ++++++++ embassy-rp/src/clocks.rs | 97 +++++++++++++++++++++++++++++++-- embassy-rp/src/dma.rs | 20 +++++++ embassy-rp/src/flash.rs | 42 +++++++++++++- embassy-rp/src/gpio.rs | 68 ++++++++++++++++++++++- embassy-rp/src/i2c.rs | 22 ++++++++ embassy-rp/src/i2c_slave.rs | 3 + embassy-rp/src/lib.rs | 1 + embassy-rp/src/pio/mod.rs | 1 + embassy-rp/src/pwm.rs | 20 +++++++ embassy-rp/src/rtc/mod.rs | 1 + embassy-rp/src/timer.rs | 1 + embassy-rp/src/uart/buffered.rs | 1 + embassy-rp/src/uart/mod.rs | 3 +- embassy-rp/src/usb.rs | 1 + 15 files changed, 294 insertions(+), 11 deletions(-) diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 5b913f156..21360bf66 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -1,3 +1,4 @@ +//! ADC driver. use core::future::poll_fn; use core::marker::PhantomData; use core::mem; @@ -16,6 +17,7 @@ use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt}; static WAKER: AtomicWaker = AtomicWaker::new(); +/// ADC config. #[non_exhaustive] pub struct Config {} @@ -30,9 +32,11 @@ enum Source<'p> { TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), } +/// ADC channel. pub struct Channel<'p>(Source<'p>); impl<'p> Channel<'p> { + /// Create a new ADC channel from pin with the provided [Pull] configuration. pub fn new_pin(pin: impl Peripheral

+ 'p, pull: Pull) -> Self { into_ref!(pin); pin.pad_ctrl().modify(|w| { @@ -49,6 +53,7 @@ impl<'p> Channel<'p> { Self(Source::Pin(pin.map_into())) } + /// Create a new ADC channel for the internal temperature sensor. pub fn new_temp_sensor(s: impl Peripheral

+ 'p) -> Self { let r = pac::ADC; r.cs().write_set(|w| w.set_ts_en(true)); @@ -83,35 +88,44 @@ impl<'p> Drop for Source<'p> { } } +/// ADC sample. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(transparent)] pub struct Sample(u16); impl Sample { + /// Sample is valid. pub fn good(&self) -> bool { self.0 < 0x8000 } + /// Sample value. pub fn value(&self) -> u16 { self.0 & !0x8000 } } +/// ADC error. #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Error converting value. ConversionFailed, } +/// ADC mode. pub trait Mode {} +/// ADC async mode. pub struct Async; impl Mode for Async {} +/// ADC blocking mode. pub struct Blocking; impl Mode for Blocking {} +/// ADC driver. pub struct Adc<'d, M: Mode> { phantom: PhantomData<(&'d ADC, M)>, } @@ -150,6 +164,7 @@ impl<'d, M: Mode> Adc<'d, M> { while !r.cs().read().ready() {} } + /// Sample a value from a channel in blocking mode. pub fn blocking_read(&mut self, ch: &mut Channel) -> Result { let r = Self::regs(); r.cs().modify(|w| { @@ -166,6 +181,7 @@ impl<'d, M: Mode> Adc<'d, M> { } impl<'d> Adc<'d, Async> { + /// Create ADC driver in async mode. pub fn new( _inner: impl Peripheral

+ 'd, _irq: impl Binding, @@ -194,6 +210,7 @@ impl<'d> Adc<'d, Async> { .await; } + /// Sample a value from a channel until completed. pub async fn read(&mut self, ch: &mut Channel<'_>) -> Result { let r = Self::regs(); r.cs().modify(|w| { @@ -272,6 +289,7 @@ impl<'d> Adc<'d, Async> { } } + /// Sample multiple values from a channel using DMA. #[inline] pub async fn read_many( &mut self, @@ -283,6 +301,7 @@ impl<'d> Adc<'d, Async> { self.read_many_inner(ch, buf, false, div, dma).await } + /// Sample multiple values from a channel using DMA with errors inlined in samples. #[inline] pub async fn read_many_raw( &mut self, @@ -299,6 +318,7 @@ impl<'d> Adc<'d, Async> { } impl<'d> Adc<'d, Blocking> { + /// Create ADC driver in blocking mode. pub fn new_blocking(_inner: impl Peripheral

+ 'd, _config: Config) -> Self { Self::setup(); @@ -306,6 +326,7 @@ impl<'d> Adc<'d, Blocking> { } } +/// Interrupt handler. pub struct InterruptHandler { _empty: (), } @@ -324,6 +345,7 @@ mod sealed { pub trait AdcChannel {} } +/// ADC sample. pub trait AdcSample: sealed::AdcSample {} impl sealed::AdcSample for u16 {} @@ -332,7 +354,9 @@ impl AdcSample for u16 {} impl sealed::AdcSample for u8 {} impl AdcSample for u8 {} +/// ADC channel. pub trait AdcChannel: sealed::AdcChannel {} +/// ADC pin. pub trait AdcPin: AdcChannel + gpio::Pin {} macro_rules! impl_pin { diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 2f0645615..19232b801 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -45,15 +45,20 @@ static CLOCKS: Clocks = Clocks { rtc: AtomicU16::new(0), }; -/// Enumeration of supported clock sources. +/// Peripheral clock sources. #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum PeriClkSrc { + /// SYS. Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _, + /// PLL SYS. PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _, + /// PLL USB. PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _, + /// ROSC. Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _, + /// XOSC. Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _, // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , @@ -83,6 +88,7 @@ pub struct ClockConfig { } impl ClockConfig { + /// Clock configuration derived from external crystal. pub fn crystal(crystal_hz: u32) -> Self { Self { rosc: Some(RoscConfig { @@ -141,6 +147,7 @@ impl ClockConfig { } } + /// Clock configuration from internal oscillator. pub fn rosc() -> Self { Self { rosc: Some(RoscConfig { @@ -190,13 +197,18 @@ impl ClockConfig { // } } +/// ROSC freq range. #[repr(u16)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RoscRange { + /// Low range. Low = pac::rosc::vals::FreqRange::LOW.0, + /// Medium range (1.33x low) Medium = pac::rosc::vals::FreqRange::MEDIUM.0, + /// High range (2x low) High = pac::rosc::vals::FreqRange::HIGH.0, + /// Too high. Should not be used. TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0, } @@ -239,96 +251,136 @@ pub struct PllConfig { pub post_div2: u8, } -/// Reference +/// Reference clock config. pub struct RefClkConfig { + /// Reference clock source. pub src: RefClkSrc, + /// Reference clock divider. pub div: u8, } +/// Reference clock source. #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RefClkSrc { - // main sources + /// XOSC. Xosc, + /// ROSC. Rosc, - // aux sources + /// PLL USB. PllUsb, // Gpin0, // Gpin1, } +/// SYS clock source. #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum SysClkSrc { - // main sources + /// REF. Ref, - // aux sources + /// PLL SYS. PllSys, + /// PLL USB. PllUsb, + /// ROSC. Rosc, + /// XOSC. Xosc, // Gpin0, // Gpin1, } +/// SYS clock config. pub struct SysClkConfig { + /// SYS clock source. pub src: SysClkSrc, + /// SYS clock divider. pub div_int: u32, + /// SYS clock fraction. pub div_frac: u8, } +/// USB clock source. #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum UsbClkSrc { + /// PLL USB. PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, + /// PLL SYS. PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _, + /// ROSC. Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _, + /// XOSC. Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _, // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ , } +/// USB clock config. pub struct UsbClkConfig { + /// USB clock source. pub src: UsbClkSrc, + /// USB clock divider. pub div: u8, + /// USB clock phase. pub phase: u8, } +/// ADC clock source. #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum AdcClkSrc { + /// PLL USB. PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, + /// PLL SYS. PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _, + /// ROSC. Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _, + /// XOSC. Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _, // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ , } +/// ADC clock config. pub struct AdcClkConfig { + /// ADC clock source. pub src: AdcClkSrc, + /// ADC clock divider. pub div: u8, + /// ADC clock phase. pub phase: u8, } +/// RTC clock source. #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RtcClkSrc { + /// PLL USB. PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _, + /// PLL SYS. PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _, + /// ROSC. Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _, + /// XOSC. Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _, // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ , } +/// RTC clock config. pub struct RtcClkConfig { + /// RTC clock source. pub src: RtcClkSrc, + /// RTC clock divider. pub div_int: u32, + /// RTC clock divider fraction. pub div_frac: u8, + /// RTC clock phase. pub phase: u8, } @@ -605,10 +657,12 @@ fn configure_rosc(config: RoscConfig) -> u32 { config.hz } +/// ROSC clock frequency. pub fn rosc_freq() -> u32 { CLOCKS.rosc.load(Ordering::Relaxed) } +/// XOSC clock frequency. pub fn xosc_freq() -> u32 { CLOCKS.xosc.load(Ordering::Relaxed) } @@ -620,34 +674,42 @@ pub fn xosc_freq() -> u32 { // CLOCKS.gpin1.load(Ordering::Relaxed) // } +/// PLL SYS clock frequency. pub fn pll_sys_freq() -> u32 { CLOCKS.pll_sys.load(Ordering::Relaxed) } +/// PLL USB clock frequency. pub fn pll_usb_freq() -> u32 { CLOCKS.pll_usb.load(Ordering::Relaxed) } +/// SYS clock frequency. pub fn clk_sys_freq() -> u32 { CLOCKS.sys.load(Ordering::Relaxed) } +/// REF clock frequency. pub fn clk_ref_freq() -> u32 { CLOCKS.reference.load(Ordering::Relaxed) } +/// Peripheral clock frequency. pub fn clk_peri_freq() -> u32 { CLOCKS.peri.load(Ordering::Relaxed) } +/// USB clock frequency. pub fn clk_usb_freq() -> u32 { CLOCKS.usb.load(Ordering::Relaxed) } +/// ADC clock frequency. pub fn clk_adc_freq() -> u32 { CLOCKS.adc.load(Ordering::Relaxed) } +/// RTC clock frequency. pub fn clk_rtc_freq() -> u16 { CLOCKS.rtc.load(Ordering::Relaxed) } @@ -708,7 +770,9 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { vco_freq / ((config.post_div1 * config.post_div2) as u32) } +/// General purpose input clock pin. pub trait GpinPin: crate::gpio::Pin { + /// Pin number. const NR: usize; } @@ -723,12 +787,14 @@ macro_rules! impl_gpinpin { impl_gpinpin!(PIN_20, 20, 0); impl_gpinpin!(PIN_22, 22, 1); +/// General purpose clock input driver. pub struct Gpin<'d, T: Pin> { gpin: PeripheralRef<'d, AnyPin>, _phantom: PhantomData, } impl<'d, T: Pin> Gpin<'d, T> { + /// Create new gpin driver. pub fn new(gpin: impl Peripheral

+ 'd) -> Gpin<'d, P> { into_ref!(gpin); @@ -754,7 +820,9 @@ impl<'d, T: Pin> Drop for Gpin<'d, T> { } } +/// General purpose clock output pin. pub trait GpoutPin: crate::gpio::Pin { + /// Pin number. fn number(&self) -> usize; } @@ -773,26 +841,38 @@ impl_gpoutpin!(PIN_23, 1); impl_gpoutpin!(PIN_24, 2); impl_gpoutpin!(PIN_25, 3); +/// Gpout clock source. #[repr(u8)] pub enum GpoutSrc { + /// Sys PLL. PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _, // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ , + /// USB PLL. PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _, + /// ROSC. Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _, + /// XOSC. Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _, + /// SYS. Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _, + /// USB. Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _, + /// ADC. Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, + /// RTC. Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, + /// REF. Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, } +/// General purpose clock output driver. pub struct Gpout<'d, T: GpoutPin> { gpout: PeripheralRef<'d, T>, } impl<'d, T: GpoutPin> Gpout<'d, T> { + /// Create new general purpose cloud output. pub fn new(gpout: impl Peripheral

+ 'd) -> Self { into_ref!(gpout); @@ -801,6 +881,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { Self { gpout } } + /// Set clock divider. pub fn set_div(&self, int: u32, frac: u8) { let c = pac::CLOCKS; c.clk_gpout_div(self.gpout.number()).write(|w| { @@ -809,6 +890,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { }); } + /// Set clock source. pub fn set_src(&self, src: GpoutSrc) { let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { @@ -816,6 +898,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { }); } + /// Enable clock. pub fn enable(&self) { let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { @@ -823,6 +906,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { }); } + /// Disable clock. pub fn disable(&self) { let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { @@ -830,6 +914,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { }); } + /// Clock frequency. pub fn get_freq(&self) -> u32 { let c = pac::CLOCKS; let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc(); diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 45ca21a75..088a842a1 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -38,6 +38,9 @@ pub(crate) unsafe fn init() { interrupt::DMA_IRQ_0.enable(); } +/// DMA read. +/// +/// SAFETY: Slice must point to a valid location reachable by DMA. pub unsafe fn read<'a, C: Channel, W: Word>( ch: impl Peripheral

+ 'a, from: *const W, @@ -57,6 +60,9 @@ pub unsafe fn read<'a, C: Channel, W: Word>( ) } +/// DMA write. +/// +/// SAFETY: Slice must point to a valid location reachable by DMA. pub unsafe fn write<'a, C: Channel, W: Word>( ch: impl Peripheral

+ 'a, from: *const [W], @@ -79,6 +85,9 @@ pub unsafe fn write<'a, C: Channel, W: Word>( // static mut so that this is allocated in RAM. static mut DUMMY: u32 = 0; +/// DMA repeated write. +/// +/// SAFETY: Slice must point to a valid location reachable by DMA. pub unsafe fn write_repeated<'a, C: Channel, W: Word>( ch: impl Peripheral

+ 'a, to: *mut W, @@ -97,6 +106,9 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>( ) } +/// DMA copy between slices. +/// +/// SAFETY: Slices must point to locations reachable by DMA. pub unsafe fn copy<'a, C: Channel, W: Word>( ch: impl Peripheral

+ 'a, from: &[W], @@ -152,6 +164,7 @@ fn copy_inner<'a, C: Channel>( Transfer::new(ch) } +/// DMA transfer driver. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a, C: Channel> { channel: PeripheralRef<'a, C>, @@ -201,19 +214,25 @@ mod sealed { pub trait Word {} } +/// DMA channel interface. pub trait Channel: Peripheral

+ sealed::Channel + Into + Sized + 'static { + /// Channel number. fn number(&self) -> u8; + /// Channel registry block. fn regs(&self) -> pac::dma::Channel { pac::DMA.ch(self.number() as _) } + /// Convert into type-erased [AnyChannel]. fn degrade(self) -> AnyChannel { AnyChannel { number: self.number() } } } +/// DMA word. pub trait Word: sealed::Word { + /// Word size. fn size() -> vals::DataSize; } @@ -238,6 +257,7 @@ impl Word for u32 { } } +/// Type erased DMA channel. pub struct AnyChannel { number: u8, } diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 1b20561da..2d673cf6c 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -1,3 +1,4 @@ +//! Flash driver. use core::future::Future; use core::marker::PhantomData; use core::pin::Pin; @@ -13,9 +14,10 @@ use crate::dma::{AnyChannel, Channel, Transfer}; use crate::pac; use crate::peripherals::FLASH; +/// Flash base address. pub const FLASH_BASE: *const u32 = 0x10000000 as _; -// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. +/// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. // TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); @@ -24,10 +26,15 @@ pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); // These limitations are currently enforced because of using the // RP2040 boot-rom flash functions, that are optimized for flash compatibility // rather than performance. +/// Flash page size. pub const PAGE_SIZE: usize = 256; +/// Flash write size. pub const WRITE_SIZE: usize = 1; +/// Flash read size. pub const READ_SIZE: usize = 1; +/// Flash erase size. pub const ERASE_SIZE: usize = 4096; +/// Flash DMA read size. pub const ASYNC_READ_SIZE: usize = 4; /// Error type for NVMC operations. @@ -38,7 +45,9 @@ pub enum Error { OutOfBounds, /// Unaligned operation or using unaligned buffers. Unaligned, + /// Accessed from the wrong core. InvalidCore, + /// Other error Other, } @@ -96,12 +105,18 @@ impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, ' } } +/// Flash driver. pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> { dma: Option>, phantom: PhantomData<(&'d mut T, M)>, } impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> { + /// Blocking read. + /// + /// The offset and buffer must be aligned. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { trace!( "Reading from 0x{:x} to 0x{:x}", @@ -116,10 +131,14 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI Ok(()) } + /// Flash capacity. pub fn capacity(&self) -> usize { FLASH_SIZE } + /// Blocking erase. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { check_erase(self, from, to)?; @@ -136,6 +155,11 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI Ok(()) } + /// Blocking write. + /// + /// The offset and buffer must be aligned. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { check_write(self, offset, bytes.len())?; @@ -219,6 +243,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI } impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> { + /// Create a new flash driver in blocking mode. pub fn new_blocking(_flash: impl Peripheral

+ 'd) -> Self { Self { dma: None, @@ -228,6 +253,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE } impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { + /// Create a new flash driver in async mode. pub fn new(_flash: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { into_ref!(dma); Self { @@ -236,6 +262,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { } } + /// Start a background read operation. + /// + /// The offset and buffer must be aligned. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. pub fn background_read<'a>( &'a mut self, offset: u32, @@ -279,6 +310,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { }) } + /// Async read. + /// + /// The offset and buffer must be aligned. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { use core::mem::MaybeUninit; @@ -874,7 +910,9 @@ mod sealed { pub trait Mode {} } +/// Flash instance. pub trait Instance: sealed::Instance {} +/// Flash mode. pub trait Mode: sealed::Mode {} impl sealed::Instance for FLASH {} @@ -887,7 +925,9 @@ macro_rules! impl_mode { }; } +/// Flash blocking mode. pub struct Blocking; +/// Flash async mode. pub struct Async; impl_mode!(Blocking); diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 23273e627..2e6692abe 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -1,3 +1,4 @@ +//! GPIO driver. #![macro_use] use core::convert::Infallible; use core::future::Future; @@ -23,7 +24,9 @@ static QSPI_WAKERS: [AtomicWaker; QSPI_PIN_COUNT] = [NEW_AW; QSPI_PIN_COUNT]; /// Represents a digital input or output level. #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum Level { + /// Logical low. Low, + /// Logical high. High, } @@ -48,48 +51,66 @@ impl From for bool { /// Represents a pull setting for an input. #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Pull { + /// No pull. None, + /// Internal pull-up resistor. Up, + /// Internal pull-down resistor. Down, } /// Drive strength of an output #[derive(Debug, Eq, PartialEq)] pub enum Drive { + /// 2 mA drive. _2mA, + /// 4 mA drive. _4mA, + /// 8 mA drive. _8mA, + /// 1 2mA drive. _12mA, } /// Slew rate of an output #[derive(Debug, Eq, PartialEq)] pub enum SlewRate { + /// Fast slew rate. Fast, + /// Slow slew rate. Slow, } /// A GPIO bank with up to 32 pins. #[derive(Debug, Eq, PartialEq)] pub enum Bank { + /// Bank 0. Bank0 = 0, + /// QSPI. #[cfg(feature = "qspi-as-gpio")] Qspi = 1, } +/// Dormant mode config. #[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DormantWakeConfig { + /// Wake on edge high. pub edge_high: bool, + /// Wake on edge low. pub edge_low: bool, + /// Wake on level high. pub level_high: bool, + /// Wake on level low. pub level_low: bool, } +/// GPIO input driver. pub struct Input<'d, T: Pin> { pin: Flex<'d, T>, } impl<'d, T: Pin> Input<'d, T> { + /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { let mut pin = Flex::new(pin); @@ -104,11 +125,13 @@ impl<'d, T: Pin> Input<'d, T> { self.pin.set_schmitt(enable) } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { self.pin.is_high() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.pin.is_low() @@ -120,31 +143,37 @@ impl<'d, T: Pin> Input<'d, T> { self.pin.get_level() } + /// Wait until the pin is high. If it is already high, return immediately. #[inline] pub async fn wait_for_high(&mut self) { self.pin.wait_for_high().await; } + /// Wait until the pin is low. If it is already low, return immediately. #[inline] pub async fn wait_for_low(&mut self) { self.pin.wait_for_low().await; } + /// Wait for the pin to undergo a transition from low to high. #[inline] pub async fn wait_for_rising_edge(&mut self) { self.pin.wait_for_rising_edge().await; } + /// Wait for the pin to undergo a transition from high to low. #[inline] pub async fn wait_for_falling_edge(&mut self) { self.pin.wait_for_falling_edge().await; } + /// Wait for the pin to undergo any transition, i.e low to high OR high to low. #[inline] pub async fn wait_for_any_edge(&mut self) { self.pin.wait_for_any_edge().await; } + /// Configure dormant wake. #[inline] pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake { self.pin.dormant_wake(cfg) @@ -155,10 +184,15 @@ impl<'d, T: Pin> Input<'d, T> { #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum InterruptTrigger { + /// Trigger on pin low. LevelLow, + /// Trigger on pin high. LevelHigh, + /// Trigger on high to low transition. EdgeLow, + /// Trigger on low to high transition. EdgeHigh, + /// Trigger on any transition. AnyEdge, } @@ -226,6 +260,7 @@ struct InputFuture<'a, T: Pin> { } impl<'d, T: Pin> InputFuture<'d, T> { + /// Create a new future wiating for input trigger. pub fn new(pin: impl Peripheral

+ 'd, level: InterruptTrigger) -> Self { into_ref!(pin); let pin_group = (pin.pin() % 8) as usize; @@ -308,11 +343,13 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> { } } +/// GPIO output driver. pub struct Output<'d, T: Pin> { pin: Flex<'d, T>, } impl<'d, T: Pin> Output<'d, T> { + /// Create GPIO output driver for a [Pin] with the provided [Level]. #[inline] pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { let mut pin = Flex::new(pin); @@ -331,7 +368,7 @@ impl<'d, T: Pin> Output<'d, T> { self.pin.set_drive_strength(strength) } - // Set the pin's slew rate. + /// Set the pin's slew rate. #[inline] pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { self.pin.set_slew_rate(slew_rate) @@ -386,6 +423,7 @@ pub struct OutputOpenDrain<'d, T: Pin> { } impl<'d, T: Pin> OutputOpenDrain<'d, T> { + /// Create GPIO output driver for a [Pin] in open drain mode with the provided [Level]. #[inline] pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { let mut pin = Flex::new(pin); @@ -403,7 +441,7 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { self.pin.set_drive_strength(strength) } - // Set the pin's slew rate. + /// Set the pin's slew rate. #[inline] pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { self.pin.set_slew_rate(slew_rate) @@ -456,11 +494,13 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { self.pin.toggle_set_as_output() } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { self.pin.is_high() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.pin.is_low() @@ -472,26 +512,31 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { self.is_high().into() } + /// Wait until the pin is high. If it is already high, return immediately. #[inline] pub async fn wait_for_high(&mut self) { self.pin.wait_for_high().await; } + /// Wait until the pin is low. If it is already low, return immediately. #[inline] pub async fn wait_for_low(&mut self) { self.pin.wait_for_low().await; } + /// Wait for the pin to undergo a transition from low to high. #[inline] pub async fn wait_for_rising_edge(&mut self) { self.pin.wait_for_rising_edge().await; } + /// Wait for the pin to undergo a transition from high to low. #[inline] pub async fn wait_for_falling_edge(&mut self) { self.pin.wait_for_falling_edge().await; } + /// Wait for the pin to undergo any transition, i.e low to high OR high to low. #[inline] pub async fn wait_for_any_edge(&mut self) { self.pin.wait_for_any_edge().await; @@ -508,6 +553,10 @@ pub struct Flex<'d, T: Pin> { } impl<'d, T: Pin> Flex<'d, T> { + /// Wrap the pin in a `Flex`. + /// + /// The pin remains disconnected. The initial output level is unspecified, but can be changed + /// before the pin is put into output mode. #[inline] pub fn new(pin: impl Peripheral

+ 'd) -> Self { into_ref!(pin); @@ -556,7 +605,7 @@ impl<'d, T: Pin> Flex<'d, T> { }); } - // Set the pin's slew rate. + /// Set the pin's slew rate. #[inline] pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { self.pin.pad_ctrl().modify(|w| { @@ -589,6 +638,7 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.sio_oe().value_set().write_value(self.bit()) } + /// Set as output pin. #[inline] pub fn is_set_as_output(&mut self) -> bool { self.ref_is_set_as_output() @@ -599,15 +649,18 @@ impl<'d, T: Pin> Flex<'d, T> { (self.pin.sio_oe().value().read() & self.bit()) != 0 } + /// Toggle output pin. #[inline] pub fn toggle_set_as_output(&mut self) { self.pin.sio_oe().value_xor().write_value(self.bit()) } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { !self.is_low() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { @@ -675,31 +728,37 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.sio_out().value_xor().write_value(self.bit()) } + /// Wait until the pin is high. If it is already high, return immediately. #[inline] pub async fn wait_for_high(&mut self) { InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await; } + /// Wait until the pin is low. If it is already low, return immediately. #[inline] pub async fn wait_for_low(&mut self) { InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await; } + /// Wait for the pin to undergo a transition from low to high. #[inline] pub async fn wait_for_rising_edge(&mut self) { InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await; } + /// Wait for the pin to undergo a transition from high to low. #[inline] pub async fn wait_for_falling_edge(&mut self) { InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await; } + /// Wait for the pin to undergo any transition, i.e low to high OR high to low. #[inline] pub async fn wait_for_any_edge(&mut self) { InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await; } + /// Configure dormant wake. #[inline] pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake { let idx = self.pin._pin() as usize; @@ -737,6 +796,7 @@ impl<'d, T: Pin> Drop for Flex<'d, T> { } } +/// Dormant wake driver. pub struct DormantWake<'w, T: Pin> { pin: PeripheralRef<'w, T>, cfg: DormantWakeConfig, @@ -818,6 +878,7 @@ pub(crate) mod sealed { } } +/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'static { /// Degrade to a generic pin struct fn degrade(self) -> AnyPin { @@ -839,6 +900,7 @@ pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'stat } } +/// Type-erased GPIO pin pub struct AnyPin { pin_bank: u8, } diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 15095236a..74d015792 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -1,3 +1,4 @@ +//! I2C driver. use core::future; use core::marker::PhantomData; use core::task::Poll; @@ -22,6 +23,7 @@ pub enum AbortReason { ArbitrationLoss, /// Transmit ended with data still in fifo TxNotEmpty(u16), + /// Other reason. Other(u32), } @@ -41,9 +43,11 @@ pub enum Error { AddressReserved(u16), } +/// I2C config. #[non_exhaustive] #[derive(Copy, Clone)] pub struct Config { + /// Frequency. pub frequency: u32, } @@ -53,13 +57,16 @@ impl Default for Config { } } +/// Size of I2C FIFO. pub const FIFO_SIZE: u8 = 16; +/// I2C driver. pub struct I2c<'d, T: Instance, M: Mode> { phantom: PhantomData<(&'d mut T, M)>, } impl<'d, T: Instance> I2c<'d, T, Blocking> { + /// Create a new driver instance in blocking mode. pub fn new_blocking( peri: impl Peripheral

+ 'd, scl: impl Peripheral

> + 'd, @@ -72,6 +79,7 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> { } impl<'d, T: Instance> I2c<'d, T, Async> { + /// Create a new driver instance in async mode. pub fn new_async( peri: impl Peripheral

+ 'd, scl: impl Peripheral

> + 'd, @@ -292,16 +300,19 @@ impl<'d, T: Instance> I2c<'d, T, Async> { } } + /// Read from address into buffer using DMA. pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { Self::setup(addr)?; self.read_async_internal(buffer, true, true).await } + /// Write to address from buffer using DMA. pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator) -> Result<(), Error> { Self::setup(addr)?; self.write_async_internal(bytes, true).await } + /// Write to address from bytes and read from address into buffer using DMA. pub async fn write_read_async( &mut self, addr: u16, @@ -314,6 +325,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { } } +/// Interrupt handler. pub struct InterruptHandler { _uart: PhantomData, } @@ -569,17 +581,20 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { // Blocking public API // ========================= + /// Read from address into buffer blocking caller until done. pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { Self::setup(address.into())?; self.read_blocking_internal(read, true, true) // Automatic Stop } + /// Write to address from buffer blocking caller until done. pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { Self::setup(address.into())?; self.write_blocking_internal(write, true) } + /// Write to address from bytes and read from address into buffer blocking caller until done. pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { Self::setup(address.into())?; self.write_blocking_internal(write, false)?; @@ -742,6 +757,7 @@ where } } +/// Check if address is reserved. pub fn i2c_reserved_addr(addr: u16) -> bool { ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 } @@ -768,6 +784,7 @@ mod sealed { pub trait SclPin {} } +/// Driver mode. pub trait Mode: sealed::Mode {} macro_rules! impl_mode { @@ -777,12 +794,15 @@ macro_rules! impl_mode { }; } +/// Blocking mode. pub struct Blocking; +/// Async mode. pub struct Async; impl_mode!(Blocking); impl_mode!(Async); +/// I2C instance. pub trait Instance: sealed::Instance {} macro_rules! impl_instance { @@ -819,7 +839,9 @@ macro_rules! impl_instance { impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); +/// SDA pin. pub trait SdaPin: sealed::SdaPin + crate::gpio::Pin {} +/// SCL pin. pub trait SclPin: sealed::SclPin + crate::gpio::Pin {} macro_rules! impl_pin { diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 9271ede3a..721b7a1f6 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -1,3 +1,4 @@ +//! I2C slave driver. use core::future; use core::marker::PhantomData; use core::task::Poll; @@ -63,11 +64,13 @@ impl Default for Config { } } +/// I2CSlave driver. pub struct I2cSlave<'d, T: Instance> { phantom: PhantomData<&'d mut T>, } impl<'d, T: Instance> I2cSlave<'d, T> { + /// Create a new instance. pub fn new( _peri: impl Peripheral

+ 'd, scl: impl Peripheral

> + 'd, diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 2c49787df..004b94589 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![allow(async_fn_in_trait)] #![doc = include_str!("../README.md")] +#![warn(missing_docs)] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index ae91d1e83..ca9795024 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -1,3 +1,4 @@ +//! PIO driver. use core::future::Future; use core::marker::PhantomData; use core::pin::Pin as FuturePin; diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 5b96557a3..784a05f92 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -119,11 +119,13 @@ impl<'d, T: Channel> Pwm<'d, T> { } } + /// Create PWM driver without any configured pins. #[inline] pub fn new_free(inner: impl Peripheral

+ 'd, config: Config) -> Self { Self::new_inner(inner, None, None, config, Divmode::DIV) } + /// Create PWM driver with a single 'a' as output. #[inline] pub fn new_output_a( inner: impl Peripheral

+ 'd, @@ -134,6 +136,7 @@ impl<'d, T: Channel> Pwm<'d, T> { Self::new_inner(inner, Some(a.map_into()), None, config, Divmode::DIV) } + /// Create PWM driver with a single 'b' pin as output. #[inline] pub fn new_output_b( inner: impl Peripheral

+ 'd, @@ -144,6 +147,7 @@ impl<'d, T: Channel> Pwm<'d, T> { Self::new_inner(inner, None, Some(b.map_into()), config, Divmode::DIV) } + /// Create PWM driver with a 'a' and 'b' pins as output. #[inline] pub fn new_output_ab( inner: impl Peripheral

+ 'd, @@ -155,6 +159,7 @@ impl<'d, T: Channel> Pwm<'d, T> { Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, Divmode::DIV) } + /// Create PWM driver with a single 'b' as input pin. #[inline] pub fn new_input( inner: impl Peripheral

+ 'd, @@ -166,6 +171,7 @@ impl<'d, T: Channel> Pwm<'d, T> { Self::new_inner(inner, None, Some(b.map_into()), config, mode.into()) } + /// Create PWM driver with a 'a' and 'b' pins in the desired input mode. #[inline] pub fn new_output_input( inner: impl Peripheral

+ 'd, @@ -178,6 +184,7 @@ impl<'d, T: Channel> Pwm<'d, T> { Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, mode.into()) } + /// Set the PWM config. pub fn set_config(&mut self, config: &Config) { Self::configure(self.inner.regs(), config); } @@ -221,28 +228,33 @@ impl<'d, T: Channel> Pwm<'d, T> { while p.csr().read().ph_ret() {} } + /// Read PWM counter. #[inline] pub fn counter(&self) -> u16 { self.inner.regs().ctr().read().ctr() } + /// Write PWM counter. #[inline] pub fn set_counter(&self, ctr: u16) { self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) } + /// Wait for channel interrupt. #[inline] pub fn wait_for_wrap(&mut self) { while !self.wrapped() {} self.clear_wrapped(); } + /// Check if interrupt for channel is set. #[inline] pub fn wrapped(&mut self) -> bool { pac::PWM.intr().read().0 & self.bit() != 0 } #[inline] + /// Clear interrupt flag. pub fn clear_wrapped(&mut self) { pac::PWM.intr().write_value(Intr(self.bit() as _)); } @@ -253,15 +265,18 @@ impl<'d, T: Channel> Pwm<'d, T> { } } +/// Batch representation of PWM channels. pub struct PwmBatch(u32); impl PwmBatch { #[inline] + /// Enable a PWM channel in this batch. pub fn enable(&mut self, pwm: &Pwm<'_, impl Channel>) { self.0 |= pwm.bit(); } #[inline] + /// Enable channels in this batch in a PWM. pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { let mut en = PwmBatch(0); batch(&mut en); @@ -289,9 +304,12 @@ mod sealed { pub trait Channel {} } +/// PWM Channel. pub trait Channel: Peripheral

+ sealed::Channel + Sized + 'static { + /// Channel number. fn number(&self) -> u8; + /// Channel register block. fn regs(&self) -> pac::pwm::Channel { pac::PWM.ch(self.number() as _) } @@ -317,7 +335,9 @@ channel!(PWM_CH5, 5); channel!(PWM_CH6, 6); channel!(PWM_CH7, 7); +/// PWM Pin A. pub trait PwmPinA: GpioPin {} +/// PWM Pin B. pub trait PwmPinB: GpioPin {} macro_rules! impl_pin { diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index c3df3ee57..b696989f5 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -1,3 +1,4 @@ +//! RTC driver. mod filter; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs index faa8df037..69c0c85b1 100644 --- a/embassy-rp/src/timer.rs +++ b/embassy-rp/src/timer.rs @@ -1,3 +1,4 @@ +//! Timer driver. use core::cell::Cell; use atomic_polyfill::{AtomicU8, Ordering}; diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index f14e08525..99c958129 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -1,3 +1,4 @@ +//! Buffered UART driver. use core::future::{poll_fn, Future}; use core::slice; use core::task::Poll; diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 32be7661d..99fce0fc9 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -1,3 +1,4 @@ +//! UART driver. use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; @@ -947,7 +948,7 @@ pub struct Async; impl_mode!(Blocking); impl_mode!(Async); -/// UART instance trait. +/// UART instance. pub trait Instance: sealed::Instance {} macro_rules! impl_instance { diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index bcd848222..905661d64 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -1,3 +1,4 @@ +//! USB driver. use core::future::poll_fn; use core::marker::PhantomData; use core::slice; From 39c166ef9b754c5caa44ef4dd4a4e216078dbcea Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 16:08:06 +0100 Subject: [PATCH 063/760] docs: document public apis for cyw43 driver --- cyw43-pio/README.md | 17 +++++++++++++++++ cyw43-pio/src/lib.rs | 6 ++++++ cyw43/README.md | 4 ++++ cyw43/src/control.rs | 16 +++++++++++++++- cyw43/src/lib.rs | 10 ++++++++++ cyw43/src/runner.rs | 2 ++ cyw43/src/structs.rs | 14 +++++++++++++- 7 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 cyw43-pio/README.md diff --git a/cyw43-pio/README.md b/cyw43-pio/README.md new file mode 100644 index 000000000..2b22db360 --- /dev/null +++ b/cyw43-pio/README.md @@ -0,0 +1,17 @@ +# cyw43-pio + +RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. The PIO driver offloads SPI communication with the WiFi chip and improves throughput. + +## Minimum supported Rust version (MSRV) + +Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 8304740b3..5efab10e4 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -1,5 +1,7 @@ #![no_std] #![allow(async_fn_in_trait)] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] use core::slice; @@ -11,6 +13,7 @@ use embassy_rp::{Peripheral, PeripheralRef}; use fixed::FixedU32; use pio_proc::pio_asm; +/// SPI comms driven by PIO. pub struct PioSpi<'d, CS: Pin, PIO: Instance, const SM: usize, DMA> { cs: Output<'d, CS>, sm: StateMachine<'d, PIO, SM>, @@ -25,6 +28,7 @@ where CS: Pin, PIO: Instance, { + /// Create a new instance of PioSpi. pub fn new( common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, @@ -143,6 +147,7 @@ where } } + /// Write data to peripheral and return status. pub async fn write(&mut self, write: &[u32]) -> u32 { self.sm.set_enable(false); let write_bits = write.len() * 32 - 1; @@ -170,6 +175,7 @@ where status } + /// Send command and read response into buffer. pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 { self.sm.set_enable(false); let write_bits = 31; diff --git a/cyw43/README.md b/cyw43/README.md index 5b8f3cf40..2c24c7d36 100644 --- a/cyw43/README.md +++ b/cyw43/README.md @@ -45,6 +45,10 @@ nc 192.168.0.250 1234 ``` Send it some data, you should see it echoed back and printed in the firmware's logs. +## Minimum supported Rust version (MSRV) + +Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. + ## License This work is licensed under either of diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 826edfe1a..311fcb08c 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -12,17 +12,23 @@ use crate::ioctl::{IoctlState, IoctlType}; use crate::structs::*; use crate::{countries, events, PowerManagementMode}; +/// Control errors. #[derive(Debug)] pub struct Error { + /// Status code. pub status: u32, } +/// Multicast errors. #[derive(Debug)] pub enum AddMulticastAddressError { + /// Not a multicast address. NotMulticast, + /// No free address slots. NoFreeSlots, } +/// Control driver. pub struct Control<'a> { state_ch: ch::StateRunner<'a>, events: &'a Events, @@ -38,6 +44,7 @@ impl<'a> Control<'a> { } } + /// Initialize WiFi controller. pub async fn init(&mut self, clm: &[u8]) { const CHUNK_SIZE: usize = 1024; @@ -154,6 +161,7 @@ impl<'a> Control<'a> { self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; } + /// Set power management mode. pub async fn set_power_management(&mut self, mode: PowerManagementMode) { // power save mode let mode_num = mode.mode(); @@ -166,6 +174,7 @@ impl<'a> Control<'a> { self.ioctl_set_u32(86, 0, mode_num).await; } + /// Join an unprotected network with the provided ssid. pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; @@ -183,6 +192,7 @@ impl<'a> Control<'a> { self.wait_for_join(i).await } + /// Join an protected network with the provided ssid and passphrase. pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; @@ -250,16 +260,19 @@ impl<'a> Control<'a> { } } + /// Set GPIO pin on WiFi chip. pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) { assert!(gpio_n < 3); self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 }) .await } + /// Start open access point. pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) { self.start_ap(ssid, "", Security::OPEN, channel).await; } + /// Start WPA2 protected access point. pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) { self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await; } @@ -494,13 +507,14 @@ impl<'a> Control<'a> { } } +/// WiFi network scanner. pub struct Scanner<'a> { subscriber: EventSubscriber<'a>, events: &'a Events, } impl Scanner<'_> { - /// wait for the next found network + /// Wait for the next found network. pub async fn next(&mut self) -> Option { let event = self.subscriber.next_message_pure().await; if event.header.status != EStatus::PARTIAL { diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 300465e36..19b0cb194 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -2,6 +2,8 @@ #![no_main] #![allow(async_fn_in_trait)] #![deny(unused_must_use)] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -102,6 +104,7 @@ const CHIP: Chip = Chip { chanspec_ctl_sb_mask: 0x0700, }; +/// Driver state. pub struct State { ioctl_state: IoctlState, ch: ch::State, @@ -109,6 +112,7 @@ pub struct State { } impl State { + /// Create new driver state holder. pub fn new() -> Self { Self { ioctl_state: IoctlState::new(), @@ -118,6 +122,7 @@ impl State { } } +/// Power management modes. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PowerManagementMode { /// Custom, officially unsupported mode. Use at your own risk. @@ -203,8 +208,13 @@ impl PowerManagementMode { } } +/// Embassy-net driver. pub type NetDriver<'a> = ch::Device<'a, MTU>; +/// Create a new instance of the CYW43 driver. +/// +/// Returns a handle to the network device, control handle and a runner for driving the low level +/// stack. pub async fn new<'a, PWR, SPI>( state: &'a mut State, pwr: PWR, diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index 83aee6b40..b2a9e3e80 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -34,6 +34,7 @@ impl Default for LogState { } } +/// Driver communicating with the WiFi chip. pub struct Runner<'a, PWR, SPI> { ch: ch::Runner<'a, MTU>, bus: Bus, @@ -222,6 +223,7 @@ where } } + /// Run the pub async fn run(mut self) -> ! { let mut buf = [0; 512]; loop { diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs index 5ba633c74..5ea62d95b 100644 --- a/cyw43/src/structs.rs +++ b/cyw43/src/structs.rs @@ -4,13 +4,16 @@ use crate::fmt::Bytes; macro_rules! impl_bytes { ($t:ident) => { impl $t { + /// Bytes consumed by this type. pub const SIZE: usize = core::mem::size_of::(); + /// Convert to byte array. #[allow(unused)] pub fn to_bytes(&self) -> [u8; Self::SIZE] { unsafe { core::mem::transmute(*self) } } + /// Create from byte array. #[allow(unused)] pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self { let alignment = core::mem::align_of::(); @@ -23,6 +26,7 @@ macro_rules! impl_bytes { unsafe { core::mem::transmute(bytes) } } + /// Create from mutable byte array. #[allow(unused)] pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self { let alignment = core::mem::align_of::(); @@ -204,6 +208,7 @@ pub struct EthernetHeader { } impl EthernetHeader { + /// Swap endianness. pub fn byteswap(&mut self) { self.ether_type = self.ether_type.to_be(); } @@ -472,19 +477,26 @@ impl ScanResults { #[repr(C, packed(2))] #[non_exhaustive] pub struct BssInfo { + /// Version. pub version: u32, + /// Length. pub length: u32, + /// BSSID. pub bssid: [u8; 6], + /// Beacon period. pub beacon_period: u16, + /// Capability. pub capability: u16, + /// SSID length. pub ssid_len: u8, + /// SSID. pub ssid: [u8; 32], // there will be more stuff here } impl_bytes!(BssInfo); impl BssInfo { - pub fn parse(packet: &mut [u8]) -> Option<&mut Self> { + pub(crate) fn parse(packet: &mut [u8]) -> Option<&mut Self> { if packet.len() < BssInfo::SIZE { return None; } From 1ea87ec6e752dca60e13731863e11d0e0f5c0492 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 16:18:24 +0100 Subject: [PATCH 064/760] stm32: document hrtim, qspi, sdmmc, spi. --- embassy-stm32/src/hrtim/mod.rs | 59 +++++++++++++++++++++---------- embassy-stm32/src/hrtim/traits.rs | 6 +--- embassy-stm32/src/lib.rs | 24 +------------ embassy-stm32/src/qspi/enums.rs | 2 ++ embassy-stm32/src/qspi/mod.rs | 11 ++++++ embassy-stm32/src/sdmmc/mod.rs | 39 ++++++++++++++------ embassy-stm32/src/spi/mod.rs | 46 +++++++++++++++++++++++- embassy-stm32/src/time.rs | 3 ++ 8 files changed, 132 insertions(+), 58 deletions(-) diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 6539326b4..1e6626a58 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -15,38 +15,42 @@ use crate::rcc::get_freqs; use crate::time::Hertz; use crate::Peripheral; -pub enum Source { - Master, - ChA, - ChB, - ChC, - ChD, - ChE, - #[cfg(hrtim_v2)] - ChF, -} - +/// HRTIM burst controller instance. pub struct BurstController { phantom: PhantomData, } + +/// HRTIM master instance. pub struct Master { phantom: PhantomData, } + +/// HRTIM channel A instance. pub struct ChA { phantom: PhantomData, } + +/// HRTIM channel B instance. pub struct ChB { phantom: PhantomData, } + +/// HRTIM channel C instance. pub struct ChC { phantom: PhantomData, } + +/// HRTIM channel D instance. pub struct ChD { phantom: PhantomData, } + +/// HRTIM channel E instance. pub struct ChE { phantom: PhantomData, } + +/// HRTIM channel F instance. #[cfg(hrtim_v2)] pub struct ChF { phantom: PhantomData, @@ -60,13 +64,16 @@ mod sealed { } } +/// Advanced channel instance trait. pub trait AdvancedChannel: sealed::AdvancedChannel {} +/// HRTIM PWM pin. pub struct PwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, phantom: PhantomData<(Perip, Channel)>, } +/// HRTIM complementary PWM pin. pub struct ComplementaryPwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, phantom: PhantomData<(Perip, Channel)>, @@ -75,6 +82,7 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> { macro_rules! advanced_channel_impl { ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -91,6 +99,7 @@ macro_rules! advanced_channel_impl { } impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -126,18 +135,29 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); /// Struct used to divide a high resolution timer into multiple channels pub struct AdvancedPwm<'d, T: Instance> { _inner: PeripheralRef<'d, T>, + /// Master instance. pub master: Master, + /// Burst controller. pub burst_controller: BurstController, + /// Channel A. pub ch_a: ChA, + /// Channel B. pub ch_b: ChB, + /// Channel C. pub ch_c: ChC, + /// Channel D. pub ch_d: ChD, + /// Channel E. pub ch_e: ChE, + /// Channel F. #[cfg(hrtim_v2)] pub ch_f: ChF, } impl<'d, T: Instance> AdvancedPwm<'d, T> { + /// Create a new HRTIM driver. + /// + /// This splits the HRTIM into its constituent parts, which you can then use individually. pub fn new( tim: impl Peripheral

+ 'd, _cha: Option>>, @@ -200,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { } } -impl BurstController { - pub fn set_source(&mut self, _source: Source) { - todo!("burst mode control registers not implemented") - } -} - -/// Represents a fixed-frequency bridge converter +/// Fixed-frequency bridge converter driver. /// /// Our implementation of the bridge converter uses a single channel and three compare registers, /// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous @@ -225,6 +239,7 @@ pub struct BridgeConverter> { } impl> BridgeConverter { + /// Create a new HRTIM bridge converter driver. pub fn new(_channel: C, frequency: Hertz) -> Self { use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; @@ -281,14 +296,17 @@ impl> BridgeConverter { } } + /// Start HRTIM. pub fn start(&mut self) { T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); } + /// Stop HRTIM. pub fn stop(&mut self) { T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); } + /// Enable burst mode. pub fn enable_burst_mode(&mut self) { T::regs().tim(C::raw()).outr().modify(|w| { // Enable Burst Mode @@ -301,6 +319,7 @@ impl> BridgeConverter { }) } + /// Disable burst mode. pub fn disable_burst_mode(&mut self) { T::regs().tim(C::raw()).outr().modify(|w| { // Disable Burst Mode @@ -357,7 +376,7 @@ impl> BridgeConverter { } } -/// Represents a variable-frequency resonant converter +/// Variable-frequency resonant converter driver. /// /// This implementation of a resonsant converter is appropriate for a half or full bridge, /// but does not include secondary rectification, which is appropriate for applications @@ -370,6 +389,7 @@ pub struct ResonantConverter> { } impl> ResonantConverter { + /// Create a new variable-frequency resonant converter driver. pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { T::set_channel_frequency(C::raw(), min_frequency); @@ -408,6 +428,7 @@ impl> ResonantConverter { T::set_channel_dead_time(C::raw(), value); } + /// Set the timer period. pub fn set_period(&mut self, period: u16) { assert!(period < self.max_period); assert!(period > self.min_period); diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 34a363a1f..cfd31c47c 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -125,7 +125,6 @@ pub(crate) mod sealed { } /// Set the dead time as a proportion of max_duty - fn set_channel_dead_time(channel: usize, dead_time: u16) { let regs = Self::regs(); @@ -148,13 +147,10 @@ pub(crate) mod sealed { w.set_dtr(dt_val as u16); }); } - - // fn enable_outputs(enable: bool); - // - // fn enable_channel(&mut self, channel: usize, enable: bool); } } +/// HRTIM instance trait. pub trait Instance: sealed::Instance + 'static {} foreach_interrupt! { diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index fd691a732..5d9b4e6a0 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -149,33 +149,15 @@ use crate::interrupt::Priority; pub use crate::pac::NVIC_PRIO_BITS; use crate::rcc::sealed::RccPeripheral; -/// `embassy-stm32` global configuration. #[non_exhaustive] pub struct Config { - /// RCC config. pub rcc: rcc::Config, - - /// Enable debug during sleep. - /// - /// May incrase power consumption. Defaults to true. #[cfg(dbgmcu)] pub enable_debug_during_sleep: bool, - - /// BDMA interrupt priority. - /// - /// Defaults to P0 (highest). #[cfg(bdma)] pub bdma_interrupt_priority: Priority, - - /// DMA interrupt priority. - /// - /// Defaults to P0 (highest). #[cfg(dma)] pub dma_interrupt_priority: Priority, - - /// GPDMA interrupt priority. - /// - /// Defaults to P0 (highest). #[cfg(gpdma)] pub gpdma_interrupt_priority: Priority, } @@ -196,11 +178,7 @@ impl Default for Config { } } -/// Initialize the `embassy-stm32` HAL with the provided configuration. -/// -/// This returns the peripheral singletons that can be used for creating drivers. -/// -/// This should only be called once at startup, otherwise it panics. +/// Initialize embassy. pub fn init(config: Config) -> Peripherals { critical_section::with(|cs| { let p = Peripherals::take_with_cs(cs); diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs index e9e7fd482..ecade9b1a 100644 --- a/embassy-stm32/src/qspi/enums.rs +++ b/embassy-stm32/src/qspi/enums.rs @@ -1,3 +1,5 @@ +//! Enums used in QSPI configuration. + #[allow(dead_code)] #[derive(Copy, Clone)] pub(crate) enum QspiMode { diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 9ea0a726c..8a709a89e 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -14,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; +/// QSPI transfer configuration. pub struct TransferConfig { /// Instraction width (IMODE) pub iwidth: QspiWidth, @@ -45,6 +46,7 @@ impl Default for TransferConfig { } } +/// QSPI driver configuration. pub struct Config { /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. /// If you need other value the whose predefined use `Other` variant. @@ -71,6 +73,7 @@ impl Default for Config { } } +/// QSPI driver. #[allow(dead_code)] pub struct Qspi<'d, T: Instance, Dma> { _peri: PeripheralRef<'d, T>, @@ -85,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> { } impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { + /// Create a new QSPI driver for bank 1. pub fn new_bk1( peri: impl Peripheral

+ 'd, d0: impl Peripheral

> + 'd, @@ -125,6 +129,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { ) } + /// Create a new QSPI driver for bank 2. pub fn new_bk2( peri: impl Peripheral

+ 'd, d0: impl Peripheral

> + 'd, @@ -223,6 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { } } + /// Do a QSPI command. pub fn command(&mut self, transaction: TransferConfig) { #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(false)); @@ -232,6 +238,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { T::REGS.fcr().modify(|v| v.set_ctcf(true)); } + /// Blocking read data. pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(false)); @@ -256,6 +263,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { T::REGS.fcr().modify(|v| v.set_ctcf(true)); } + /// Blocking write data. pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { // STM32H7 does not have dmaen #[cfg(not(stm32h7))] @@ -278,6 +286,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { T::REGS.fcr().modify(|v| v.set_ctcf(true)); } + /// Blocking read data, using DMA. pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) where Dma: QuadDma, @@ -310,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { transfer.blocking_wait(); } + /// Blocking write data, using DMA. pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) where Dma: QuadDma, @@ -379,6 +389,7 @@ pub(crate) mod sealed { } } +/// QSPI instance trait. pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} pin_trait!(SckPin, Instance); diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 6099b9f43..ab142053a 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -54,6 +54,7 @@ const SD_INIT_FREQ: Hertz = Hertz(400_000); /// The signalling scheme used on the SDMMC bus #[non_exhaustive] +#[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Signalling { @@ -70,6 +71,9 @@ impl Default for Signalling { } } +/// Aligned data block for SDMMC transfers. +/// +/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements. #[repr(align(4))] #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -94,17 +98,23 @@ impl DerefMut for DataBlock { #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Timeout reported by the hardware Timeout, + /// Timeout reported by the software driver. SoftwareTimeout, + /// Unsupported card version. UnsupportedCardVersion, + /// Unsupported card type. UnsupportedCardType, + /// CRC error. Crc, - DataCrcFail, - RxOverFlow, + /// No card inserted. NoCard, + /// Bad clock supplied to the SDMMC peripheral. BadClock, + /// Signaling switch failed. SignalingSwitchFailed, - PeripheralBusy, + /// ST bit error. #[cfg(sdmmc_v1)] StBitErr, } @@ -363,6 +373,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { #[cfg(sdmmc_v2)] impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { + /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -396,6 +407,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { ) } + /// Create a new SDMMC driver, with 4 data lanes. pub fn new_4bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -497,7 +509,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Data transfer is in progress - #[inline(always)] + #[inline] fn data_active() -> bool { let regs = T::regs(); @@ -509,7 +521,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Coammand transfer is in progress - #[inline(always)] + #[inline] fn cmd_active() -> bool { let regs = T::regs(); @@ -521,7 +533,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) - #[inline(always)] + #[inline] fn wait_idle() { while Self::data_active() || Self::cmd_active() {} } @@ -837,7 +849,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Clear flags in interrupt clear register - #[inline(always)] + #[inline] fn clear_interrupt_flags() { let regs = T::regs(); regs.icr().write(|w| { @@ -1152,7 +1164,8 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Ok(()) } - #[inline(always)] + /// Read a data block. + #[inline] pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { let card_capacity = self.card()?.card_type; @@ -1204,6 +1217,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { res } + /// Write a data block. pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { let card = self.card.as_mut().ok_or(Error::NoCard)?; @@ -1283,7 +1297,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// /// Returns Error::NoCard if [`init_card`](#method.init_card) /// has not previously succeeded - #[inline(always)] + #[inline] pub fn card(&self) -> Result<&Card, Error> { self.card.as_ref().ok_or(Error::NoCard) } @@ -1419,7 +1433,9 @@ pub(crate) mod sealed { pub trait Pins {} } +/// SDMMC instance trait. pub trait Instance: sealed::Instance + RccPeripheral + 'static {} + pin_trait!(CkPin, Instance); pin_trait!(CmdPin, Instance); pin_trait!(D0Pin, Instance); @@ -1434,7 +1450,10 @@ pin_trait!(D7Pin, Instance); #[cfg(sdmmc_v1)] dma_trait!(SdmmcDma, Instance); -// SDMMCv2 uses internal DMA +/// DMA instance trait. +/// +/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of +/// using ST's system-wide DMA peripheral. #[cfg(sdmmc_v2)] pub trait SdmmcDma {} #[cfg(sdmmc_v2)] diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 5a1ad3e91..674a5d316 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -16,27 +16,38 @@ use crate::rcc::RccPeripheral; use crate::time::Hertz; use crate::{peripherals, Peripheral}; +/// SPI error. #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Invalid framing. Framing, + /// CRC error (only if hardware CRC checking is enabled). Crc, + /// Mode fault ModeFault, + /// Overrun. Overrun, } -// TODO move upwards in the tree +/// SPI bit order #[derive(Copy, Clone)] pub enum BitOrder { + /// Least significant bit first. LsbFirst, + /// Most significant bit first. MsbFirst, } +/// SPI configuration. #[non_exhaustive] #[derive(Copy, Clone)] pub struct Config { + /// SPI mode. pub mode: Mode, + /// Bit order. pub bit_order: BitOrder, + /// Clock frequency. pub frequency: Hertz, } @@ -73,6 +84,7 @@ impl Config { } } +/// SPI driver. pub struct Spi<'d, T: Instance, Tx, Rx> { _peri: PeripheralRef<'d, T>, sck: Option>, @@ -84,6 +96,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> { } impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { + /// Create a new SPI driver. pub fn new( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, @@ -118,6 +131,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { ) } + /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI). pub fn new_rxonly( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, @@ -143,6 +157,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { ) } + /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO). pub fn new_txonly( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, @@ -168,6 +183,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { ) } + /// Create a new SPI driver, in TX-only mode, without SCK pin. + /// + /// This can be useful for bit-banging non-SPI protocols. pub fn new_txonly_nosck( peri: impl Peripheral

+ 'd, mosi: impl Peripheral

> + 'd, @@ -355,6 +373,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Get current SPI configuration. pub fn get_current_config(&self) -> Config { #[cfg(any(spi_v1, spi_f1, spi_v2))] let cfg = T::REGS.cr1().read(); @@ -444,6 +463,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { self.current_word_size = word_size; } + /// SPI write, using DMA. pub async fn write(&mut self, data: &[W]) -> Result<(), Error> where Tx: TxDma, @@ -477,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// SPI read, using DMA. pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> where Tx: TxDma, @@ -580,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Bidirectional transfer, using DMA. + /// + /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`. + /// + /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. + /// If `write` is shorter it is padded with zero bytes. pub async fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> where Tx: TxDma, @@ -588,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { self.transfer_inner(read, write).await } + /// In-place bidirectional transfer, using DMA. + /// + /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. pub async fn transfer_in_place(&mut self, data: &mut [W]) -> Result<(), Error> where Tx: TxDma, @@ -596,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { self.transfer_inner(data, data).await } + /// Blocking write. pub fn blocking_write(&mut self, words: &[W]) -> Result<(), Error> { T::REGS.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(T::REGS); @@ -606,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Blocking read. pub fn blocking_read(&mut self, words: &mut [W]) -> Result<(), Error> { T::REGS.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(T::REGS); @@ -616,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Blocking in-place bidirectional transfer. + /// + /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. pub fn blocking_transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Error> { T::REGS.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(T::REGS); @@ -626,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Blocking bidirectional transfer. + /// + /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`. + /// + /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. + /// If `write` is shorter it is padded with zero bytes. pub fn blocking_transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { T::REGS.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(T::REGS); @@ -946,6 +987,7 @@ pub(crate) mod sealed { } } +/// Word sizes usable for SPI. pub trait Word: word::Word + sealed::Word {} macro_rules! impl_word { @@ -1025,7 +1067,9 @@ mod word_impl { impl_word!(u32, 32 - 1); } +/// SPI instance trait. pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} + pin_trait!(SckPin, Instance); pin_trait!(MosiPin, Instance); pin_trait!(MisoPin, Instance); diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index a0bc33944..17690aefc 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs @@ -8,14 +8,17 @@ use core::ops::{Div, Mul}; pub struct Hertz(pub u32); impl Hertz { + /// Create a `Hertz` from the given hertz. pub const fn hz(hertz: u32) -> Self { Self(hertz) } + /// Create a `Hertz` from the given kilohertz. pub const fn khz(kilohertz: u32) -> Self { Self(kilohertz * 1_000) } + /// Create a `Hertz` from the given megahertz. pub const fn mhz(megahertz: u32) -> Self { Self(megahertz * 1_000_000) } From 9ddf8b08e448caca3825fc47aa737247323d8725 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 16:33:05 +0100 Subject: [PATCH 065/760] docs: document usb-logger and usb-dfu --- embassy-usb-dfu/README.md | 20 +++++++++++++++++++ embassy-usb-dfu/src/application.rs | 1 + embassy-usb-dfu/src/consts.rs | 12 ++++++++--- embassy-usb-dfu/src/{bootloader.rs => dfu.rs} | 1 + embassy-usb-dfu/src/lib.rs | 11 +++++++--- embassy-usb-logger/README.md | 14 +++++++++++++ 6 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 embassy-usb-dfu/README.md rename embassy-usb-dfu/src/{bootloader.rs => dfu.rs} (99%) diff --git a/embassy-usb-dfu/README.md b/embassy-usb-dfu/README.md new file mode 100644 index 000000000..d8bc19bfd --- /dev/null +++ b/embassy-usb-dfu/README.md @@ -0,0 +1,20 @@ +# embassy-usb-dfu + +An implementation of the USB DFU 1.1 protocol using embassy-boot. It has 2 components depending on which feature is enabled by the user. + +* DFU protocol mode, enabled by the `dfu` feature. This mode corresponds to the transfer phase DFU protocol described by the USB IF. It supports DFU_DNLOAD requests if marked by the user, and will automatically reset the chip once a DFU transaction has been completed. It also responds to DFU_GETSTATUS, DFU_GETSTATE, DFU_ABORT, and DFU_CLRSTATUS with no user intervention. +* DFU runtime mode, enabled by the `application feature`. This mode allows users to expose a DFU interface on their USB device, informing the host of the capability to DFU over USB, and allowing the host to reset the device into its bootloader to complete a DFU operation. Supports DFU_GETSTATUS and DFU_DETACH. When detach/reset is seen by the device as described by the standard, will write a new DFU magic number into the bootloader state in flash, and reset the system. + +## Minimum supported Rust version (MSRV) + +Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 75689db26..f0d7626f6 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -24,6 +24,7 @@ pub struct Control<'d, STATE: NorFlash, RST: Reset> { } impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { + /// Create a new DFU instance to expose a DFU interface. pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { Control { firmware_state, diff --git a/embassy-usb-dfu/src/consts.rs b/embassy-usb-dfu/src/consts.rs index b359a107e..f8a056e5c 100644 --- a/embassy-usb-dfu/src/consts.rs +++ b/embassy-usb-dfu/src/consts.rs @@ -1,3 +1,4 @@ +//! USB DFU constants. pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE; pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01; #[allow(unused)] @@ -18,10 +19,15 @@ defmt::bitflags! { #[cfg(not(feature = "defmt"))] bitflags::bitflags! { + /// Attributes supported by the DFU controller. pub struct DfuAttributes: u8 { + /// Generate WillDetache sequence on bus. const WILL_DETACH = 0b0000_1000; + /// Device can communicate during manifestation phase. const MANIFESTATION_TOLERANT = 0b0000_0100; + /// Capable of upload. const CAN_UPLOAD = 0b0000_0010; + /// Capable of download. const CAN_DOWNLOAD = 0b0000_0001; } } @@ -29,7 +35,7 @@ bitflags::bitflags! { #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u8)] #[allow(unused)] -pub enum State { +pub(crate) enum State { AppIdle = 0, AppDetach = 1, DfuIdle = 2, @@ -46,7 +52,7 @@ pub enum State { #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u8)] #[allow(unused)] -pub enum Status { +pub(crate) enum Status { Ok = 0x00, ErrTarget = 0x01, ErrFile = 0x02, @@ -67,7 +73,7 @@ pub enum Status { #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u8)] -pub enum Request { +pub(crate) enum Request { Detach = 0, Dnload = 1, Upload = 2, diff --git a/embassy-usb-dfu/src/bootloader.rs b/embassy-usb-dfu/src/dfu.rs similarity index 99% rename from embassy-usb-dfu/src/bootloader.rs rename to embassy-usb-dfu/src/dfu.rs index d41e6280d..e99aa70c3 100644 --- a/embassy-usb-dfu/src/bootloader.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -23,6 +23,7 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S } impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> { + /// Create a new DFU instance to handle DFU transfers. pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { Self { updater, diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs index 389bb33f2..eaa4b6e33 100644 --- a/embassy-usb-dfu/src/lib.rs +++ b/embassy-usb-dfu/src/lib.rs @@ -1,12 +1,14 @@ #![no_std] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] mod fmt; pub mod consts; #[cfg(feature = "dfu")] -mod bootloader; +mod dfu; #[cfg(feature = "dfu")] -pub use self::bootloader::*; +pub use self::dfu::*; #[cfg(feature = "application")] mod application; @@ -17,7 +19,7 @@ pub use self::application::*; all(feature = "dfu", feature = "application"), not(any(feature = "dfu", feature = "application")) ))] -compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features"); +compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `application` features"); /// Provides a platform-agnostic interface for initiating a system reset. /// @@ -26,9 +28,11 @@ compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `a /// /// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function. pub trait Reset { + /// Reset the device. fn sys_reset() -> !; } +/// Reset immediately. #[cfg(feature = "esp32c3-hal")] pub struct ResetImmediate; @@ -40,6 +44,7 @@ impl Reset for ResetImmediate { } } +/// Reset immediately. #[cfg(feature = "cortex-m")] pub struct ResetImmediate; diff --git a/embassy-usb-logger/README.md b/embassy-usb-logger/README.md index 81b0dcd0e..6cb18e87d 100644 --- a/embassy-usb-logger/README.md +++ b/embassy-usb-logger/README.md @@ -13,3 +13,17 @@ async fn logger_task(driver: Driver<'static, USB>) { embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver); } ``` + +## Minimum supported Rust version (MSRV) + +Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. From f97ef61ef896fa3abff7e35d78823c36ff50d9a8 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Tue, 19 Dec 2023 16:41:00 +0100 Subject: [PATCH 066/760] Documented usart public API --- .vscode/settings.json | 6 +-- embassy-stm32/src/usart/buffered.rs | 12 ++++++ embassy-stm32/src/usart/mod.rs | 54 +++++++++++++++++++++++-- embassy-stm32/src/usart/ringbuffered.rs | 7 +++- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d46ce603b..016df796d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,12 +17,12 @@ //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", "rust-analyzer.cargo.features": [ // Uncomment if the example has a "nightly" feature. - "nightly", + //"nightly", ], "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. - "examples/nrf52840/Cargo.toml", + //"examples/nrf52840/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", @@ -39,7 +39,7 @@ // "examples/stm32g0/Cargo.toml", // "examples/stm32g4/Cargo.toml", // "examples/stm32h5/Cargo.toml", - // "examples/stm32h7/Cargo.toml", + "examples/stm32h7/Cargo.toml", // "examples/stm32l0/Cargo.toml", // "examples/stm32l1/Cargo.toml", // "examples/stm32l4/Cargo.toml", diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index a2e4ceaae..962547bd7 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -82,6 +82,7 @@ impl interrupt::typelevel::Handler for Interrupt } } +/// Buffered UART State pub struct State { rx_waker: AtomicWaker, rx_buf: RingBuffer, @@ -91,6 +92,7 @@ pub struct State { } impl State { + /// Create new state pub const fn new() -> Self { Self { rx_buf: RingBuffer::new(), @@ -101,15 +103,18 @@ impl State { } } +/// Bidirectional buffered UART pub struct BufferedUart<'d, T: BasicInstance> { rx: BufferedUartRx<'d, T>, tx: BufferedUartTx<'d, T>, } +/// Tx-only buffered UART pub struct BufferedUartTx<'d, T: BasicInstance> { phantom: PhantomData<&'d mut T>, } +/// Rx-only buffered UART pub struct BufferedUartRx<'d, T: BasicInstance> { phantom: PhantomData<&'d mut T>, } @@ -142,6 +147,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> { } impl<'d, T: BasicInstance> BufferedUart<'d, T> { + /// Create a new bidirectional buffered UART driver pub fn new( peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -158,6 +164,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } + /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins pub fn new_with_rtscts( peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -185,6 +192,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } + /// Create a new bidirectional buffered UART driver with a driver-enable pin #[cfg(not(any(usart_v1, usart_v2)))] pub fn new_with_de( peri: impl Peripheral

+ 'd, @@ -246,10 +254,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { }) } + /// Split the driver into a Tx and Rx part (useful for sending to separate tasks) pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { (self.tx, self.rx) } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config)?; @@ -337,6 +347,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { } } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config)?; @@ -418,6 +429,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { } } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config)?; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index e2e3bd3eb..8a0c85d2c 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,5 +1,6 @@ //! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART) #![macro_use] +#![warn(missing_docs)] use core::future::poll_fn; use core::marker::PhantomData; @@ -77,21 +78,29 @@ impl interrupt::typelevel::Handler for Interrupt #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Number of data bits pub enum DataBits { + /// 8 Data Bits DataBits8, + /// 9 Data Bits DataBits9, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Parity pub enum Parity { + /// No parity ParityNone, + /// Even Parity ParityEven, + /// Odd Parity ParityOdd, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Number of stop bits pub enum StopBits { #[doc = "1 stop bit"] STOP1, @@ -106,26 +115,37 @@ pub enum StopBits { #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Config Error pub enum ConfigError { + /// Baudrate too low BaudrateTooLow, + /// Baudrate too high BaudrateTooHigh, + /// Rx or Tx not enabled RxOrTxNotEnabled, } #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] +/// Config pub struct Config { + /// Baud rate pub baudrate: u32, + /// Number of data bits pub data_bits: DataBits, + /// Number of stop bits pub stop_bits: StopBits, + /// Parity type pub parity: Parity, - /// if true, on read-like method, if there is a latent error pending, - /// read will abort, the error reported and cleared - /// if false, the error is ignored and cleared + + /// If true: on a read-like method, if there is a latent error pending, + /// the read will abort and the error will be reported and cleared + /// + /// If false: the error is ignored and cleared pub detect_previous_overrun: bool, /// Set this to true if the line is considered noise free. - /// This will increase the receivers tolerance to clock deviations, + /// This will increase the receiver’s tolerance to clock deviations, /// but will effectively disable noise detection. #[cfg(not(usart_v1))] pub assume_noise_free: bool, @@ -188,6 +208,7 @@ enum ReadCompletionEvent { Idle(usize), } +/// Bidirectional UART Driver pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { tx: UartTx<'d, T, TxDma>, rx: UartRx<'d, T, RxDma>, @@ -203,6 +224,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> } } +/// Tx-only UART Driver pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { phantom: PhantomData<&'d mut T>, tx_dma: PeripheralRef<'d, TxDma>, @@ -217,6 +239,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { } } +/// Rx-only UART Driver pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { _peri: PeripheralRef<'d, T>, rx_dma: PeripheralRef<'d, RxDma>, @@ -247,6 +270,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { Self::new_inner(peri, tx, tx_dma, config) } + /// Create a new tx-only UART with a clear-to-send pin pub fn new_with_cts( peri: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, @@ -288,10 +312,12 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { }) } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } + /// Initiate an asynchronous UART write pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> where TxDma: crate::usart::TxDma, @@ -308,6 +334,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { Ok(()) } + /// Perform a blocking UART write pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { let r = T::regs(); for &b in buffer { @@ -317,6 +344,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { Ok(()) } + /// Block until transmission complete pub fn blocking_flush(&mut self) -> Result<(), Error> { let r = T::regs(); while !sr(r).read().tc() {} @@ -338,6 +366,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { Self::new_inner(peri, rx, rx_dma, config) } + /// Create a new rx-only UART with a request-to-send pin pub fn new_with_rts( peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -387,6 +416,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { }) } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -444,6 +474,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { Ok(sr.rxne()) } + /// Initiate an asynchronous UART read pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> where RxDma: crate::usart::RxDma, @@ -453,6 +484,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { Ok(()) } + /// Read a single u8 if there is one available, otherwise return WouldBlock pub fn nb_read(&mut self) -> Result> { let r = T::regs(); if self.check_rx_flags()? { @@ -462,6 +494,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } + /// Perform a blocking read into `buffer` pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { let r = T::regs(); for b in buffer { @@ -471,6 +504,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { Ok(()) } + /// Initiate an asynchronous read with idle line detection enabled pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result where RxDma: crate::usart::RxDma, @@ -695,6 +729,7 @@ impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { } impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { + /// Create a new bidirectional UART pub fn new( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, @@ -711,6 +746,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) } + /// Create a new bidirectional UART with request-to-send and clear-to-send pins pub fn new_with_rtscts( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, @@ -738,6 +774,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } #[cfg(not(any(usart_v1, usart_v2)))] + /// Create a new bidirectional UART with a driver-enable pin pub fn new_with_de( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, @@ -813,6 +850,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { }) } + /// Initiate an asynchronous write pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> where TxDma: crate::usart::TxDma, @@ -820,14 +858,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { self.tx.write(buffer).await } + /// Perform a blocking write pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.blocking_write(buffer) } + /// Block until transmission complete pub fn blocking_flush(&mut self) -> Result<(), Error> { self.tx.blocking_flush() } + /// Initiate an asynchronous read into `buffer` pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> where RxDma: crate::usart::RxDma, @@ -835,14 +876,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { self.rx.read(buffer).await } + /// Read a single `u8` or return `WouldBlock` pub fn nb_read(&mut self) -> Result> { self.rx.nb_read() } + /// Perform a blocking read into `buffer` pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.blocking_read(buffer) } + /// Initiate an an asynchronous read with idle line detection enabled pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result where RxDma: crate::usart::RxDma, @@ -1292,8 +1336,10 @@ pub(crate) mod sealed { } } +/// Basic UART driver instance pub trait BasicInstance: Peripheral

+ sealed::BasicInstance + 'static + Send {} +/// Full UART driver instance pub trait FullInstance: sealed::FullInstance {} pin_trait!(RxPin, BasicInstance); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index f8ada3926..4391bfef7 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -11,6 +11,7 @@ use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, use crate::dma::ReadableRingBuffer; use crate::usart::{Regs, Sr}; +/// Rx-only Ring-buffered UART Driver pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma> { _peri: PeripheralRef<'d, T>, ring_buf: ReadableRingBuffer<'d, RxDma, u8>, @@ -27,8 +28,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> SetConfig for RingBufferedUar impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { /// Turn the `UartRx` into a buffered uart which can continously receive in the background - /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the - /// DMA controller, and must be sufficiently large, such that it will not overflow. + /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the + /// DMA controller, and must be large enough to prevent overflows. pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); @@ -49,6 +50,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { } impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxDma> { + /// Clear the ring buffer and start receiving in the background pub fn start(&mut self) -> Result<(), Error> { // Clear the ring buffer so that it is ready to receive data self.ring_buf.clear(); @@ -64,6 +66,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD Err(err) } + /// Cleanly stop and reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { self.teardown_uart(); reconfigure::(config) From 6564c045317defa309921fed74c0c096973330e4 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Tue, 19 Dec 2023 16:42:51 +0100 Subject: [PATCH 067/760] Reset .vscode/settings.json (doh) --- .vscode/settings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 016df796d..d46ce603b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,12 +17,12 @@ //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", "rust-analyzer.cargo.features": [ // Uncomment if the example has a "nightly" feature. - //"nightly", + "nightly", ], "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. - //"examples/nrf52840/Cargo.toml", + "examples/nrf52840/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", @@ -39,7 +39,7 @@ // "examples/stm32g0/Cargo.toml", // "examples/stm32g4/Cargo.toml", // "examples/stm32h5/Cargo.toml", - "examples/stm32h7/Cargo.toml", + // "examples/stm32h7/Cargo.toml", // "examples/stm32l0/Cargo.toml", // "examples/stm32l1/Cargo.toml", // "examples/stm32l4/Cargo.toml", From 189b15c426a3a9ef7d4024ba7e5de6a255f88ee7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 17:35:38 +0100 Subject: [PATCH 068/760] stm32/timer: docs. --- embassy-stm32/src/hrtim/mod.rs | 16 +- embassy-stm32/src/lib.rs | 25 ++- embassy-stm32/src/timer/complementary_pwm.rs | 31 +++- embassy-stm32/src/timer/mod.rs | 158 +++++++++++++++--- embassy-stm32/src/timer/qei.rs | 23 ++- embassy-stm32/src/timer/simple_pwm.rs | 43 +++-- examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 2 +- .../stm32h7/src/bin/low_level_timer_api.rs | 10 +- 8 files changed, 247 insertions(+), 61 deletions(-) diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 1e6626a58..faefaabbc 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -68,22 +68,22 @@ mod sealed { pub trait AdvancedChannel: sealed::AdvancedChannel {} /// HRTIM PWM pin. -pub struct PwmPin<'d, Perip, Channel> { +pub struct PwmPin<'d, T, C> { _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(Perip, Channel)>, + phantom: PhantomData<(T, C)>, } /// HRTIM complementary PWM pin. -pub struct ComplementaryPwmPin<'d, Perip, Channel> { +pub struct ComplementaryPwmPin<'d, T, C> { _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(Perip, Channel)>, + phantom: PhantomData<(T, C)>, } macro_rules! advanced_channel_impl { ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { - impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel> { + impl<'d, T: Instance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { pin.set_low(); @@ -98,9 +98,9 @@ macro_rules! advanced_channel_impl { } } - impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel> { + impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { pin.set_low(); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 5d9b4e6a0..4952d26eb 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -79,6 +79,7 @@ pub(crate) mod _generated { #![allow(dead_code)] #![allow(unused_imports)] #![allow(non_snake_case)] + #![allow(missing_docs)] include!(concat!(env!("OUT_DIR"), "/_generated.rs")); } @@ -149,15 +150,33 @@ use crate::interrupt::Priority; pub use crate::pac::NVIC_PRIO_BITS; use crate::rcc::sealed::RccPeripheral; +/// `embassy-stm32` global configuration. #[non_exhaustive] pub struct Config { + /// RCC config. pub rcc: rcc::Config, + + /// Enable debug during sleep. + /// + /// May incrase power consumption. Defaults to true. #[cfg(dbgmcu)] pub enable_debug_during_sleep: bool, + + /// BDMA interrupt priority. + /// + /// Defaults to P0 (highest). #[cfg(bdma)] pub bdma_interrupt_priority: Priority, + + /// DMA interrupt priority. + /// + /// Defaults to P0 (highest). #[cfg(dma)] pub dma_interrupt_priority: Priority, + + /// GPDMA interrupt priority. + /// + /// Defaults to P0 (highest). #[cfg(gpdma)] pub gpdma_interrupt_priority: Priority, } @@ -178,7 +197,11 @@ impl Default for Config { } } -/// Initialize embassy. +/// Initialize the `embassy-stm32` HAL with the provided configuration. +/// +/// This returns the peripheral singletons that can be used for creating drivers. +/// +/// This should only be called once at startup, otherwise it panics. pub fn init(config: Config) -> Peripherals { critical_section::with(|cs| { let p = Peripherals::take_with_cs(cs); diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index e543a5b43..71d7110b5 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -13,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType}; use crate::time::Hertz; use crate::Peripheral; -pub struct ComplementaryPwmPin<'d, Perip, Channel> { +/// Complementary PWM pin wrapper. +/// +/// This wraps a pin to make it usable with PWM. +pub struct ComplementaryPwmPin<'d, T, C> { _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(Perip, Channel)>, + phantom: PhantomData<(T, C)>, } macro_rules! complementary_channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { - pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { + impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); critical_section::with(|_| { pin.set_low(); @@ -43,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin); complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); +/// PWM driver with support for standard and complementary outputs. pub struct ComplementaryPwm<'d, T> { inner: PeripheralRef<'d, T>, } impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { + /// Create a new complementary PWM driver. pub fn new( tim: impl Peripheral

+ 'd, _ch1: Option>, @@ -72,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { let mut this = Self { inner: tim }; this.inner.set_counting_mode(counting_mode); - this.set_freq(freq); + this.set_frequency(freq); this.inner.start(); this.inner.enable_outputs(); @@ -88,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { this } + /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { self.inner.enable_channel(channel, true); self.inner.enable_complementary_channel(channel, true); } + /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { self.inner.enable_complementary_channel(channel, false); self.inner.enable_channel(channel, false); } - pub fn set_freq(&mut self, freq: Hertz) { + /// Set PWM frequency. + /// + /// Note: when you call this, the max duty value changes, so you will have to + /// call `set_duty` on all channels with the duty calculated based on the new max duty. + pub fn set_frequency(&mut self, freq: Hertz) { let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 2u8 } else { @@ -107,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { self.inner.set_frequency(freq * multiplier); } + /// Get max duty value. + /// + /// This value depends on the configured frequency and the timer's clock rate from RCC. pub fn get_max_duty(&self) -> u16 { self.inner.get_max_compare_value() + 1 } + /// Set the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); self.inner.set_compare_value(channel, duty) } + /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { self.inner.set_output_polarity(channel, polarity); self.inner.set_complementary_output_polarity(channel, polarity); diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 42ef878f7..74120adad 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -17,17 +17,27 @@ pub mod low_level { } pub(crate) mod sealed { - use super::*; + + /// Basic 16-bit timer instance. pub trait Basic16bitInstance: RccPeripheral { + /// Interrupt for this timer. type Interrupt: interrupt::typelevel::Interrupt; + /// Get access to the basic 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. fn regs() -> crate::pac::timer::TimBasic; + /// Start the timer. fn start(&mut self) { Self::regs().cr1().modify(|r| r.set_cen(true)); } + /// Stop the timer. fn stop(&mut self) { Self::regs().cr1().modify(|r| r.set_cen(false)); } @@ -63,6 +73,9 @@ pub(crate) mod sealed { regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); } + /// Clear update interrupt. + /// + /// Returns whether the update interrupt flag was set. fn clear_update_interrupt(&mut self) -> bool { let regs = Self::regs(); let sr = regs.sr().read(); @@ -76,14 +89,17 @@ pub(crate) mod sealed { } } + /// Enable/disable the update interrupt. fn enable_update_interrupt(&mut self, enable: bool) { Self::regs().dier().write(|r| r.set_uie(enable)); } + /// Enable/disable autoreload preload. fn set_autoreload_preload(&mut self, enable: bool) { Self::regs().cr1().modify(|r| r.set_arpe(enable)); } + /// Get the timer frequency. fn get_frequency(&self) -> Hertz { let timer_f = Self::frequency(); @@ -95,9 +111,17 @@ pub(crate) mod sealed { } } + /// Gneral-purpose 16-bit timer instance. pub trait GeneralPurpose16bitInstance: Basic16bitInstance { + /// Get access to the general purpose 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. fn regs_gp16() -> crate::pac::timer::TimGp16; + /// Set counting mode. fn set_counting_mode(&mut self, mode: CountingMode) { let (cms, dir) = mode.into(); @@ -110,19 +134,29 @@ pub(crate) mod sealed { Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) } + /// Get counting mode. fn get_counting_mode(&self) -> CountingMode { let cr1 = Self::regs_gp16().cr1().read(); (cr1.cms(), cr1.dir()).into() } + /// Set clock divider. fn set_clock_division(&mut self, ckd: vals::Ckd) { Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); } } + /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { + /// Get access to the general purpose 32bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. fn regs_gp32() -> crate::pac::timer::TimGp32; + /// Set timer frequency. fn set_frequency(&mut self, frequency: Hertz) { let f = frequency.0; assert!(f > 0); @@ -140,6 +174,7 @@ pub(crate) mod sealed { regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); } + /// Get timer frequency. fn get_frequency(&self) -> Hertz { let timer_f = Self::frequency(); @@ -151,141 +186,177 @@ pub(crate) mod sealed { } } + /// Advanced control timer instance. pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { + /// Get access to the advanced timer registers. fn regs_advanced() -> crate::pac::timer::TimAdv; } + /// Capture/Compare 16-bit timer instance. pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { + /// Set input capture filter. fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { - let raw_channel = channel.raw(); + let raw_channel = channel.index(); Self::regs_gp16() .ccmr_input(raw_channel / 2) .modify(|r| r.set_icf(raw_channel % 2, icf)); } + /// Clear input interrupt. fn clear_input_interrupt(&mut self, channel: Channel) { - Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false)); + Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); } + /// Enable input interrupt. fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { - Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable)); + Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); } + + /// Set input capture prescaler. fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { - let raw_channel = channel.raw(); + let raw_channel = channel.index(); Self::regs_gp16() .ccmr_input(raw_channel / 2) .modify(|r| r.set_icpsc(raw_channel % 2, factor)); } + /// Set input TI selection. fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { - let raw_channel = channel.raw(); + let raw_channel = channel.index(); Self::regs_gp16() .ccmr_input(raw_channel / 2) .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); } + + /// Set input capture mode. fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { Self::regs_gp16().ccer().modify(|r| match mode { InputCaptureMode::Rising => { - r.set_ccnp(channel.raw(), false); - r.set_ccp(channel.raw(), false); + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), false); } InputCaptureMode::Falling => { - r.set_ccnp(channel.raw(), false); - r.set_ccp(channel.raw(), true); + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), true); } InputCaptureMode::BothEdges => { - r.set_ccnp(channel.raw(), true); - r.set_ccp(channel.raw(), true); + r.set_ccnp(channel.index(), true); + r.set_ccp(channel.index(), true); } }); } + + /// Enable timer outputs. fn enable_outputs(&mut self); + /// Set output compare mode. fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { let r = Self::regs_gp16(); - let raw_channel: usize = channel.raw(); + let raw_channel: usize = channel.index(); r.ccmr_output(raw_channel / 2) .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); } + /// Set output polarity. fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { Self::regs_gp16() .ccer() - .modify(|w| w.set_ccp(channel.raw(), polarity.into())); + .modify(|w| w.set_ccp(channel.index(), polarity.into())); } + /// Enable/disable a channel. fn enable_channel(&mut self, channel: Channel, enable: bool) { - Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable)); + Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); } + /// Set compare value for a channel. fn set_compare_value(&mut self, channel: Channel, value: u16) { - Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); + Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); } + /// Get capture value for a channel. fn get_capture_value(&mut self, channel: Channel) -> u16 { - Self::regs_gp16().ccr(channel.raw()).read().ccr() + Self::regs_gp16().ccr(channel.index()).read().ccr() } + /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. fn get_max_compare_value(&self) -> u16 { Self::regs_gp16().arr().read().arr() } + /// Get compare value for a channel. fn get_compare_value(&self, channel: Channel) -> u16 { - Self::regs_gp16().ccr(channel.raw()).read().ccr() + Self::regs_gp16().ccr(channel.index()).read().ccr() } } + /// Capture/Compare 16-bit timer instance with complementary pin support. pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { + /// Set complementary output polarity. fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { Self::regs_advanced() .ccer() - .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); + .modify(|w| w.set_ccnp(channel.index(), polarity.into())); } + /// Set clock divider for the dead time. fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); } + /// Set dead time, as a fraction of the max duty value. fn set_dead_time_value(&mut self, value: u8) { Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); } + /// Enable/disable a complementary channel. fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { Self::regs_advanced() .ccer() - .modify(|w| w.set_ccne(channel.raw(), enable)); + .modify(|w| w.set_ccne(channel.index(), enable)); } } + /// Capture/Compare 32-bit timer instance. pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { + /// Set comapre value for a channel. fn set_compare_value(&mut self, channel: Channel, value: u32) { - Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); + Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); } + /// Get capture value for a channel. fn get_capture_value(&mut self, channel: Channel) -> u32 { - Self::regs_gp32().ccr(channel.raw()).read().ccr() + Self::regs_gp32().ccr(channel.index()).read().ccr() } + /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. fn get_max_compare_value(&self) -> u32 { Self::regs_gp32().arr().read().arr() } + /// Get compare value for a channel. fn get_compare_value(&self, channel: Channel) -> u32 { - Self::regs_gp32().ccr(channel.raw()).read().ccr() + Self::regs_gp32().ccr(channel.index()).read().ccr() } } } +/// Timer channel. #[derive(Clone, Copy)] pub enum Channel { + /// Channel 1. Ch1, + /// Channel 2. Ch2, + /// Channel 3. Ch3, + /// Channel 4. Ch4, } impl Channel { - pub fn raw(&self) -> usize { + /// Get the channel index (0..3) + pub fn index(&self) -> usize { match self { Channel::Ch1 => 0, Channel::Ch2 => 1, @@ -295,17 +366,25 @@ impl Channel { } } +/// Input capture mode. #[derive(Clone, Copy)] pub enum InputCaptureMode { + /// Rising edge only. Rising, + /// Falling edge only. Falling, + /// Both rising or falling edges. BothEdges, } +/// Input TI selection. #[derive(Clone, Copy)] pub enum InputTISelection { + /// Normal Normal, + /// Alternate Alternate, + /// TRC TRC, } @@ -319,6 +398,7 @@ impl From for stm32_metapac::timer::vals::CcmrInputCcs { } } +/// Timer counting mode. #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum CountingMode { @@ -345,6 +425,7 @@ pub enum CountingMode { } impl CountingMode { + /// Return whether this mode is edge-aligned (up or down). pub fn is_edge_aligned(&self) -> bool { match self { CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, @@ -352,6 +433,7 @@ impl CountingMode { } } + /// Return whether this mode is center-aligned. pub fn is_center_aligned(&self) -> bool { match self { CountingMode::CenterAlignedDownInterrupts @@ -386,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode { } } +/// Output compare mode. #[derive(Clone, Copy)] pub enum OutputCompareMode { + /// The comparison between the output compare register TIMx_CCRx and + /// the counter TIMx_CNT has no effect on the outputs. + /// (this mode is used to generate a timing base). Frozen, + /// Set channel to active level on match. OCxREF signal is forced high when the + /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). ActiveOnMatch, + /// Set channel to inactive level on match. OCxREF signal is forced low when the + /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). InactiveOnMatch, + /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. Toggle, + /// Force inactive level - OCxREF is forced low. ForceInactive, + /// Force active level - OCxREF is forced high. ForceActive, + /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNTTIMx_CCRx else active (OCxREF=1). PwmMode1, + /// PWM mode 2 - In upcounting, channel is inactive as long as + /// TIMx_CNTTIMx_CCRx else inactive. PwmMode2, + // TODO: there's more modes here depending on the chip family. } impl From for stm32_metapac::timer::vals::Ocm { @@ -413,9 +513,12 @@ impl From for stm32_metapac::timer::vals::Ocm { } } +/// Timer output pin polarity. #[derive(Clone, Copy)] pub enum OutputPolarity { + /// Active high (higher duty value makes the pin spend more time high). ActiveHigh, + /// Active low (higher duty value makes the pin spend more time low). ActiveLow, } @@ -428,24 +531,31 @@ impl From for bool { } } +/// Basic 16-bit timer instance. pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} +/// Gneral-purpose 16-bit timer instance. pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} +/// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} +/// Advanced control timer instance. pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} +/// Capture/Compare 16-bit timer instance. pub trait CaptureCompare16bitInstance: sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static { } +/// Capture/Compare 16-bit timer instance with complementary pin support. pub trait ComplementaryCaptureCompare16bitInstance: sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static { } +/// Capture/Compare 32-bit timer instance. pub trait CaptureCompare32bitInstance: sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static { diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 9f9379c20..59efb72ba 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -9,23 +9,30 @@ use crate::gpio::sealed::AFType; use crate::gpio::AnyPin; use crate::Peripheral; +/// Counting direction pub enum Direction { + /// Counting up. Upcounting, + /// Counting down. Downcounting, } -pub struct Ch1; -pub struct Ch2; +/// Channel 1 marker type. +pub enum Ch1 {} +/// Channel 2 marker type. +pub enum Ch2 {} -pub struct QeiPin<'d, Perip, Channel> { +/// Wrapper for using a pin with QEI. +pub struct QeiPin<'d, T, Channel> { _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(Perip, Channel)>, + phantom: PhantomData<(T, Channel)>, } macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { pin.set_low(); @@ -45,11 +52,13 @@ macro_rules! channel_impl { channel_impl!(new_ch1, Ch1, Channel1Pin); channel_impl!(new_ch2, Ch2, Channel2Pin); +/// Quadrature decoder driver. pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { + /// Create a new quadrature decoder driver. pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) } @@ -84,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { Self { _inner: tim } } + /// Get direction. pub fn read_direction(&self) -> Direction { match T::regs_gp16().cr1().read().dir() { vals::Dir::DOWN => Direction::Downcounting, @@ -91,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { } } + /// Get count. pub fn count(&self) -> u16 { T::regs_gp16().cnt().read().cnt() } diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 234bbaff0..e6072aa15 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -11,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType}; use crate::time::Hertz; use crate::Peripheral; -pub struct Ch1; -pub struct Ch2; -pub struct Ch3; -pub struct Ch4; +/// Channel 1 marker type. +pub enum Ch1 {} +/// Channel 2 marker type. +pub enum Ch2 {} +/// Channel 3 marker type. +pub enum Ch3 {} +/// Channel 4 marker type. +pub enum Ch4 {} -pub struct PwmPin<'d, Perip, Channel> { +/// PWM pin wrapper. +/// +/// This wraps a pin to make it usable with PWM. +pub struct PwmPin<'d, T, C> { _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(Perip, Channel)>, + phantom: PhantomData<(T, C)>, } macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { - pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { + impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); critical_section::with(|_| { pin.set_low(); @@ -46,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin); channel_impl!(new_ch3, Ch3, Channel3Pin); channel_impl!(new_ch4, Ch4, Channel4Pin); +/// Simple PWM driver. pub struct SimplePwm<'d, T> { inner: PeripheralRef<'d, T>, } impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { + /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, _ch1: Option>, @@ -71,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { let mut this = Self { inner: tim }; this.inner.set_counting_mode(counting_mode); - this.set_freq(freq); + this.set_frequency(freq); this.inner.start(); this.inner.enable_outputs(); @@ -87,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { this } + /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { self.inner.enable_channel(channel, true); } + /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { self.inner.enable_channel(channel, false); } - pub fn set_freq(&mut self, freq: Hertz) { + /// Set PWM frequency. + /// + /// Note: when you call this, the max duty value changes, so you will have to + /// call `set_duty` on all channels with the duty calculated based on the new max duty. + pub fn set_frequency(&mut self, freq: Hertz) { let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 2u8 } else { @@ -104,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { self.inner.set_frequency(freq * multiplier); } + /// Get max duty value. + /// + /// This value depends on the configured frequency and the timer's clock rate from RCC. pub fn get_max_duty(&self) -> u16 { self.inner.get_max_compare_value() + 1 } + /// Set the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); self.inner.set_compare_value(channel, duty) } + /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { self.inner.set_output_polarity(channel, polarity); } diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index 52cc665c7..39f5d3421 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -110,7 +110,7 @@ async fn main(_spawner: Spawner) { &mut dp.DMA1_CH2, 5, color_list[color_list_index], - pac::TIM3.ccr(pwm_channel.raw()).as_ptr() as *mut _, + pac::TIM3.ccr(pwm_channel.index()).as_ptr() as *mut _, dma_transfer_option, ) .await; diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index e0be495d1..394ed3281 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -85,7 +85,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { let mut this = Self { inner: tim }; - this.set_freq(freq); + this.set_frequency(freq); this.inner.start(); let r = T::regs_gp32(); @@ -102,14 +102,14 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { } pub fn enable(&mut self, channel: Channel) { - T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); + T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); } pub fn disable(&mut self, channel: Channel) { - T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); + T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false)); } - pub fn set_freq(&mut self, freq: Hertz) { + pub fn set_frequency(&mut self, freq: Hertz) { ::set_frequency(&mut self.inner, freq); } @@ -119,6 +119,6 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { pub fn set_duty(&mut self, channel: Channel, duty: u32) { defmt::assert!(duty < self.get_max_duty()); - T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) + T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty)) } } From c8c8b89104acb396476b72ff9192d7b14a46752d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 18:03:20 +0100 Subject: [PATCH 069/760] stm32: doc everything else. --- embassy-stm32/src/dma/gpdma.rs | 18 ++++++ embassy-stm32/src/ipcc.rs | 8 +++ embassy-stm32/src/lib.rs | 1 + embassy-stm32/src/low_power.rs | 106 +++++++++++++++++-------------- embassy-stm32/src/opamp.rs | 9 +++ embassy-stm32/src/rng.rs | 1 + embassy-stm32/src/sdmmc/mod.rs | 2 + embassy-stm32/src/usb/mod.rs | 4 ++ embassy-stm32/src/usb/usb.rs | 7 ++ embassy-stm32/src/usb_otg/mod.rs | 2 + embassy-stm32/src/usb_otg/usb.rs | 13 +++- embassy-stm32/src/wdg/mod.rs | 4 ++ 12 files changed, 127 insertions(+), 48 deletions(-) diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index b061415eb..34b2426b9 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -16,6 +16,7 @@ use crate::interrupt::Priority; use crate::pac; use crate::pac::gpdma::vals; +/// GPDMA transfer options. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -113,10 +114,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in } } +/// DMA request type alias. (also known as DMA channel number in some chips) pub type Request = u8; +/// DMA channel. #[cfg(dmamux)] pub trait Channel: sealed::Channel + Peripheral

+ 'static + super::dmamux::MuxChannel {} +/// DMA channel. #[cfg(not(dmamux))] pub trait Channel: sealed::Channel + Peripheral

+ 'static {} @@ -131,12 +135,14 @@ pub(crate) mod sealed { } } +/// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a, C: Channel> { channel: PeripheralRef<'a, C>, } impl<'a, C: Channel> Transfer<'a, C> { + /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( channel: impl Peripheral

+ 'a, request: Request, @@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> { Self::new_read_raw(channel, request, peri_addr, buf, options) } + /// Create a new read DMA transfer (peripheral to memory), using raw pointers. pub unsafe fn new_read_raw( channel: impl Peripheral

+ 'a, request: Request, @@ -172,6 +179,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ) } + /// Create a new write DMA transfer (memory to peripheral). pub unsafe fn new_write( channel: impl Peripheral

+ 'a, request: Request, @@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> { Self::new_write_raw(channel, request, buf, peri_addr, options) } + /// Create a new write DMA transfer (memory to peripheral), using raw pointers. pub unsafe fn new_write_raw( channel: impl Peripheral

+ 'a, request: Request, @@ -207,6 +216,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ) } + /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. pub unsafe fn new_write_repeated( channel: impl Peripheral

+ 'a, request: Request, @@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> { this } + /// Request the transfer to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); ch.cr().modify(|w| { @@ -304,6 +317,10 @@ impl<'a, C: Channel> Transfer<'a, C> { }) } + /// Return whether this transfer is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().ch(self.channel.num()); let sr = ch.sr().read(); @@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ch.br1().read().bndt() } + /// Blocking wait until the transfer finishes. pub fn blocking_wait(mut self) { while self.is_running() {} diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 4006dee19..663a7f59d 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -1,3 +1,5 @@ +//! Inter-Process Communication Controller (IPCC) + use core::future::poll_fn; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; @@ -41,6 +43,7 @@ impl interrupt::typelevel::Handler for Receive } } +/// TX interrupt handler. pub struct TransmitInterruptHandler {} impl interrupt::typelevel::Handler for TransmitInterruptHandler { @@ -72,6 +75,7 @@ impl interrupt::typelevel::Handler for Transmi } } +/// IPCC config. #[non_exhaustive] #[derive(Clone, Copy, Default)] pub struct Config { @@ -79,6 +83,8 @@ pub struct Config { // reserved for future use } +/// Channel. +#[allow(missing_docs)] #[derive(Debug, Clone, Copy)] #[repr(C)] pub enum IpccChannel { @@ -90,9 +96,11 @@ pub enum IpccChannel { Channel6 = 5, } +/// IPCC driver. pub struct Ipcc; impl Ipcc { + /// Enable IPCC. pub fn enable(_config: Config) { IPCC::enable_and_reset(); IPCC::set_cpu2(true); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 4952d26eb..207f7ed8f 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(test), no_std)] #![allow(async_fn_in_trait)] +#![warn(missing_docs)] //! ## Feature flags #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 20d8f9045..a41c40eba 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -1,50 +1,53 @@ -/// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating -/// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which -/// can use knowledge of which peripherals are currently blocked upon to transparently and safely -/// enter such low-power modes (currently, only `STOP2`) when idle. -/// -/// The executor determines which peripherals are active by their RCC state; consequently, -/// low-power states can only be entered if all peripherals have been `drop`'d. There are a few -/// exceptions to this rule: -/// -/// * `GPIO` -/// * `RCC` -/// -/// Since entering and leaving low-power modes typically incurs a significant latency, the -/// low-power executor will only attempt to enter when the next timer event is at least -/// [`time_driver::MIN_STOP_PAUSE`] in the future. -/// -/// Currently there is no macro analogous to `embassy_executor::main` for this executor; -/// consequently one must define their entrypoint manually. Moveover, you must relinquish control -/// of the `RTC` peripheral to the executor. This will typically look like -/// -/// ```rust,no_run -/// use embassy_executor::Spawner; -/// use embassy_stm32::low_power::Executor; -/// use embassy_stm32::rtc::{Rtc, RtcConfig}; -/// use static_cell::make_static; -/// -/// #[cortex_m_rt::entry] -/// fn main() -> ! { -/// Executor::take().run(|spawner| { -/// unwrap!(spawner.spawn(async_main(spawner))); -/// }); -/// } -/// -/// #[embassy_executor::task] -/// async fn async_main(spawner: Spawner) { -/// // initialize the platform... -/// let mut config = embassy_stm32::Config::default(); -/// let p = embassy_stm32::init(config); -/// -/// // give the RTC to the executor... -/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); -/// let rtc = make_static!(rtc); -/// embassy_stm32::low_power::stop_with_rtc(rtc); -/// -/// // your application here... -/// } -/// ``` +//! Low-power support. +//! +//! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating +//! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which +//! can use knowledge of which peripherals are currently blocked upon to transparently and safely +//! enter such low-power modes (currently, only `STOP2`) when idle. +//! +//! The executor determines which peripherals are active by their RCC state; consequently, +//! low-power states can only be entered if all peripherals have been `drop`'d. There are a few +//! exceptions to this rule: +//! +//! * `GPIO` +//! * `RCC` +//! +//! Since entering and leaving low-power modes typically incurs a significant latency, the +//! low-power executor will only attempt to enter when the next timer event is at least +//! [`time_driver::MIN_STOP_PAUSE`] in the future. +//! +//! Currently there is no macro analogous to `embassy_executor::main` for this executor; +//! consequently one must define their entrypoint manually. Moveover, you must relinquish control +//! of the `RTC` peripheral to the executor. This will typically look like +//! +//! ```rust,no_run +//! use embassy_executor::Spawner; +//! use embassy_stm32::low_power::Executor; +//! use embassy_stm32::rtc::{Rtc, RtcConfig}; +//! use static_cell::make_static; +//! +//! #[cortex_m_rt::entry] +//! fn main() -> ! { +//! Executor::take().run(|spawner| { +//! unwrap!(spawner.spawn(async_main(spawner))); +//! }); +//! } +//! +//! #[embassy_executor::task] +//! async fn async_main(spawner: Spawner) { +//! // initialize the platform... +//! let mut config = embassy_stm32::Config::default(); +//! let p = embassy_stm32::init(config); +//! +//! // give the RTC to the executor... +//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); +//! let rtc = make_static!(rtc); +//! embassy_stm32::low_power::stop_with_rtc(rtc); +//! +//! // your application here... +//! } +//! ``` + use core::arch::asm; use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; @@ -64,6 +67,7 @@ static mut EXECUTOR: Option = None; foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { #[interrupt] + #[allow(non_snake_case)] unsafe fn $irq() { EXECUTOR.as_mut().unwrap().on_wakeup_irq(); } @@ -75,10 +79,15 @@ pub(crate) unsafe fn on_wakeup_irq() { EXECUTOR.as_mut().unwrap().on_wakeup_irq(); } +/// Configure STOP mode with RTC. pub fn stop_with_rtc(rtc: &'static Rtc) { unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) } +/// Get whether the core is ready to enter the given stop mode. +/// +/// This will return false if some peripheral driver is in use that +/// prevents entering the given stop mode. pub fn stop_ready(stop_mode: StopMode) -> bool { match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { Some(StopMode::Stop2) => true, @@ -87,10 +96,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool { } } +/// Available stop modes. #[non_exhaustive] #[derive(PartialEq)] pub enum StopMode { + /// STOP 1 Stop1, + /// STOP 2 Stop2, } diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index e1eb031d1..df8a78bcc 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -1,9 +1,12 @@ +//! Operational Amplifier (OPAMP) #![macro_use] use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::Peripheral; +/// Gain +#[allow(missing_docs)] #[derive(Clone, Copy)] pub enum OpAmpGain { Mul1, @@ -13,6 +16,8 @@ pub enum OpAmpGain { Mul16, } +/// Speed +#[allow(missing_docs)] #[derive(Clone, Copy)] pub enum OpAmpSpeed { Normal, @@ -180,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { } } +/// Opamp instance trait. pub trait Instance: sealed::Instance + 'static {} pub(crate) mod sealed { @@ -198,8 +204,11 @@ pub(crate) mod sealed { pub trait OutputPin {} } +/// Non-inverting pin trait. pub trait NonInvertingPin: sealed::NonInvertingPin {} +/// Inverting pin trait. pub trait InvertingPin: sealed::InvertingPin {} +/// Output pin trait. pub trait OutputPin: sealed::OutputPin {} macro_rules! impl_opamp_external_output { diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 6ee89a922..ca641f352 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -80,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> { let _ = self.next_u32(); } + /// Reset the RNG. #[cfg(not(rng_v1))] pub fn reset(&mut self) { T::regs().cr().write(|reg| { diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ab142053a..10006baff 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -293,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma = NoDma> { #[cfg(sdmmc_v1)] impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { + /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -327,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { ) } + /// Create a new SDMMC driver, with 4 data lanes. pub fn new_4bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index d0b289462..4debd4e54 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -1,3 +1,5 @@ +//! Universal Serial Bus (USB) + use crate::interrupt; use crate::rcc::RccPeripheral; @@ -10,7 +12,9 @@ pub(crate) mod sealed { } } +/// USB instance trait. pub trait Instance: sealed::Instance + RccPeripheral + 'static { + /// Interrupt for this USB instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 295dc9198..a8aebfe1f 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -244,6 +244,7 @@ struct EndpointData { used_out: bool, } +/// USB driver. pub struct Driver<'d, T: Instance> { phantom: PhantomData<&'d mut T>, alloc: [EndpointData; EP_COUNT], @@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> { } impl<'d, T: Instance> Driver<'d, T> { + /// Create a new USB driver. pub fn new( _usb: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -465,6 +467,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { } } +/// USB bus. pub struct Bus<'d, T: Instance> { phantom: PhantomData<&'d mut T>, ep_types: [EpType; EP_COUNT - 1], @@ -640,6 +643,7 @@ trait Dir { fn waker(i: usize) -> &'static AtomicWaker; } +/// Marker type for the "IN" direction. pub enum In {} impl Dir for In { fn dir() -> Direction { @@ -652,6 +656,7 @@ impl Dir for In { } } +/// Marker type for the "OUT" direction. pub enum Out {} impl Dir for Out { fn dir() -> Direction { @@ -664,6 +669,7 @@ impl Dir for Out { } } +/// USB endpoint. pub struct Endpoint<'d, T: Instance, D> { _phantom: PhantomData<(&'d mut T, D)>, info: EndpointInfo, @@ -813,6 +819,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { } } +/// USB control pipe. pub struct ControlPipe<'d, T: Instance> { _phantom: PhantomData<&'d mut T>, max_packet_size: u16, diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs index 1abd031dd..0649e684b 100644 --- a/embassy-stm32/src/usb_otg/mod.rs +++ b/embassy-stm32/src/usb_otg/mod.rs @@ -20,7 +20,9 @@ pub(crate) mod sealed { } } +/// USB OTG instance. pub trait Instance: sealed::Instance + RccPeripheral { + /// Interrupt for this USB OTG instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index ba77bfb16..190fb274f 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -204,6 +204,7 @@ pub enum PhyType { } impl PhyType { + /// Get whether this PHY is any of the internal types. pub fn internal(&self) -> bool { match self { PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, @@ -211,6 +212,7 @@ impl PhyType { } } + /// Get whether this PHY is any of the high-speed types. pub fn high_speed(&self) -> bool { match self { PhyType::InternalFullSpeed => false, @@ -218,7 +220,7 @@ impl PhyType { } } - pub fn to_dspd(&self) -> vals::Dspd { + fn to_dspd(&self) -> vals::Dspd { match self { PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, @@ -230,6 +232,7 @@ impl PhyType { /// Indicates that [State::ep_out_buffers] is empty. const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; +/// USB OTG driver state. pub struct State { /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. ep0_setup_data: UnsafeCell<[u8; 8]>, @@ -247,6 +250,7 @@ unsafe impl Send for State {} unsafe impl Sync for State {} impl State { + /// Create a new State. pub const fn new() -> Self { const NEW_AW: AtomicWaker = AtomicWaker::new(); const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); @@ -271,6 +275,7 @@ struct EndpointData { fifo_size_words: u16, } +/// USB driver config. #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Config { @@ -297,6 +302,7 @@ impl Default for Config { } } +/// USB driver. pub struct Driver<'d, T: Instance> { config: Config, phantom: PhantomData<&'d mut T>, @@ -527,6 +533,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { } } +/// USB bus. pub struct Bus<'d, T: Instance> { config: Config, phantom: PhantomData<&'d mut T>, @@ -1092,6 +1099,7 @@ trait Dir { fn dir() -> Direction; } +/// Marker type for the "IN" direction. pub enum In {} impl Dir for In { fn dir() -> Direction { @@ -1099,6 +1107,7 @@ impl Dir for In { } } +/// Marker type for the "OUT" direction. pub enum Out {} impl Dir for Out { fn dir() -> Direction { @@ -1106,6 +1115,7 @@ impl Dir for Out { } } +/// USB endpoint. pub struct Endpoint<'d, T: Instance, D> { _phantom: PhantomData<(&'d mut T, D)>, info: EndpointInfo, @@ -1299,6 +1309,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { } } +/// USB control pipe. pub struct ControlPipe<'d, T: Instance> { _phantom: PhantomData<&'d mut T>, max_packet_size: u16, diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 5751a9ff3..dc701ef64 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -6,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr}; use crate::rcc::LSI_FREQ; +/// Independent watchdog (IWDG) driver. pub struct IndependentWatchdog<'d, T: Instance> { wdg: PhantomData<&'d mut T>, } @@ -64,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { IndependentWatchdog { wdg: PhantomData } } + /// Unleash (start) the watchdog. pub fn unleash(&mut self) { T::regs().kr().write(|w| w.set_key(Key::START)); } + /// Pet (reload, refresh) the watchdog. pub fn pet(&mut self) { T::regs().kr().write(|w| w.set_key(Key::RESET)); } @@ -79,6 +82,7 @@ mod sealed { } } +/// IWDG instance trait. pub trait Instance: sealed::Instance {} foreach_peripheral!( From 9d46ee0758dbc7a8625174370aff5fb8334f8170 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 20:24:55 +0100 Subject: [PATCH 070/760] fix: update salty to released version --- embassy-boot/boot/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml index dd2ff8158..f0810f418 100644 --- a/embassy-boot/boot/Cargo.toml +++ b/embassy-boot/boot/Cargo.toml @@ -31,7 +31,7 @@ embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } -salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true } +salty = { version = "0.3", optional = true } signature = { version = "1.6.4", default-features = false } [dev-dependencies] From efd5dbe0196a71527777d949261cb7bbb7bee376 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 20:25:20 +0100 Subject: [PATCH 071/760] fix: build warnings --- embassy-boot/boot/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml index f0810f418..f63ea92cf 100644 --- a/embassy-boot/boot/Cargo.toml +++ b/embassy-boot/boot/Cargo.toml @@ -43,6 +43,7 @@ sha1 = "0.10.5" critical-section = { version = "1.1.1", features = ["std"] } [dev-dependencies.ed25519-dalek] +version = "1.0.1" default_features = false features = ["rand", "std", "u32_backend"] From 871ed538b1fb0836bdc12f5d59dbc7f5fea53920 Mon Sep 17 00:00:00 2001 From: dragonn Date: Tue, 19 Dec 2023 21:17:42 +0100 Subject: [PATCH 072/760] fix stm32 rtc year from 1970 base 2000 --- embassy-stm32/src/rtc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 11b252139..40cd752a2 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -130,7 +130,7 @@ impl RtcTimeProvider { let weekday = day_of_week_from_u8(dr.wdu()).map_err(RtcError::InvalidDateTime)?; let day = bcd2_to_byte((dr.dt(), dr.du())); let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); - let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; + let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16; DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) }) @@ -261,7 +261,7 @@ impl Rtc { let (dt, du) = byte_to_bcd2(t.day() as u8); let (mt, mu) = byte_to_bcd2(t.month() as u8); let yr = t.year() as u16; - let yr_offset = (yr - 1970_u16) as u8; + let yr_offset = (yr - 2000_u16) as u8; let (yt, yu) = byte_to_bcd2(yr_offset); use crate::pac::rtc::vals::Ampm; From 12de90e13dd564e3f3f445f00ca2be622ad2c7fe Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 21:20:30 +0100 Subject: [PATCH 073/760] fix: update ed25519-dalek to new version --- embassy-boot/boot/Cargo.toml | 4 ++-- .../boot/src/digest_adapters/ed25519_dalek.rs | 4 ++-- .../boot/src/firmware_updater/asynch.rs | 17 +++++++---------- .../boot/src/firmware_updater/blocking.rs | 17 +++++++---------- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml index f63ea92cf..e47776d62 100644 --- a/embassy-boot/boot/Cargo.toml +++ b/embassy-boot/boot/Cargo.toml @@ -26,13 +26,13 @@ features = ["defmt"] defmt = { version = "0.3", optional = true } digest = "0.10" log = { version = "0.4", optional = true } -ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } +ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } salty = { version = "0.3", optional = true } -signature = { version = "1.6.4", default-features = false } +signature = { version = "2.2", default-features = false } [dev-dependencies] log = "0.4" diff --git a/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs index a184d1c51..2e4e03da3 100644 --- a/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs +++ b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs @@ -1,6 +1,6 @@ use digest::typenum::U64; use digest::{FixedOutput, HashMarker, OutputSizeUser, Update}; -use ed25519_dalek::Digest as _; +use ed25519_dalek::Digest; pub struct Sha512(ed25519_dalek::Sha512); @@ -12,7 +12,7 @@ impl Default for Sha512 { impl Update for Sha512 { fn update(&mut self, data: &[u8]) { - self.0.update(data) + Digest::update(&mut self.0, data) } } diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs index d8d85c3d2..4af5a087d 100644 --- a/embassy-boot/boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/boot/src/firmware_updater/asynch.rs @@ -79,8 +79,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { #[cfg(feature = "_verify")] pub async fn verify_and_mark_updated( &mut self, - _public_key: &[u8], - _signature: &[u8], + _public_key: &[u8; 32], + _signature: &[u8; 64], _update_len: u32, ) -> Result<(), FirmwareUpdaterError> { assert!(_update_len <= self.dfu.capacity() as u32); @@ -89,14 +89,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { #[cfg(feature = "ed25519-dalek")] { - use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; + use ed25519_dalek::{VerifyingKey, Signature, SignatureError, Verifier}; use crate::digest_adapters::ed25519_dalek::Sha512; let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); - let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; - let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; + let public_key = VerifyingKey::from_bytes(_public_key).map_err(into_signature_error)?; + let signature = Signature::from_bytes(_signature); let mut chunk_buf = [0; 2]; let mut message = [0; 64]; @@ -106,7 +106,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { } #[cfg(feature = "ed25519-salty")] { - use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; use salty::{PublicKey, Signature}; use crate::digest_adapters::salty::Sha512; @@ -115,10 +114,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { FirmwareUpdaterError::Signature(signature::Error::default()) } - let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; - let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; - let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; - let signature = Signature::try_from(&signature).map_err(into_signature_error)?; + let public_key = PublicKey::try_from(_public_key).map_err(into_signature_error)?; + let signature = Signature::try_from(_signature).map_err(into_signature_error)?; let mut message = [0; 64]; let mut chunk_buf = [0; 2]; diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs index c4c142169..f1368540d 100644 --- a/embassy-boot/boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/boot/src/firmware_updater/blocking.rs @@ -86,8 +86,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> #[cfg(feature = "_verify")] pub fn verify_and_mark_updated( &mut self, - _public_key: &[u8], - _signature: &[u8], + _public_key: &[u8; 32], + _signature: &[u8; 64], _update_len: u32, ) -> Result<(), FirmwareUpdaterError> { assert!(_update_len <= self.dfu.capacity() as u32); @@ -96,14 +96,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> #[cfg(feature = "ed25519-dalek")] { - use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; + use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey}; use crate::digest_adapters::ed25519_dalek::Sha512; let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); - let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; - let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; + let public_key = VerifyingKey::from_bytes(_public_key).map_err(into_signature_error)?; + let signature = Signature::from_bytes(_signature); let mut message = [0; 64]; let mut chunk_buf = [0; 2]; @@ -113,7 +113,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> } #[cfg(feature = "ed25519-salty")] { - use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; use salty::{PublicKey, Signature}; use crate::digest_adapters::salty::Sha512; @@ -122,10 +121,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> FirmwareUpdaterError::Signature(signature::Error::default()) } - let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; - let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; - let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; - let signature = Signature::try_from(&signature).map_err(into_signature_error)?; + let public_key = PublicKey::try_from(_public_key).map_err(into_signature_error)?; + let signature = Signature::try_from(_signature).map_err(into_signature_error)?; let mut message = [0; 64]; let mut chunk_buf = [0; 2]; From 4567b874826e30f54dbd0e5d12b6f0243e284be3 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Dec 2023 21:21:52 +0100 Subject: [PATCH 074/760] cargo fmt --- embassy-boot/boot/src/firmware_updater/asynch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs index 4af5a087d..64a4b32ec 100644 --- a/embassy-boot/boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/boot/src/firmware_updater/asynch.rs @@ -89,7 +89,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { #[cfg(feature = "ed25519-dalek")] { - use ed25519_dalek::{VerifyingKey, Signature, SignatureError, Verifier}; + use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey}; use crate::digest_adapters::ed25519_dalek::Sha512; From c7841a37fab60a9f017c4aa7ea3f0c9b0c2aba0d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 22:26:50 +0100 Subject: [PATCH 075/760] boot: update ed25519-dalek in dev-dependencies. --- embassy-boot/boot/Cargo.toml | 10 +++------- embassy-boot/boot/src/lib.rs | 8 +++----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml index e47776d62..3c84ffcd3 100644 --- a/embassy-boot/boot/Cargo.toml +++ b/embassy-boot/boot/Cargo.toml @@ -32,20 +32,16 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } salty = { version = "0.3", optional = true } -signature = { version = "2.2", default-features = false } +signature = { version = "2.0", default-features = false } [dev-dependencies] log = "0.4" env_logger = "0.9" -rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version +rand = "0.8" futures = { version = "0.3", features = ["executor"] } sha1 = "0.10.5" critical-section = { version = "1.1.1", features = ["std"] } - -[dev-dependencies.ed25519-dalek] -version = "1.0.1" -default_features = false -features = ["rand", "std", "u32_backend"] +ed25519-dalek = { version = "2", default_features = false, features = ["std", "rand_core", "digest"] } [features] ed25519-dalek = ["dep:ed25519-dalek", "_verify"] diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 15b69f69d..b4f03e01e 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -275,21 +275,19 @@ mod tests { // The following key setup is based on: // https://docs.rs/ed25519-dalek/latest/ed25519_dalek/#example - use ed25519_dalek::Keypair; + use ed25519_dalek::{Digest, Sha512, Signature, Signer, SigningKey, VerifyingKey}; use rand::rngs::OsRng; let mut csprng = OsRng {}; - let keypair: Keypair = Keypair::generate(&mut csprng); + let keypair = SigningKey::generate(&mut csprng); - use ed25519_dalek::{Digest, Sha512, Signature, Signer}; let firmware: &[u8] = b"This are bytes that would otherwise be firmware bytes for DFU."; let mut digest = Sha512::new(); digest.update(&firmware); let message = digest.finalize(); let signature: Signature = keypair.sign(&message); - use ed25519_dalek::PublicKey; - let public_key: PublicKey = keypair.public; + let public_key = keypair.verifying_key(); // Setup flash let flash = BlockingTestFlash::new(BootLoaderConfig { From f9d0daad80827dd1b379ca727a2e27870a497122 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 20 Dec 2023 08:37:15 +0100 Subject: [PATCH 076/760] feat(embassy-sync): Add try_take() to signal --- embassy-sync/src/signal.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index bea67d8be..97d76b463 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs @@ -111,6 +111,17 @@ where poll_fn(move |cx| self.poll_wait(cx)) } + /// non-blocking method to try and take the signal value. + pub fn try_take(&self) -> Option { + self.state.lock(|cell| { + let state = cell.replace(State::None); + match state { + State::Signaled(res) => Some(res), + _ => None, + } + }) + } + /// non-blocking method to check whether this signal has been signaled. pub fn signaled(&self) -> bool { self.state.lock(|cell| { From fc6e70caa5afb2e6b37e45516fad9a233e32d108 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 09:24:10 +0100 Subject: [PATCH 077/760] docs: document public apis of embassy-net-driver-channel --- embassy-net-driver-channel/src/lib.rs | 58 ++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index bfb2c9c03..7ad4d449e 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![doc = include_str!("../README.md")] +#![warn(missing_docs)] // must go first! mod fmt; @@ -15,6 +16,9 @@ use embassy_sync::blocking_mutex::Mutex; use embassy_sync::waitqueue::WakerRegistration; use embassy_sync::zerocopy_channel; +/// Channel state. +/// +/// Holds a buffer of packets with size MTU, for both TX and RX. pub struct State { rx: [PacketBuf; N_RX], tx: [PacketBuf; N_TX], @@ -24,6 +28,7 @@ pub struct State { impl State { const NEW_PACKET: PacketBuf = PacketBuf::new(); + /// Create a new channel state. pub const fn new() -> Self { Self { rx: [Self::NEW_PACKET; N_RX], @@ -39,33 +44,45 @@ struct StateInner<'d, const MTU: usize> { shared: Mutex>, } -/// State of the LinkState struct Shared { link_state: LinkState, waker: WakerRegistration, hardware_address: driver::HardwareAddress, } +/// Channel runner. +/// +/// Holds the shared state and the lower end of channels for inbound and outbound packets. pub struct Runner<'d, const MTU: usize> { tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, shared: &'d Mutex>, } +/// State runner. +/// +/// Holds the shared state of the channel such as link state. #[derive(Clone, Copy)] pub struct StateRunner<'d> { shared: &'d Mutex>, } +/// RX runner. +/// +/// Holds the lower end of the channel for passing inbound packets up the stack. pub struct RxRunner<'d, const MTU: usize> { rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, } +/// TX runner. +/// +/// Holds the lower end of the channel for passing outbound packets down the stack. pub struct TxRunner<'d, const MTU: usize> { tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, } impl<'d, const MTU: usize> Runner<'d, MTU> { + /// Split the runner into separate runners for controlling state, rx and tx. pub fn split(self) -> (StateRunner<'d>, RxRunner<'d, MTU>, TxRunner<'d, MTU>) { ( StateRunner { shared: self.shared }, @@ -74,6 +91,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { ) } + /// Split the runner into separate runners for controlling state, rx and tx borrowing the underlying state. pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) { ( StateRunner { shared: self.shared }, @@ -86,10 +104,12 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { ) } + /// Create a state runner sharing the state channel. pub fn state_runner(&self) -> StateRunner<'d> { StateRunner { shared: self.shared } } + /// Set the link state. pub fn set_link_state(&mut self, state: LinkState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); @@ -98,6 +118,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { }); } + /// Set the hardware address. pub fn set_hardware_address(&mut self, address: driver::HardwareAddress) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); @@ -106,16 +127,19 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { }); } + /// Wait until there is space for more inbound packets and return a slice they can be copied into. pub async fn rx_buf(&mut self) -> &mut [u8] { let p = self.rx_chan.send().await; &mut p.buf } + /// Check if there is space for more inbound packets right now. pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { let p = self.rx_chan.try_send()?; Some(&mut p.buf) } + /// Polling the inbound channel if there is space for packets. pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { match self.rx_chan.poll_send(cx) { Poll::Ready(p) => Poll::Ready(&mut p.buf), @@ -123,22 +147,26 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { } } + /// Mark packet of len bytes as pushed to the inbound channel. pub fn rx_done(&mut self, len: usize) { let p = self.rx_chan.try_send().unwrap(); p.len = len; self.rx_chan.send_done(); } + /// Wait until there is space for more outbound packets and return a slice they can be copied into. pub async fn tx_buf(&mut self) -> &mut [u8] { let p = self.tx_chan.receive().await; &mut p.buf[..p.len] } + /// Check if there is space for more outbound packets right now. pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { let p = self.tx_chan.try_receive()?; Some(&mut p.buf[..p.len]) } + /// Polling the outbound channel if there is space for packets. pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { match self.tx_chan.poll_receive(cx) { Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), @@ -146,12 +174,14 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { } } + /// Mark outbound packet as copied. pub fn tx_done(&mut self) { self.tx_chan.receive_done(); } } impl<'d> StateRunner<'d> { + /// Set link state. pub fn set_link_state(&self, state: LinkState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); @@ -160,6 +190,7 @@ impl<'d> StateRunner<'d> { }); } + /// Set the hardware address. pub fn set_hardware_address(&self, address: driver::HardwareAddress) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); @@ -170,16 +201,19 @@ impl<'d> StateRunner<'d> { } impl<'d, const MTU: usize> RxRunner<'d, MTU> { + /// Wait until there is space for more inbound packets and return a slice they can be copied into. pub async fn rx_buf(&mut self) -> &mut [u8] { let p = self.rx_chan.send().await; &mut p.buf } + /// Check if there is space for more inbound packets right now. pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { let p = self.rx_chan.try_send()?; Some(&mut p.buf) } + /// Polling the inbound channel if there is space for packets. pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { match self.rx_chan.poll_send(cx) { Poll::Ready(p) => Poll::Ready(&mut p.buf), @@ -187,6 +221,7 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> { } } + /// Mark packet of len bytes as pushed to the inbound channel. pub fn rx_done(&mut self, len: usize) { let p = self.rx_chan.try_send().unwrap(); p.len = len; @@ -195,16 +230,19 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> { } impl<'d, const MTU: usize> TxRunner<'d, MTU> { + /// Wait until there is space for more outbound packets and return a slice they can be copied into. pub async fn tx_buf(&mut self) -> &mut [u8] { let p = self.tx_chan.receive().await; &mut p.buf[..p.len] } + /// Check if there is space for more outbound packets right now. pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { let p = self.tx_chan.try_receive()?; Some(&mut p.buf[..p.len]) } + /// Polling the outbound channel if there is space for packets. pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { match self.tx_chan.poll_receive(cx) { Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), @@ -212,11 +250,18 @@ impl<'d, const MTU: usize> TxRunner<'d, MTU> { } } + /// Mark outbound packet as copied. pub fn tx_done(&mut self) { self.tx_chan.receive_done(); } } +/// Create a channel. +/// +/// Returns a pair of handles for interfacing with the peripheral and the networking stack. +/// +/// The runner is interfacing with the peripheral at the lower part of the stack. +/// The device is interfacing with the networking stack on the layer above. pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( state: &'d mut State, hardware_address: driver::HardwareAddress, @@ -257,17 +302,22 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( ) } +/// Represents a packet of size MTU. pub struct PacketBuf { len: usize, buf: [u8; MTU], } impl PacketBuf { + /// Create a new packet buffer. pub const fn new() -> Self { Self { len: 0, buf: [0; MTU] } } } +/// Channel device. +/// +/// Holds the shared state and upper end of channels for inbound and outbound packets. pub struct Device<'d, const MTU: usize> { rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, @@ -314,6 +364,9 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> { } } +/// A rx token. +/// +/// Holds inbound receive channel and interfaces with embassy-net-driver. pub struct RxToken<'a, const MTU: usize> { rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf>, } @@ -331,6 +384,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { } } +/// A tx token. +/// +/// Holds outbound transmit channel and interfaces with embassy-net-driver. pub struct TxToken<'a, const MTU: usize> { tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf>, } From abea4dde3d30388f8338985e323203d8792dabeb Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 10:09:05 +0100 Subject: [PATCH 078/760] docs: document most of esp-hosted driver --- embassy-net-esp-hosted/src/control.rs | 17 +++++++++++++++++ embassy-net-esp-hosted/src/lib.rs | 9 +++++++++ embassy-net-esp-hosted/src/proto.rs | 2 ++ 3 files changed, 28 insertions(+) diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index c86891bc3..b141bd6d2 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -5,6 +5,7 @@ use heapless::String; use crate::ioctl::Shared; use crate::proto::{self, CtrlMsg}; +/// Errors reported by control. #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { @@ -13,30 +14,42 @@ pub enum Error { Internal, } +/// Handle for managing the network and WiFI state. pub struct Control<'a> { state_ch: ch::StateRunner<'a>, shared: &'a Shared, } +/// WiFi mode. #[allow(unused)] #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] enum WifiMode { + /// No mode. None = 0, + /// Client station. Sta = 1, + /// Access point mode. Ap = 2, + /// Repeater mode. ApSta = 3, } pub use proto::CtrlWifiSecProt as Security; +/// WiFi status. #[derive(Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Status { + /// Service Set Identifier. pub ssid: String<32>, + /// Basic Service Set Identifier. pub bssid: [u8; 6], + /// Received Signal Strength Indicator. pub rssi: i32, + /// WiFi channel. pub channel: u32, + /// Security mode. pub security: Security, } @@ -65,6 +78,7 @@ impl<'a> Control<'a> { Self { state_ch, shared } } + /// Initialize device. pub async fn init(&mut self) -> Result<(), Error> { debug!("wait for init event..."); self.shared.init_wait().await; @@ -82,6 +96,7 @@ impl<'a> Control<'a> { Ok(()) } + /// Get the current status. pub async fn get_status(&mut self) -> Result { let req = proto::CtrlMsgReqGetApConfig {}; ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp); @@ -95,6 +110,7 @@ impl<'a> Control<'a> { }) } + /// Connect to the network identified by ssid using the provided password. pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> { let req = proto::CtrlMsgReqConnectAp { ssid: unwrap!(String::try_from(ssid)), @@ -108,6 +124,7 @@ impl<'a> Control<'a> { Ok(()) } + /// Disconnect from any currently connected network. pub async fn disconnect(&mut self) -> Result<(), Error> { let req = proto::CtrlMsgReqGetStatus {}; ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp); diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index d61eaef3a..ce7f39dc1 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -97,12 +97,14 @@ enum InterfaceType { const MAX_SPI_BUFFER_SIZE: usize = 1600; const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20); +/// Shared driver state. pub struct State { shared: Shared, ch: ch::State, } impl State { + /// Shared state for the pub fn new() -> Self { Self { shared: Shared::new(), @@ -111,8 +113,13 @@ impl State { } } +/// Type alias for network driver. pub type NetDriver<'a> = ch::Device<'a, MTU>; +/// Create a new esp-hosted driver using the provided state, SPI peripheral and pins. +/// +/// Returns a device handle for interfacing with embassy-net, a control handle for +/// interacting with the driver, and a runner for communicating with the WiFi device. pub async fn new<'a, SPI, IN, OUT>( state: &'a mut State, spi: SPI, @@ -144,6 +151,7 @@ where (device, Control::new(state_ch, &state.shared), runner) } +/// Runner for communicating with the WiFi device. pub struct Runner<'a, SPI, IN, OUT> { ch: ch::Runner<'a, MTU>, state_ch: ch::StateRunner<'a>, @@ -166,6 +174,7 @@ where { async fn init(&mut self) {} + /// Run the packet processing. pub async fn run(mut self) -> ! { debug!("resetting..."); self.reset.set_low().unwrap(); diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs index 8ceb1579d..b42ff62f1 100644 --- a/embassy-net-esp-hosted/src/proto.rs +++ b/embassy-net-esp-hosted/src/proto.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use heapless::{String, Vec}; /// internal supporting structures for CtrlMsg From 89cfdcb9f554c835d1228c1b9a191786d065df6a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 12:06:49 +0100 Subject: [PATCH 079/760] fix suddenly ending comment --- embassy-net-esp-hosted/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index ce7f39dc1..a5e9ddb4f 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -97,14 +97,14 @@ enum InterfaceType { const MAX_SPI_BUFFER_SIZE: usize = 1600; const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20); -/// Shared driver state. +/// State for the esp-hosted driver. pub struct State { shared: Shared, ch: ch::State, } impl State { - /// Shared state for the + /// Create a new state. pub fn new() -> Self { Self { shared: Shared::new(), From afb01e3fc51d44a637e99db3a16d0243a5921f6b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 12:05:17 +0100 Subject: [PATCH 080/760] docs: document embassy-net-tuntap --- embassy-net-tuntap/src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/embassy-net-tuntap/src/lib.rs b/embassy-net-tuntap/src/lib.rs index 75c54c487..de30934eb 100644 --- a/embassy-net-tuntap/src/lib.rs +++ b/embassy-net-tuntap/src/lib.rs @@ -1,3 +1,5 @@ +#![warn(missing_docs)] +#![doc = include_str!("../README.md")] use std::io; use std::io::{Read, Write}; use std::os::unix::io::{AsRawFd, RawFd}; @@ -7,12 +9,19 @@ use async_io::Async; use embassy_net_driver::{self, Capabilities, Driver, HardwareAddress, LinkState}; use log::*; +/// Get the MTU of the given interface. pub const SIOCGIFMTU: libc::c_ulong = 0x8921; +/// Get the index of the given interface. pub const _SIOCGIFINDEX: libc::c_ulong = 0x8933; +/// Capture all packages. pub const _ETH_P_ALL: libc::c_short = 0x0003; +/// Set the interface flags. pub const TUNSETIFF: libc::c_ulong = 0x400454CA; +/// TUN device. pub const _IFF_TUN: libc::c_int = 0x0001; +/// TAP device. pub const IFF_TAP: libc::c_int = 0x0002; +/// No packet information. pub const IFF_NO_PI: libc::c_int = 0x1000; const ETHERNET_HEADER_LEN: usize = 14; @@ -47,6 +56,7 @@ fn ifreq_ioctl(lower: libc::c_int, ifreq: &mut ifreq, cmd: libc::c_ulong) -> io: Ok(ifreq.ifr_data) } +/// A TUN/TAP device. #[derive(Debug)] pub struct TunTap { fd: libc::c_int, @@ -60,6 +70,7 @@ impl AsRawFd for TunTap { } impl TunTap { + /// Create a new TUN/TAP device. pub fn new(name: &str) -> io::Result { unsafe { let fd = libc::open( @@ -126,11 +137,13 @@ impl io::Write for TunTap { } } +/// A TUN/TAP device, wrapped in an async interface. pub struct TunTapDevice { device: Async, } impl TunTapDevice { + /// Create a new TUN/TAP device. pub fn new(name: &str) -> io::Result { Ok(Self { device: Async::new(TunTap::new(name)?)?, From 4a2dd7b944a4b81afdba6a4b1648f2c938d51096 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 12:14:25 +0100 Subject: [PATCH 081/760] docs: document public apis of wiznet driver --- embassy-net-wiznet/Cargo.toml | 1 + embassy-net-wiznet/src/chip/mod.rs | 2 ++ embassy-net-wiznet/src/chip/w5100s.rs | 1 + embassy-net-wiznet/src/chip/w5500.rs | 1 + embassy-net-wiznet/src/lib.rs | 2 ++ 5 files changed, 7 insertions(+) diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index a1f0b0c51..f628d8bd1 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -6,6 +6,7 @@ keywords = ["embedded", "wiznet", "embassy-net", "embedded-hal-async", "ethernet categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" +repository = "https://github.com/embassy-rs/embassy" [dependencies] embedded-hal = { version = "1.0.0-rc.3" } diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs index 562db515a..b987c2b36 100644 --- a/embassy-net-wiznet/src/chip/mod.rs +++ b/embassy-net-wiznet/src/chip/mod.rs @@ -1,3 +1,4 @@ +//! Wiznet W5100s and W5500 family driver. mod w5500; pub use w5500::W5500; mod w5100s; @@ -45,4 +46,5 @@ pub(crate) mod sealed { } } +/// Trait for Wiznet chips. pub trait Chip: sealed::Chip {} diff --git a/embassy-net-wiznet/src/chip/w5100s.rs b/embassy-net-wiznet/src/chip/w5100s.rs index 07a840370..7d328bce5 100644 --- a/embassy-net-wiznet/src/chip/w5100s.rs +++ b/embassy-net-wiznet/src/chip/w5100s.rs @@ -4,6 +4,7 @@ const SOCKET_BASE: u16 = 0x400; const TX_BASE: u16 = 0x4000; const RX_BASE: u16 = 0x6000; +/// Wizard W5100S chip. pub enum W5100S {} impl super::Chip for W5100S {} diff --git a/embassy-net-wiznet/src/chip/w5500.rs b/embassy-net-wiznet/src/chip/w5500.rs index 61e512946..16236126d 100644 --- a/embassy-net-wiznet/src/chip/w5500.rs +++ b/embassy-net-wiznet/src/chip/w5500.rs @@ -8,6 +8,7 @@ pub enum RegisterBlock { RxBuf = 0x03, } +/// Wiznet W5500 chip. pub enum W5500 {} impl super::Chip for W5500 {} diff --git a/embassy-net-wiznet/src/lib.rs b/embassy-net-wiznet/src/lib.rs index f26f2bbb7..da70d22bd 100644 --- a/embassy-net-wiznet/src/lib.rs +++ b/embassy-net-wiznet/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![allow(async_fn_in_trait)] #![doc = include_str!("../README.md")] +#![warn(missing_docs)] pub mod chip; mod device; @@ -47,6 +48,7 @@ pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> { /// You must call this in a background task for the driver to operate. impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> { + /// Run the driver. pub async fn run(mut self) -> ! { let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); let mut tick = Ticker::every(Duration::from_millis(500)); From 73f8cd7ade632a9905252698d09f71bd7ac3714c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 12:16:01 +0100 Subject: [PATCH 082/760] fix: add repository to manifest --- embassy-net-tuntap/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml index 4e374c365..7e2c7bfd5 100644 --- a/embassy-net-tuntap/Cargo.toml +++ b/embassy-net-tuntap/Cargo.toml @@ -6,6 +6,7 @@ keywords = ["embedded", "tuntap", "embassy-net", "embedded-hal-async", "ethernet categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" +repository = "https://github.com/embassy-rs/embassy" [dependencies] embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } @@ -16,4 +17,4 @@ libc = "0.2.101" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-tuntap-v$VERSION/embassy-net-tuntap/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-tuntap/src/" -target = "thumbv7em-none-eabi" \ No newline at end of file +target = "thumbv7em-none-eabi" From 4dfae9328e75ea5e7797b32b9c3a42f1babf6e35 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 12:18:02 +0100 Subject: [PATCH 083/760] add missing guards --- embassy-net-esp-hosted/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index a5e9ddb4f..c78578bf1 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -1,4 +1,6 @@ #![no_std] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] use embassy_futures::select::{select4, Either4}; use embassy_net_driver_channel as ch; From c3b827d8cd66ed64e22987ca27cf16e371755227 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 12:24:51 +0100 Subject: [PATCH 084/760] fix: add readme and fix remaining warnings --- embassy-net-esp-hosted/Cargo.toml | 4 ++++ embassy-net-esp-hosted/README.md | 27 +++++++++++++++++++++++++++ embassy-net-esp-hosted/src/control.rs | 3 +++ 3 files changed, 34 insertions(+) create mode 100644 embassy-net-esp-hosted/README.md diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 70b1bbe2a..b051b37ad 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -2,6 +2,10 @@ name = "embassy-net-esp-hosted" version = "0.1.0" edition = "2021" +description = "embassy-net driver for ESP-Hosted" +keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +license = "MIT OR Apache-2.0" [dependencies] defmt = { version = "0.3", optional = true } diff --git a/embassy-net-esp-hosted/README.md b/embassy-net-esp-hosted/README.md new file mode 100644 index 000000000..3c9cc4c9e --- /dev/null +++ b/embassy-net-esp-hosted/README.md @@ -0,0 +1,27 @@ +# ESP-Hosted `embassy-net` integration + +[`embassy-net`](https://crates.io/crates/embassy-net) integration for Espressif SoCs running the the ESP-Hosted stack. + +See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840) directory for usage examples with the nRF52840. + +## Supported chips + +- W5500 +- W5100S + +## Interoperability + +This crate can run on any executor. + +It supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async). + + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index b141bd6d2..c8cea8503 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -9,8 +9,11 @@ use crate::proto::{self, CtrlMsg}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// The operation failed with the given error code. Failed(u32), + /// The operation timed out. Timeout, + /// Internal error. Internal, } From 246c49621c30f1fb66fb328045934a8a0234855e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 12:51:47 +0100 Subject: [PATCH 085/760] docs: embassy-net-adin1110 --- embassy-net-adin1110/Cargo.toml | 3 +-- embassy-net-adin1110/src/crc32.rs | 7 +++++++ embassy-net-adin1110/src/lib.rs | 2 ++ embassy-net-adin1110/src/mdio.rs | 1 + embassy-net-adin1110/src/phy.rs | 5 +++++ embassy-net-adin1110/src/regs.rs | 1 + 6 files changed, 17 insertions(+), 2 deletions(-) diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index b1582ac9b..f1be52da5 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -6,8 +6,7 @@ keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethern categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +repository = "https://github.com/embassy-rs/embassy" [dependencies] heapless = "0.8" diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs index ec020b70c..d7c8346aa 100644 --- a/embassy-net-adin1110/src/crc32.rs +++ b/embassy-net-adin1110/src/crc32.rs @@ -1,3 +1,4 @@ +/// CRC32 lookup table. pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ 0x0000_0000, 0x7707_3096, @@ -263,8 +264,10 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ pub struct ETH_FCS(pub u32); impl ETH_FCS { + /// CRC32_OK pub const CRC32_OK: u32 = 0x2144_df1c; + /// Create a new frame check sequence from `data`. #[must_use] pub fn new(data: &[u8]) -> Self { let fcs = data.iter().fold(u32::MAX, |crc, byte| { @@ -274,6 +277,7 @@ impl ETH_FCS { Self(fcs) } + /// Update the frame check sequence with `data`. #[must_use] pub fn update(self, data: &[u8]) -> Self { let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| { @@ -283,16 +287,19 @@ impl ETH_FCS { Self(fcs) } + /// Check if the frame check sequence is correct. #[must_use] pub fn crc_ok(&self) -> bool { self.0 == Self::CRC32_OK } + /// Switch byte order. #[must_use] pub fn hton_bytes(&self) -> [u8; 4] { self.0.to_le_bytes() } + /// Switch byte order as a u32. #[must_use] pub fn hton(&self) -> u32 { self.0.to_le() diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 080b3f94d..4dafc8b0f 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -5,6 +5,7 @@ #![allow(clippy::missing_errors_doc)] #![allow(clippy::missing_panics_doc)] #![doc = include_str!("../README.md")] +#![warn(missing_docs)] // must go first! mod fmt; @@ -446,6 +447,7 @@ pub struct Runner<'d, SPI, INT, RST> { } impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { + /// Run the driver. #[allow(clippy::too_many_lines)] pub async fn run(mut self) -> ! { loop { diff --git a/embassy-net-adin1110/src/mdio.rs b/embassy-net-adin1110/src/mdio.rs index 1ae5f0043..6fea9370e 100644 --- a/embassy-net-adin1110/src/mdio.rs +++ b/embassy-net-adin1110/src/mdio.rs @@ -39,6 +39,7 @@ enum Reg13Op { /// /// Clause 45 methodes are bases on pub trait MdioBus { + /// Error type. type Error; /// Read, Clause 22 diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs index d54d843d2..a37b2baa3 100644 --- a/embassy-net-adin1110/src/phy.rs +++ b/embassy-net-adin1110/src/phy.rs @@ -30,6 +30,7 @@ pub mod RegsC45 { } impl DA1 { + /// Convert. #[must_use] pub fn into(self) -> (u8, u16) { (0x01, self as u16) @@ -49,6 +50,7 @@ pub mod RegsC45 { } impl DA3 { + /// Convert. #[must_use] pub fn into(self) -> (u8, u16) { (0x03, self as u16) @@ -64,6 +66,7 @@ pub mod RegsC45 { } impl DA7 { + /// Convert. #[must_use] pub fn into(self) -> (u8, u16) { (0x07, self as u16) @@ -87,6 +90,7 @@ pub mod RegsC45 { } impl DA1E { + /// Convert. #[must_use] pub fn into(self) -> (u8, u16) { (0x1e, self as u16) @@ -104,6 +108,7 @@ pub mod RegsC45 { } impl DA1F { + /// Convert. #[must_use] pub fn into(self) -> (u8, u16) { (0x1f, self as u16) diff --git a/embassy-net-adin1110/src/regs.rs b/embassy-net-adin1110/src/regs.rs index beaf9466e..8780c2b9d 100644 --- a/embassy-net-adin1110/src/regs.rs +++ b/embassy-net-adin1110/src/regs.rs @@ -2,6 +2,7 @@ use core::fmt::{Debug, Display}; use bitfield::{bitfield, bitfield_bitrange, bitfield_fields}; +#[allow(missing_docs)] #[allow(non_camel_case_types)] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] From b0583b17cbbf13988c37dcb1291d3acf6a78977c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 13:08:06 +0100 Subject: [PATCH 086/760] fix: make non-public instead --- embassy-net-adin1110/src/crc32.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs index d7c8346aa..4b3c69f23 100644 --- a/embassy-net-adin1110/src/crc32.rs +++ b/embassy-net-adin1110/src/crc32.rs @@ -264,8 +264,7 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ pub struct ETH_FCS(pub u32); impl ETH_FCS { - /// CRC32_OK - pub const CRC32_OK: u32 = 0x2144_df1c; + const CRC32_OK: u32 = 0x2144_df1c; /// Create a new frame check sequence from `data`. #[must_use] From 13c107e81582e2249df2fd940791b611a1ddbd62 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 20 Dec 2023 13:09:16 +0100 Subject: [PATCH 087/760] Put waiting state back if any --- embassy-sync/src/signal.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index 97d76b463..d75750ce7 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs @@ -117,7 +117,10 @@ where let state = cell.replace(State::None); match state { State::Signaled(res) => Some(res), - _ => None, + state => { + cell.set(state); + None + } } }) } From b8777eaea2e2f7966c1c0789e261bffcdc2a1be4 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 13:12:32 +0100 Subject: [PATCH 088/760] better keep missing docs for into --- embassy-net-adin1110/src/phy.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs index a37b2baa3..9966e1f6a 100644 --- a/embassy-net-adin1110/src/phy.rs +++ b/embassy-net-adin1110/src/phy.rs @@ -30,7 +30,7 @@ pub mod RegsC45 { } impl DA1 { - /// Convert. + #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x01, self as u16) @@ -50,7 +50,7 @@ pub mod RegsC45 { } impl DA3 { - /// Convert. + #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x03, self as u16) @@ -66,7 +66,7 @@ pub mod RegsC45 { } impl DA7 { - /// Convert. + #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x07, self as u16) @@ -90,7 +90,7 @@ pub mod RegsC45 { } impl DA1E { - /// Convert. + #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x1e, self as u16) @@ -108,7 +108,7 @@ pub mod RegsC45 { } impl DA1F { - /// Convert. + #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x1f, self as u16) From 1c3cf347cbd1b650f55a0c88a07210af83608157 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 13:20:43 +0100 Subject: [PATCH 089/760] remove embedded-sdmmc Remove support for embedded-sdmmc due to lack of maintainership. Bring it back once the upstream includes the async functionality. --- ci.sh | 4 +-- embassy-stm32/Cargo.toml | 1 - embassy-stm32/src/sdmmc/mod.rs | 50 ---------------------------------- examples/stm32f4/Cargo.toml | 2 +- 4 files changed, 3 insertions(+), 54 deletions(-) diff --git a/ci.sh b/ci.sh index 83c05d1b9..e3918783f 100755 --- a/ci.sh +++ b/ci.sh @@ -91,12 +91,12 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f417zg,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f423zh,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f427zi,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,embedded-sdmmc,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f437zi,log,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f439zi,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446ze,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f469zi,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,embedded-sdmmc,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 7f2cf6bfb..83db7c4bf 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -56,7 +56,6 @@ cortex-m = "0.7.6" futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand_core = "0.6.3" sdio-host = "0.5.0" -embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2234f380f51d16d0398b8e547088b33ea623cc7c" } vcell = "0.1.3" diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 10006baff..debe26c88 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1538,53 +1538,3 @@ foreach_peripheral!( impl Instance for peripherals::$inst {} }; ); - -#[cfg(feature = "embedded-sdmmc")] -mod sdmmc_rs { - use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx}; - - use super::*; - - impl<'d, T: Instance, Dma: SdmmcDma> BlockDevice for Sdmmc<'d, T, Dma> { - type Error = Error; - - async fn read( - &mut self, - blocks: &mut [Block], - start_block_idx: BlockIdx, - _reason: &str, - ) -> Result<(), Self::Error> { - let mut address = start_block_idx.0; - - for block in blocks.iter_mut() { - let block: &mut [u8; 512] = &mut block.contents; - - // NOTE(unsafe) Block uses align(4) - let block = unsafe { &mut *(block as *mut _ as *mut DataBlock) }; - self.read_block(address, block).await?; - address += 1; - } - Ok(()) - } - - async fn write(&mut self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> { - let mut address = start_block_idx.0; - - for block in blocks.iter() { - let block: &[u8; 512] = &block.contents; - - // NOTE(unsafe) DataBlock uses align 4 - let block = unsafe { &*(block as *const _ as *const DataBlock) }; - self.write_block(address, block).await?; - address += 1; - } - Ok(()) - } - - fn num_blocks(&self) -> Result { - let card = self.card()?; - let count = card.csd.block_count(); - Ok(BlockCount(count)) - } - } -} diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 6ea0018cd..e24fbee82 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } From 51a67cb69ab72e44c6cbeea677c4c6bd1e5c2550 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 13:34:34 +0100 Subject: [PATCH 090/760] fix: expose less --- embassy-net-adin1110/src/lib.rs | 5 +++-- embassy-net-adin1110/src/phy.rs | 5 ----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 4dafc8b0f..6ecfa587d 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -27,8 +27,9 @@ use embedded_hal_async::digital::Wait; use embedded_hal_async::spi::{Error, Operation, SpiDevice}; use heapless::Vec; pub use mdio::MdioBus; -pub use phy::{Phy10BaseT1x, RegsC22, RegsC45}; -pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; +pub use phy::Phy10BaseT1x; +use phy::{RegsC22, RegsC45}; +use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; use crate::fmt::Bytes; use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs index 9966e1f6a..d54d843d2 100644 --- a/embassy-net-adin1110/src/phy.rs +++ b/embassy-net-adin1110/src/phy.rs @@ -30,7 +30,6 @@ pub mod RegsC45 { } impl DA1 { - #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x01, self as u16) @@ -50,7 +49,6 @@ pub mod RegsC45 { } impl DA3 { - #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x03, self as u16) @@ -66,7 +64,6 @@ pub mod RegsC45 { } impl DA7 { - #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x07, self as u16) @@ -90,7 +87,6 @@ pub mod RegsC45 { } impl DA1E { - #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x1e, self as u16) @@ -108,7 +104,6 @@ pub mod RegsC45 { } impl DA1F { - #[allow(missing_docs)] #[must_use] pub fn into(self) -> (u8, u16) { (0x1f, self as u16) From 93bb34d8d1304a87ba62017834f4be848a1757e5 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 13:39:45 +0100 Subject: [PATCH 091/760] fix: expose less --- embassy-net-esp-hosted/src/proto.rs | 110 ++++++++++++++-------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs index b42ff62f1..034d5bf84 100644 --- a/embassy-net-esp-hosted/src/proto.rs +++ b/embassy-net-esp-hosted/src/proto.rs @@ -1,12 +1,10 @@ -#![allow(missing_docs)] - use heapless::{String, Vec}; /// internal supporting structures for CtrlMsg #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ScanResult { +pub(crate) struct ScanResult { #[noproto(tag = "1")] pub ssid: String<32>, #[noproto(tag = "2")] @@ -21,7 +19,7 @@ pub struct ScanResult { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ConnectedStaList { +pub(crate) struct ConnectedStaList { #[noproto(tag = "1")] pub mac: String<32>, #[noproto(tag = "2")] @@ -31,14 +29,14 @@ pub struct ConnectedStaList { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqGetMacAddress { +pub(crate) struct CtrlMsgReqGetMacAddress { #[noproto(tag = "1")] pub mode: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespGetMacAddress { +pub(crate) struct CtrlMsgRespGetMacAddress { #[noproto(tag = "1")] pub mac: String<32>, #[noproto(tag = "2")] @@ -47,11 +45,11 @@ pub struct CtrlMsgRespGetMacAddress { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqGetMode {} +pub(crate) struct CtrlMsgReqGetMode {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespGetMode { +pub(crate) struct CtrlMsgRespGetMode { #[noproto(tag = "1")] pub mode: u32, #[noproto(tag = "2")] @@ -60,32 +58,32 @@ pub struct CtrlMsgRespGetMode { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqSetMode { +pub(crate) struct CtrlMsgReqSetMode { #[noproto(tag = "1")] pub mode: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespSetMode { +pub(crate) struct CtrlMsgRespSetMode { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqGetStatus {} +pub(crate) struct CtrlMsgReqGetStatus {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespGetStatus { +pub(crate) struct CtrlMsgRespGetStatus { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqSetMacAddress { +pub(crate) struct CtrlMsgReqSetMacAddress { #[noproto(tag = "1")] pub mac: String<32>, #[noproto(tag = "2")] @@ -94,18 +92,18 @@ pub struct CtrlMsgReqSetMacAddress { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespSetMacAddress { +pub(crate) struct CtrlMsgRespSetMacAddress { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqGetApConfig {} +pub(crate) struct CtrlMsgReqGetApConfig {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespGetApConfig { +pub(crate) struct CtrlMsgRespGetApConfig { #[noproto(tag = "1")] pub ssid: String<32>, #[noproto(tag = "2")] @@ -122,7 +120,7 @@ pub struct CtrlMsgRespGetApConfig { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqConnectAp { +pub(crate) struct CtrlMsgReqConnectAp { #[noproto(tag = "1")] pub ssid: String<32>, #[noproto(tag = "2")] @@ -137,7 +135,7 @@ pub struct CtrlMsgReqConnectAp { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespConnectAp { +pub(crate) struct CtrlMsgRespConnectAp { #[noproto(tag = "1")] pub resp: u32, #[noproto(tag = "2")] @@ -146,11 +144,11 @@ pub struct CtrlMsgRespConnectAp { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqGetSoftApConfig {} +pub(crate) struct CtrlMsgReqGetSoftApConfig {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespGetSoftApConfig { +pub(crate) struct CtrlMsgRespGetSoftApConfig { #[noproto(tag = "1")] pub ssid: String<32>, #[noproto(tag = "2")] @@ -171,7 +169,7 @@ pub struct CtrlMsgRespGetSoftApConfig { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqStartSoftAp { +pub(crate) struct CtrlMsgReqStartSoftAp { #[noproto(tag = "1")] pub ssid: String<32>, #[noproto(tag = "2")] @@ -190,7 +188,7 @@ pub struct CtrlMsgReqStartSoftAp { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespStartSoftAp { +pub(crate) struct CtrlMsgRespStartSoftAp { #[noproto(tag = "1")] pub resp: u32, #[noproto(tag = "2")] @@ -199,11 +197,11 @@ pub struct CtrlMsgRespStartSoftAp { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqScanResult {} +pub(crate) struct CtrlMsgReqScanResult {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespScanResult { +pub(crate) struct CtrlMsgRespScanResult { #[noproto(tag = "1")] pub count: u32, #[noproto(repeated, tag = "2")] @@ -214,11 +212,11 @@ pub struct CtrlMsgRespScanResult { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqSoftApConnectedSta {} +pub(crate) struct CtrlMsgReqSoftApConnectedSta {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespSoftApConnectedSta { +pub(crate) struct CtrlMsgRespSoftApConnectedSta { #[noproto(tag = "1")] pub num: u32, #[noproto(repeated, tag = "2")] @@ -229,43 +227,43 @@ pub struct CtrlMsgRespSoftApConnectedSta { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqOtaBegin {} +pub(crate) struct CtrlMsgReqOtaBegin {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespOtaBegin { +pub(crate) struct CtrlMsgRespOtaBegin { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqOtaWrite { +pub(crate) struct CtrlMsgReqOtaWrite { #[noproto(tag = "1")] pub ota_data: Vec, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespOtaWrite { +pub(crate) struct CtrlMsgRespOtaWrite { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqOtaEnd {} +pub(crate) struct CtrlMsgReqOtaEnd {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespOtaEnd { +pub(crate) struct CtrlMsgRespOtaEnd { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqVendorIeData { +pub(crate) struct CtrlMsgReqVendorIeData { #[noproto(tag = "1")] pub element_id: u32, #[noproto(tag = "2")] @@ -280,7 +278,7 @@ pub struct CtrlMsgReqVendorIeData { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqSetSoftApVendorSpecificIe { +pub(crate) struct CtrlMsgReqSetSoftApVendorSpecificIe { #[noproto(tag = "1")] pub enable: bool, #[noproto(tag = "2")] @@ -293,32 +291,32 @@ pub struct CtrlMsgReqSetSoftApVendorSpecificIe { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespSetSoftApVendorSpecificIe { +pub(crate) struct CtrlMsgRespSetSoftApVendorSpecificIe { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqSetWifiMaxTxPower { +pub(crate) struct CtrlMsgReqSetWifiMaxTxPower { #[noproto(tag = "1")] pub wifi_max_tx_power: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespSetWifiMaxTxPower { +pub(crate) struct CtrlMsgRespSetWifiMaxTxPower { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqGetWifiCurrTxPower {} +pub(crate) struct CtrlMsgReqGetWifiCurrTxPower {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespGetWifiCurrTxPower { +pub(crate) struct CtrlMsgRespGetWifiCurrTxPower { #[noproto(tag = "1")] pub wifi_curr_tx_power: u32, #[noproto(tag = "2")] @@ -327,7 +325,7 @@ pub struct CtrlMsgRespGetWifiCurrTxPower { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgReqConfigHeartbeat { +pub(crate) struct CtrlMsgReqConfigHeartbeat { #[noproto(tag = "1")] pub enable: bool, #[noproto(tag = "2")] @@ -336,7 +334,7 @@ pub struct CtrlMsgReqConfigHeartbeat { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgRespConfigHeartbeat { +pub(crate) struct CtrlMsgRespConfigHeartbeat { #[noproto(tag = "1")] pub resp: u32, } @@ -344,28 +342,28 @@ pub struct CtrlMsgRespConfigHeartbeat { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgEventEspInit { +pub(crate) struct CtrlMsgEventEspInit { #[noproto(tag = "1")] pub init_data: Vec, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgEventHeartbeat { +pub(crate) struct CtrlMsgEventHeartbeat { #[noproto(tag = "1")] pub hb_num: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgEventStationDisconnectFromAp { +pub(crate) struct CtrlMsgEventStationDisconnectFromAp { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsgEventStationDisconnectFromEspSoftAp { +pub(crate) struct CtrlMsgEventStationDisconnectFromEspSoftAp { #[noproto(tag = "1")] pub resp: u32, #[noproto(tag = "2")] @@ -374,7 +372,7 @@ pub struct CtrlMsgEventStationDisconnectFromEspSoftAp { #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CtrlMsg { +pub(crate) struct CtrlMsg { /// msg_type could be req, resp or Event #[noproto(tag = "1")] pub msg_type: CtrlMsgType, @@ -392,7 +390,7 @@ pub struct CtrlMsg { /// union of all msg ids #[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlMsgPayload { +pub(crate) enum CtrlMsgPayload { /// * Requests * #[noproto(tag = "101")] ReqGetMacAddress(CtrlMsgReqGetMacAddress), @@ -494,7 +492,7 @@ pub enum CtrlMsgPayload { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlVendorIeType { +pub(crate) enum CtrlVendorIeType { #[default] Beacon = 0, ProbeReq = 1, @@ -506,7 +504,7 @@ pub enum CtrlVendorIeType { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlVendorIeid { +pub(crate) enum CtrlVendorIeid { #[default] Id0 = 0, Id1 = 1, @@ -515,7 +513,7 @@ pub enum CtrlVendorIeid { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlWifiMode { +pub(crate) enum CtrlWifiMode { #[default] None = 0, Sta = 1, @@ -526,7 +524,7 @@ pub enum CtrlWifiMode { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlWifiBw { +pub(crate) enum CtrlWifiBw { #[default] BwInvalid = 0, Ht20 = 1, @@ -536,13 +534,15 @@ pub enum CtrlWifiBw { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlWifiPowerSave { +pub(crate) enum CtrlWifiPowerSave { #[default] PsInvalid = 0, MinModem = 1, MaxModem = 2, } +/// Wifi Security Settings +#[allow(missing_docs)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -562,7 +562,7 @@ pub enum CtrlWifiSecProt { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlStatus { +pub(crate) enum CtrlStatus { #[default] Connected = 0, NotConnected = 1, @@ -575,7 +575,7 @@ pub enum CtrlStatus { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlMsgType { +pub(crate) enum CtrlMsgType { #[default] MsgTypeInvalid = 0, Req = 1, @@ -587,7 +587,7 @@ pub enum CtrlMsgType { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CtrlMsgId { +pub(crate) enum CtrlMsgId { #[default] MsgIdInvalid = 0, /// * Request Msgs * From 896690c41573f1c06c4efa02d367b70741322cdb Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 20 Dec 2023 13:46:43 +0100 Subject: [PATCH 092/760] fix: remove git dependency in embassy-boot --- embassy-boot/nrf/Cargo.toml | 8 +++++++- embassy-boot/rp/Cargo.toml | 6 ++++++ embassy-boot/stm32/Cargo.toml | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/embassy-boot/nrf/Cargo.toml b/embassy-boot/nrf/Cargo.toml index eea29cf2e..9f74fb126 100644 --- a/embassy-boot/nrf/Cargo.toml +++ b/embassy-boot/nrf/Cargo.toml @@ -4,6 +4,12 @@ name = "embassy-boot-nrf" version = "0.1.0" description = "Bootloader lib for nRF chips" license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +categories = [ + "embedded", + "no-std", + "asynchronous", +] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/nrf/src/" @@ -25,7 +31,7 @@ embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } cfg-if = "1.0.0" -nrf-softdevice-mbr = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-softdevice.git", branch = "master", optional = true } +nrf-softdevice-mbr = { version = "0.2.0", optional = true } [features] defmt = [ diff --git a/embassy-boot/rp/Cargo.toml b/embassy-boot/rp/Cargo.toml index 0f2dc4628..90bab0996 100644 --- a/embassy-boot/rp/Cargo.toml +++ b/embassy-boot/rp/Cargo.toml @@ -4,6 +4,12 @@ name = "embassy-boot-rp" version = "0.1.0" description = "Bootloader lib for RP2040 chips" license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +categories = [ + "embedded", + "no-std", + "asynchronous", +] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/" diff --git a/embassy-boot/stm32/Cargo.toml b/embassy-boot/stm32/Cargo.toml index bc8da6738..70919b76d 100644 --- a/embassy-boot/stm32/Cargo.toml +++ b/embassy-boot/stm32/Cargo.toml @@ -4,6 +4,12 @@ name = "embassy-boot-stm32" version = "0.1.0" description = "Bootloader lib for STM32 chips" license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +categories = [ + "embedded", + "no-std", + "asynchronous", +] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/stm32/src/" From d6fda686bce8b0f6e0ccc1196d22ddc86baa34e6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 20 Dec 2023 14:13:52 +0100 Subject: [PATCH 093/760] net-esp-hosted: use released noproto version. --- embassy-net-esp-hosted/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index b051b37ad..61984dd53 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -19,8 +19,7 @@ embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver- embedded-hal = { version = "1.0.0-rc.3" } embedded-hal-async = { version = "=1.0.0-rc.3" } -noproto = { git="https://github.com/embassy-rs/noproto", rev = "f5e6d1f325b6ad4e344f60452b09576e24671f62", default-features = false, features = ["derive"] } -#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] } +noproto = "0.1.0" heapless = "0.8" [package.metadata.embassy_docs] From 745d618ab7f40f518c25d8db2116cfd774c16623 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 21 Dec 2023 16:59:20 +0800 Subject: [PATCH 094/760] note on circular mode DMA --- embassy-stm32/src/dma/bdma.rs | 4 ++++ embassy-stm32/src/dma/dma.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 2f37b1edf..a2b83716d 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -23,6 +23,10 @@ use crate::pac::bdma::{regs, vals}; #[non_exhaustive] pub struct TransferOptions { /// Enable circular DMA + /// + /// Note: + /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task. + /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever. pub circular: bool, /// Enable half transfer interrupt pub half_transfer_ir: bool, diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 9b47ca5c3..16d02f273 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -30,6 +30,10 @@ pub struct TransferOptions { /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. pub fifo_threshold: Option, /// Enable circular DMA + /// + /// Note: + /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task. + /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever. pub circular: bool, /// Enable half transfer interrupt pub half_transfer_ir: bool, From 0acf7b09c3bc9176d00479d601356d8df2537a9b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 21 Dec 2023 08:50:54 +0100 Subject: [PATCH 095/760] chore: replace make_static! macro usage with non-macro version --- embassy-net/src/lib.rs | 6 ++-- embassy-stm32/src/low_power.rs | 5 +-- .../nrf52840/src/bin/ethernet_enc28j60.rs | 17 +++++++--- examples/nrf52840/src/bin/usb_ethernet.rs | 32 +++++++++++-------- .../nrf52840/src/bin/usb_serial_multitask.rs | 20 ++++++++---- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 13 +++++--- .../rp/src/bin/ethernet_w5500_multisocket.rs | 13 +++++--- .../rp/src/bin/ethernet_w5500_tcp_client.rs | 13 +++++--- .../rp/src/bin/ethernet_w5500_tcp_server.rs | 13 +++++--- examples/rp/src/bin/ethernet_w5500_udp.rs | 13 +++++--- examples/rp/src/bin/uart_buffered_split.rs | 8 +++-- examples/rp/src/bin/usb_ethernet.rs | 28 ++++++++++------ examples/rp/src/bin/wifi_ap_tcp_server.rs | 13 +++++--- examples/rp/src/bin/wifi_blinky.rs | 5 +-- examples/rp/src/bin/wifi_scan.rs | 5 +-- examples/rp/src/bin/wifi_tcp_server.rs | 13 +++++--- examples/std/src/bin/net.rs | 10 +++--- examples/std/src/bin/net_dns.rs | 10 +++--- examples/std/src/bin/net_ppp.rs | 13 +++++--- examples/std/src/bin/net_udp.rs | 10 +++--- examples/std/src/bin/tcp_accept.rs | 10 +++--- examples/stm32f4/src/bin/eth.rs | 13 +++++--- examples/stm32f4/src/bin/usb_ethernet.rs | 31 +++++++++++------- examples/stm32f7/src/bin/can.rs | 7 ++-- examples/stm32f7/src/bin/eth.rs | 13 +++++--- examples/stm32h5/src/bin/eth.rs | 13 +++++--- examples/stm32h7/src/bin/eth.rs | 13 +++++--- examples/stm32h7/src/bin/eth_client.rs | 13 +++++--- .../src/bin/spe_adin1110_http_server.rs | 13 +++++--- examples/stm32l5/src/bin/usb_ethernet.rs | 28 ++++++++++------ examples/stm32wb/src/bin/mac_ffd_net.rs | 20 ++++++++---- tests/nrf/src/bin/ethernet_enc28j60_perf.rs | 10 +++--- tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 13 +++++--- tests/rp/src/bin/cyw43-perf.rs | 13 +++++--- tests/rp/src/bin/ethernet_w5100s_perf.rs | 13 +++++--- tests/stm32/src/bin/eth.rs | 13 +++++--- tests/stm32/src/bin/stop.rs | 5 +-- 37 files changed, 313 insertions(+), 188 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index bf1468642..d970d0332 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -411,10 +411,12 @@ impl Stack { /// ```ignore /// let config = embassy_net::Config::dhcpv4(Default::default()); ///// Init network stack - /// let stack = &*make_static!(embassy_net::Stack::new( + /// static RESOURCES: StaticCell = StaticCell::new(); + /// static STACK: StaticCell = StaticCell::new(); + /// let stack = &*STACK.init(embassy_net::Stack::new( /// device, /// config, - /// make_static!(embassy_net::StackResources::<2>::new()), + /// RESOURCES.init(embassy_net::StackResources::new()), /// seed /// )); /// // Launch network task that runs `stack.run().await` diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index a41c40eba..4fab8dae4 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -24,7 +24,7 @@ //! use embassy_executor::Spawner; //! use embassy_stm32::low_power::Executor; //! use embassy_stm32::rtc::{Rtc, RtcConfig}; -//! use static_cell::make_static; +//! use static_cell::StaticCell; //! //! #[cortex_m_rt::entry] //! fn main() -> ! { @@ -41,7 +41,8 @@ //! //! // give the RTC to the executor... //! let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); -//! let rtc = make_static!(rtc); +//! static RTC: StaticCell = StaticCell::new(); +//! let rtc = RTC.init(rtc); //! embassy_stm32::low_power::stop_with_rtc(rtc); //! //! // your application here... diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index d1b796fab..840a16556 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -14,7 +14,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spim}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -70,11 +70,20 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static RESOURCES: StaticCell> = StaticCell::new(); + static STACK: StaticCell< + Stack< + Enc28j60< + ExclusiveDevice, Output<'static, peripherals::P0_15>, Delay>, + Output<'static, peripherals::P0_13>, + >, + >, + > = StaticCell::new(); + let stack = STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index b7806f418..de661c019 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -16,7 +16,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, Config, UsbDevice}; use embedded_io_async::Write; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -71,14 +71,19 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; // Create embassy-usb DeviceBuilder using the driver and config. + static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); + static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); let mut builder = Builder::new( driver, config, - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], - &mut make_static!([0; 128])[..], - &mut make_static!([0; 128])[..], + &mut DEVICE_DESC.init([0; 256])[..], + &mut CONFIG_DESC.init([0; 256])[..], + &mut BOS_DESC.init([0; 256])[..], + &mut MSOS_DESC.init([0; 128])[..], + &mut CONTROL_BUF.init([0; 128])[..], ); // Our MAC addr. @@ -87,14 +92,16 @@ async fn main(spawner: Spawner) { let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; // Create classes on the builder. - let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); + static STATE: StaticCell = StaticCell::new(); + let class = CdcNcmClass::new(&mut builder, STATE.init(State::new()), host_mac_addr, 64); // Build the builder. let usb = builder.build(); unwrap!(spawner.spawn(usb_task(usb))); - let (runner, device) = class.into_embassy_net_device::(make_static!(NetState::new()), our_mac_addr); + static NET_STATE: StaticCell> = StaticCell::new(); + let (runner, device) = class.into_embassy_net_device::(NET_STATE.init(NetState::new()), our_mac_addr); unwrap!(spawner.spawn(usb_ncm_task(runner))); let config = embassy_net::Config::dhcpv4(Default::default()); @@ -111,12 +118,9 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( - device, - config, - make_static!(StackResources::<2>::new()), - seed - )); + static RESOURCES: StaticCell> = StaticCell::new(); + static STACK: StaticCell>> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index cd4392903..7a7bf962b 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -12,7 +12,7 @@ use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::{Builder, Config, UsbDevice}; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -64,17 +64,23 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; config.composite_with_iads = true; - let state = make_static!(State::new()); + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(State::new()); // Create embassy-usb DeviceBuilder using the driver and config. + static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); + static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); let mut builder = Builder::new( driver, config, - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], - &mut make_static!([0; 128])[..], - &mut make_static!([0; 128])[..], + &mut DEVICE_DESC.init([0; 256])[..], + &mut CONFIG_DESC.init([0; 256])[..], + &mut BOS_DESC.init([0; 256])[..], + &mut MSOS_DESC.init([0; 128])[..], + &mut CONTROL_BUF.init([0; 128])[..], ); // Create classes on the builder. diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index a60822fd9..b56c9bd8d 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -13,7 +13,7 @@ use embassy_nrf::{bind_interrupts, peripherals}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; const WIFI_NETWORK: &str = "EmbassyTest"; @@ -61,8 +61,9 @@ async fn main(spawner: Spawner) { let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); let spi = ExclusiveDevice::new(spi, cs, Delay); + static ESP_STATE: StaticCell = StaticCell::new(); let (device, mut control, runner) = embassy_net_esp_hosted::new( - make_static!(embassy_net_esp_hosted::State::new()), + ESP_STATE.init(embassy_net_esp_hosted::State::new()), spi, handshake, ready, @@ -89,11 +90,13 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static RESOURCES: StaticCell> = StaticCell::new(); + static STACK: StaticCell>> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index c0fde62ab..b9dba0f1d 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -20,7 +20,7 @@ use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; use rand::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] @@ -55,7 +55,8 @@ async fn main(spawner: Spawner) { let w5500_reset = Output::new(p.PIN_20, Level::High); let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; - let state = make_static!(State::<8, 8>::new()); + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); let (device, runner) = embassy_net_wiznet::new( mac_addr, state, @@ -70,11 +71,13 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - make_static!(StackResources::<3>::new()), - seed + RESOURCES.init(StackResources::<3>::new()), + seed, )); // Launch network task diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index b19362fc1..36073f20b 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -22,7 +22,7 @@ use embassy_time::{Delay, Duration, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; use rand::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] @@ -58,7 +58,8 @@ async fn main(spawner: Spawner) { let w5500_reset = Output::new(p.PIN_20, Level::High); let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; - let state = make_static!(State::<8, 8>::new()); + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); let (device, runner) = embassy_net_wiznet::new( mac_addr, state, @@ -73,11 +74,13 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index c62caed7a..d523a8772 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -21,7 +21,7 @@ use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; use rand::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] @@ -57,7 +57,8 @@ async fn main(spawner: Spawner) { let w5500_reset = Output::new(p.PIN_20, Level::High); let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; - let state = make_static!(State::<8, 8>::new()); + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); let (device, runner) = embassy_net_wiznet::new( mac_addr, state, @@ -72,11 +73,13 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 76dabce1c..0cc47cb56 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -20,7 +20,7 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use rand::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] @@ -55,7 +55,8 @@ async fn main(spawner: Spawner) { let w5500_reset = Output::new(p.PIN_20, Level::High); let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; - let state = make_static!(State::<8, 8>::new()); + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); let (device, runner) = embassy_net_wiznet::new( mac_addr, state, @@ -70,11 +71,13 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs index 14e8810a4..dc57d89c7 100644 --- a/examples/rp/src/bin/uart_buffered_split.rs +++ b/examples/rp/src/bin/uart_buffered_split.rs @@ -15,7 +15,7 @@ use embassy_rp::peripherals::UART0; use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; use embassy_time::Timer; use embedded_io_async::{Read, Write}; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -27,8 +27,10 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0); - let tx_buf = &mut make_static!([0u8; 16])[..]; - let rx_buf = &mut make_static!([0u8; 16])[..]; + static TX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); + let tx_buf = &mut TX_BUF.init([0; 16])[..]; + static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); + let rx_buf = &mut RX_BUF.init([0; 16])[..]; let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); let (rx, mut tx) = uart.split(); diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index cc63029fb..674b83f5d 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -17,7 +17,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, Config, UsbDevice}; use embedded_io_async::Write; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -65,14 +65,18 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; // Create embassy-usb DeviceBuilder using the driver and config. + static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); let mut builder = Builder::new( driver, config, - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], + &mut DEVICE_DESC.init([0; 256])[..], + &mut CONFIG_DESC.init([0; 256])[..], + &mut BOS_DESC.init([0; 256])[..], &mut [], // no msos descriptors - &mut make_static!([0; 128])[..], + &mut CONTROL_BUF.init([0; 128])[..], ); // Our MAC addr. @@ -81,14 +85,16 @@ async fn main(spawner: Spawner) { let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; // Create classes on the builder. - let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); + static STATE: StaticCell = StaticCell::new(); + let class = CdcNcmClass::new(&mut builder, STATE.init(State::new()), host_mac_addr, 64); // Build the builder. let usb = builder.build(); unwrap!(spawner.spawn(usb_task(usb))); - let (runner, device) = class.into_embassy_net_device::(make_static!(NetState::new()), our_mac_addr); + static NET_STATE: StaticCell> = StaticCell::new(); + let (runner, device) = class.into_embassy_net_device::(NET_STATE.init(NetState::new()), our_mac_addr); unwrap!(spawner.spawn(usb_ncm_task(runner))); let config = embassy_net::Config::dhcpv4(Default::default()); @@ -102,11 +108,13 @@ async fn main(spawner: Spawner) { let seed = 1234; // guaranteed random, chosen by a fair dice roll // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index ad1fa6462..20b8aad15 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -19,7 +19,7 @@ use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::Duration; use embedded_io_async::Write; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -59,7 +59,8 @@ async fn main(spawner: Spawner) { let mut pio = Pio::new(p.PIO0, Irqs); let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); - let state = make_static!(cyw43::State::new()); + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; unwrap!(spawner.spawn(wifi_task(runner))); @@ -79,11 +80,13 @@ async fn main(spawner: Spawner) { let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( net_device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 14ace74e9..b89447b7d 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -14,7 +14,7 @@ use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::{Duration, Timer}; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -46,7 +46,8 @@ async fn main(spawner: Spawner) { let mut pio = Pio::new(p.PIO0, Irqs); let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); - let state = make_static!(cyw43::State::new()); + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(cyw43::State::new()); let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; unwrap!(spawner.spawn(wifi_task(runner))); diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 7adf52b88..0f7ad27dd 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -16,7 +16,7 @@ use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -56,7 +56,8 @@ async fn main(spawner: Spawner) { let mut pio = Pio::new(p.PIO0, Irqs); let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); - let state = make_static!(cyw43::State::new()); + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(cyw43::State::new()); let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; unwrap!(spawner.spawn(wifi_task(runner))); diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index ec6b4ee74..f6cc48d8f 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -19,7 +19,7 @@ use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -62,7 +62,8 @@ async fn main(spawner: Spawner) { let mut pio = Pio::new(p.PIO0, Irqs); let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); - let state = make_static!(cyw43::State::new()); + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; unwrap!(spawner.spawn(wifi_task(runner))); @@ -82,11 +83,13 @@ async fn main(spawner: Spawner) { let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( net_device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index 8d8345057..c62a38d07 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -12,7 +12,7 @@ use embedded_io_async::Write; use heapless::Vec; use log::*; use rand_core::{OsRng, RngCore}; -use static_cell::{make_static, StaticCell}; +use static_cell::StaticCell; #[derive(Parser)] #[clap(version = "1.0")] @@ -54,11 +54,13 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<3>::new()), - seed + RESOURCES.init(StackResources::<3>::new()), + seed, )); // Launch network task diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index 6c19874d5..e1e015bc8 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs @@ -10,7 +10,7 @@ use embassy_net_tuntap::TunTapDevice; use heapless::Vec; use log::*; use rand_core::{OsRng, RngCore}; -use static_cell::{make_static, StaticCell}; +use static_cell::StaticCell; #[derive(Parser)] #[clap(version = "1.0")] @@ -53,11 +53,13 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack: &Stack<_> = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack: &Stack<_> = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<3>::new()), - seed + RESOURCES.init(StackResources::<3>::new()), + seed, )); // Launch network task diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index cee04e558..8c80c4beb 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -25,7 +25,7 @@ use heapless::Vec; use log::*; use nix::sys::termios; use rand_core::{OsRng, RngCore}; -use static_cell::{make_static, StaticCell}; +use static_cell::StaticCell; use crate::serial_port::SerialPort; @@ -88,7 +88,8 @@ async fn main_task(spawner: Spawner) { let port = SerialPort::new(opts.device.as_str(), baudrate).unwrap(); // Init network device - let state = make_static!(embassy_net_ppp::State::<4, 4>::new()); + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(embassy_net_ppp::State::<4, 4>::new()); let (device, runner) = embassy_net_ppp::new(state); // Generate random seed @@ -97,11 +98,13 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, Config::default(), // don't configure IP yet - make_static!(StackResources::<3>::new()), - seed + RESOURCES.init(StackResources::<3>::new()), + seed, )); // Launch network task diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs index 98dcc9925..ac99ec626 100644 --- a/examples/std/src/bin/net_udp.rs +++ b/examples/std/src/bin/net_udp.rs @@ -8,7 +8,7 @@ use embassy_net_tuntap::TunTapDevice; use heapless::Vec; use log::*; use rand_core::{OsRng, RngCore}; -use static_cell::{make_static, StaticCell}; +use static_cell::StaticCell; #[derive(Parser)] #[clap(version = "1.0")] @@ -50,11 +50,13 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<3>::new()), - seed + RESOURCES.init(StackResources::<3>::new()), + seed, )); // Launch network task diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 79fa375cd..54ef0156b 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs @@ -13,7 +13,7 @@ use embedded_io_async::Write as _; use heapless::Vec; use log::*; use rand_core::{OsRng, RngCore}; -use static_cell::{make_static, StaticCell}; +use static_cell::StaticCell; #[derive(Parser)] #[clap(version = "1.0")] @@ -65,11 +65,13 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<3>::new()), - seed + RESOURCES.init(StackResources::<3>::new()), + seed, )); // Launch network task diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 088d83c06..17a14aac4 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -14,7 +14,7 @@ use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -63,8 +63,9 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - make_static!(PacketQueue::<16, 16>::new()), + PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, p.PA1, @@ -88,11 +89,13 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 6bf5b1cba..57ee35e97 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -14,7 +14,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; use embedded_io_async::Write; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>; @@ -68,7 +68,8 @@ async fn main(spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let ep_out_buffer = &mut make_static!([0; 256])[..]; + static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); + let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; let mut config = embassy_stm32::usb_otg::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); @@ -88,14 +89,18 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; // Create embassy-usb DeviceBuilder using the driver and config. + static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); let mut builder = Builder::new( driver, config, - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], + &mut DEVICE_DESC.init([0; 256])[..], + &mut CONFIG_DESC.init([0; 256])[..], + &mut BOS_DESC.init([0; 256])[..], &mut [], // no msos descriptors - &mut make_static!([0; 128])[..], + &mut CONTROL_BUF.init([0; 128])[..], ); // Our MAC addr. @@ -104,14 +109,16 @@ async fn main(spawner: Spawner) { let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; // Create classes on the builder. - let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); + static STATE: StaticCell = StaticCell::new(); + let class = CdcNcmClass::new(&mut builder, STATE.init(State::new()), host_mac_addr, 64); // Build the builder. let usb = builder.build(); unwrap!(spawner.spawn(usb_task(usb))); - let (runner, device) = class.into_embassy_net_device::(make_static!(NetState::new()), our_mac_addr); + static NET_STATE: StaticCell> = StaticCell::new(); + let (runner, device) = class.into_embassy_net_device::(NET_STATE.init(NetState::new()), our_mac_addr); unwrap!(spawner.spawn(usb_ncm_task(runner))); let config = embassy_net::Config::dhcpv4(Default::default()); @@ -128,11 +135,13 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 78b21ceaa..06cd1ac7e 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -12,6 +12,7 @@ use embassy_stm32::can::{ }; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN3; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -43,7 +44,8 @@ async fn main(spawner: Spawner) { let rx_pin = Input::new(&mut p.PA15, Pull::Up); core::mem::forget(rx_pin); - let can: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); + static CAN: StaticCell> = StaticCell::new(); + let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); can.as_mut() .modify_filters() .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); @@ -56,7 +58,8 @@ async fn main(spawner: Spawner) { let (tx, mut rx) = can.split(); - let tx: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx); + static CAN_TX: StaticCell> = StaticCell::new(); + let tx = CAN_TX.init(tx); spawner.spawn(send_can_message(tx)).unwrap(); loop { diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index dd0069447..86c709852 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -15,7 +15,7 @@ use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; use rand_core::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -64,8 +64,9 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - make_static!(PacketQueue::<16, 16>::new()), + PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, p.PA1, @@ -89,11 +90,13 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index b2758cba0..8789e4e0b 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -18,7 +18,7 @@ use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; use rand_core::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -67,8 +67,9 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - make_static!(PacketQueue::<4, 4>::new()), + PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, p.PA1, @@ -92,11 +93,13 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index dbddfc22f..a64b3253a 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -14,7 +14,7 @@ use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; use rand_core::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -64,8 +64,9 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - make_static!(PacketQueue::<16, 16>::new()), + PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, p.PA1, @@ -89,11 +90,13 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<3>::new()), - seed + RESOURCES.init(StackResources::<3>::new()), + seed, )); // Launch network task diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 17e1d9fb7..8e84d9964 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -15,7 +15,7 @@ use embassy_time::Timer; use embedded_io_async::Write; use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; use rand_core::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -65,8 +65,9 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - make_static!(PacketQueue::<16, 16>::new()), + PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, p.PA1, @@ -90,11 +91,13 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<3>::new()), - seed + RESOURCES.init(StackResources::<3>::new()), + seed, )); // Launch network task diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 8ec810c7f..eb04fe5e6 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -36,7 +36,7 @@ use hal::rng::{self, Rng}; use hal::{bind_interrupts, exti, pac, peripherals}; use heapless::Vec; use rand::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {embassy_stm32 as hal, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -180,7 +180,8 @@ async fn main(spawner: Spawner) { } }; - let state = make_static!(embassy_net_adin1110::State::<8, 8>::new()); + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(embassy_net_adin1110::State::<8, 8>::new()); let (device, runner) = embassy_net_adin1110::new( MAC, @@ -217,11 +218,13 @@ async fn main(spawner: Spawner) { }; // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, ip_cfg, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 0b0a0e2db..214235bd5 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -15,7 +15,7 @@ use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; use embedded_io_async::Write; use rand_core::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>; @@ -76,14 +76,18 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; // Create embassy-usb DeviceBuilder using the driver and config. + static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); + static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); let mut builder = Builder::new( driver, config, - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], - &mut make_static!([0; 256])[..], + &mut DEVICE_DESC.init([0; 256])[..], + &mut CONFIG_DESC.init([0; 256])[..], + &mut BOS_DESC.init([0; 256])[..], &mut [], // no msos descriptors - &mut make_static!([0; 128])[..], + &mut CONTROL_BUF.init([0; 128])[..], ); // Our MAC addr. @@ -92,14 +96,16 @@ async fn main(spawner: Spawner) { let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; // Create classes on the builder. - let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); + static STATE: StaticCell = StaticCell::new(); + let class = CdcNcmClass::new(&mut builder, STATE.init(State::new()), host_mac_addr, 64); // Build the builder. let usb = builder.build(); unwrap!(spawner.spawn(usb_task(usb))); - let (runner, device) = class.into_embassy_net_device::(make_static!(NetState::new()), our_mac_addr); + static NET_STATE: StaticCell> = StaticCell::new(); + let (runner, device) = class.into_embassy_net_device::(NET_STATE.init(NetState::new()), our_mac_addr); unwrap!(spawner.spawn(usb_ncm_task(runner))); let config = embassy_net::Config::dhcpv4(Default::default()); @@ -114,11 +120,13 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index f8c76b5a4..454530c03 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -12,7 +12,7 @@ use embassy_stm32_wpan::mac::typedefs::{MacChannel, PanId, PibId}; use embassy_stm32_wpan::mac::{self, Runner}; use embassy_stm32_wpan::sub::mm; use embassy_stm32_wpan::TlMbox; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ @@ -154,15 +154,21 @@ async fn main(spawner: Spawner) { .unwrap(); defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); + static TX1: StaticCell<[u8; 127]> = StaticCell::new(); + static TX2: StaticCell<[u8; 127]> = StaticCell::new(); + static TX3: StaticCell<[u8; 127]> = StaticCell::new(); + static TX4: StaticCell<[u8; 127]> = StaticCell::new(); + static TX5: StaticCell<[u8; 127]> = StaticCell::new(); let tx_queue = [ - make_static!([0u8; 127]), - make_static!([0u8; 127]), - make_static!([0u8; 127]), - make_static!([0u8; 127]), - make_static!([0u8; 127]), + TX1.init([0u8; 127]), + TX2.init([0u8; 127]), + TX3.init([0u8; 127]), + TX4.init([0u8; 127]), + TX5.init([0u8; 127]), ]; - let runner = make_static!(Runner::new(mbox.mac_subsystem, tx_queue)); + static RUNNER: StaticCell = StaticCell::new(); + let runner = RUNNER.init(Runner::new(mbox.mac_subsystem, tx_queue)); spawner.spawn(run_mac(runner)).unwrap(); diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs index 60d30a2ff..c26c0d066 100644 --- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs @@ -14,7 +14,7 @@ use embassy_nrf::spim::{self, Spim}; use embassy_nrf::{bind_interrupts, peripherals}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -68,11 +68,13 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index 9eee39ccf..5b43b75d7 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -13,7 +13,7 @@ use embassy_nrf::spim::{self, Spim}; use embassy_nrf::{bind_interrupts, peripherals}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -64,8 +64,9 @@ async fn main(spawner: Spawner) { let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); let spi = ExclusiveDevice::new(spi, cs, Delay); + static STATE: StaticCell = StaticCell::new(); let (device, mut control, runner) = embassy_net_esp_hosted::new( - make_static!(embassy_net_esp_hosted::State::new()), + STATE.init(embassy_net_esp_hosted::State::new()), spi, handshake, ready, @@ -85,11 +86,13 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, Config::dhcpv4(Default::default()), - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index de29c06dd..d70ef8ef3 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -11,7 +11,7 @@ use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::{bind_interrupts, rom_data}; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -58,7 +58,8 @@ async fn main(spawner: Spawner) { let mut pio = Pio::new(p.PIO0, Irqs); let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); - let state = make_static!(cyw43::State::new()); + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; unwrap!(spawner.spawn(wifi_task(runner))); @@ -71,11 +72,13 @@ async fn main(spawner: Spawner) { let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( net_device, Config::dhcpv4(Default::default()), - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); unwrap!(spawner.spawn(net_task(stack))); diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs index a4d253b3c..5588b6427 100644 --- a/tests/rp/src/bin/ethernet_w5100s_perf.rs +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs @@ -16,7 +16,7 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use rand::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] @@ -51,7 +51,8 @@ async fn main(spawner: Spawner) { let w5500_reset = Output::new(p.PIN_20, Level::High); let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; - let state = make_static!(State::<8, 8>::new()); + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); let (device, runner) = embassy_net_wiznet::new( mac_addr, state, @@ -66,11 +67,13 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell>> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index 754354944..c01f33a97 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -14,7 +14,7 @@ use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng}; use rand_core::RngCore; -use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; teleprobe_meta::timeout!(120); @@ -71,8 +71,9 @@ async fn main(spawner: Spawner) { #[cfg(not(feature = "stm32f207zg"))] const PACKET_QUEUE_SIZE: usize = 4; + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - make_static!(PacketQueue::::new()), + PACKETS.init(PacketQueue::::new()), p.ETH, Irqs, p.PA1, @@ -99,11 +100,13 @@ async fn main(spawner: Spawner) { //}); // Init network stack - let stack = &*make_static!(Stack::new( + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( device, config, - make_static!(StackResources::<2>::new()), - seed + RESOURCES.init(StackResources::<2>::new()), + seed, )); // Launch network task diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index b9810673a..f8e3c43d7 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -15,7 +15,7 @@ use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; use embassy_time::Timer; -use static_cell::make_static; +use static_cell::StaticCell; #[entry] fn main() -> ! { @@ -64,7 +64,8 @@ async fn async_main(spawner: Spawner) { rtc.set_datetime(now.into()).expect("datetime not set"); - let rtc = make_static!(rtc); + static RTC: StaticCell = StaticCell::new(); + let rtc = RTC.init(rtc); stop_with_rtc(rtc); From cf0e5e32add134aefb8ffc1bfac9f49f48bdc9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 21 Dec 2023 14:22:56 +0100 Subject: [PATCH 096/760] Remove Xtensa specifier --- docs/modules/ROOT/pages/faq.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index d1a012978..1fe9bde37 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -35,7 +35,7 @@ For Cortex-M targets, consider making sure that ALL of the following features ar * `executor-thread` * `nightly` -For Xtensa ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate]. +For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate]. == Why is my binary so big? From 8b36a32ed5d834b23e970d5b723dd7df1f1c94a2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 21 Dec 2023 14:57:49 +0100 Subject: [PATCH 097/760] ci: use beta, add secondary nightly ci. --- .../ci/{build-stable.sh => build-nightly.sh} | 5 +- .github/ci/rustfmt.sh | 12 +++ .github/ci/test-nightly.sh | 13 ++++ .github/ci/test.sh | 3 - .vscode/settings.json | 8 +- ci-nightly.sh | 30 ++++++++ ci.sh | 37 ++++----- ci_stable.sh | 77 ------------------- docs/modules/ROOT/examples/basic/src/main.rs | 1 - .../layer-by-layer/blinky-async/Cargo.toml | 2 +- .../layer-by-layer/blinky-async/src/main.rs | 1 - embassy-executor/Cargo.toml | 4 +- embassy-rp/Cargo.toml | 2 +- embassy-rp/src/lib.rs | 1 - embassy-rp/src/multicore.rs | 1 - embassy-stm32-wpan/Cargo.toml | 2 +- embassy-time/src/timer.rs | 7 -- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/nrf/src/bin/a.rs | 1 - examples/boot/application/nrf/src/bin/b.rs | 1 - examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/rp/src/bin/a.rs | 1 - examples/boot/application/rp/src/bin/b.rs | 1 - examples/boot/application/stm32f3/Cargo.toml | 2 +- .../boot/application/stm32f3/src/bin/a.rs | 1 - .../boot/application/stm32f3/src/bin/b.rs | 1 - examples/boot/application/stm32f7/Cargo.toml | 2 +- .../boot/application/stm32f7/src/bin/a.rs | 1 - .../boot/application/stm32f7/src/bin/b.rs | 1 - examples/boot/application/stm32h7/Cargo.toml | 2 +- .../boot/application/stm32h7/src/bin/a.rs | 1 - .../boot/application/stm32h7/src/bin/b.rs | 1 - examples/boot/application/stm32l0/Cargo.toml | 2 +- .../boot/application/stm32l0/src/bin/a.rs | 1 - .../boot/application/stm32l0/src/bin/b.rs | 1 - examples/boot/application/stm32l1/Cargo.toml | 2 +- .../boot/application/stm32l1/src/bin/a.rs | 1 - .../boot/application/stm32l1/src/bin/b.rs | 1 - examples/boot/application/stm32l4/Cargo.toml | 2 +- .../boot/application/stm32l4/src/bin/a.rs | 1 - .../boot/application/stm32l4/src/bin/b.rs | 1 - .../boot/application/stm32wb-dfu/Cargo.toml | 2 +- .../boot/application/stm32wb-dfu/src/main.rs | 1 - examples/boot/application/stm32wl/Cargo.toml | 2 +- .../boot/application/stm32wl/src/bin/a.rs | 1 - .../boot/application/stm32wl/src/bin/b.rs | 1 - examples/nrf-rtos-trace/src/bin/rtos_trace.rs | 1 - examples/nrf52840/Cargo.toml | 6 -- examples/nrf52840/src/bin/blinky.rs | 1 - examples/nrf52840/src/bin/buffered_uart.rs | 1 - examples/nrf52840/src/bin/channel.rs | 1 - .../src/bin/channel_sender_receiver.rs | 1 - .../nrf52840/src/bin/ethernet_enc28j60.rs | 1 - .../src/bin/executor_fairness_test.rs | 1 - examples/nrf52840/src/bin/gpiote_channel.rs | 1 - examples/nrf52840/src/bin/gpiote_port.rs | 1 - examples/nrf52840/src/bin/i2s_effect.rs | 1 - examples/nrf52840/src/bin/i2s_monitor.rs | 1 - examples/nrf52840/src/bin/i2s_waveform.rs | 1 - .../src/bin/manually_create_executor.rs | 1 - examples/nrf52840/src/bin/multiprio.rs | 1 - examples/nrf52840/src/bin/mutex.rs | 1 - examples/nrf52840/src/bin/nvmc.rs | 1 - examples/nrf52840/src/bin/pdm.rs | 1 - examples/nrf52840/src/bin/pdm_continuous.rs | 1 - examples/nrf52840/src/bin/ppi.rs | 1 - examples/nrf52840/src/bin/pubsub.rs | 1 - examples/nrf52840/src/bin/pwm.rs | 1 - .../nrf52840/src/bin/pwm_double_sequence.rs | 1 - examples/nrf52840/src/bin/pwm_sequence.rs | 1 - examples/nrf52840/src/bin/pwm_sequence_ppi.rs | 1 - .../nrf52840/src/bin/pwm_sequence_ws2812b.rs | 1 - examples/nrf52840/src/bin/pwm_servo.rs | 1 - examples/nrf52840/src/bin/qdec.rs | 1 - examples/nrf52840/src/bin/qspi.rs | 1 - examples/nrf52840/src/bin/qspi_lowpower.rs | 1 - examples/nrf52840/src/bin/rng.rs | 1 - examples/nrf52840/src/bin/saadc.rs | 1 - examples/nrf52840/src/bin/saadc_continuous.rs | 1 - examples/nrf52840/src/bin/self_spawn.rs | 1 - .../src/bin/self_spawn_current_executor.rs | 1 - examples/nrf52840/src/bin/spim.rs | 1 - examples/nrf52840/src/bin/spis.rs | 1 - examples/nrf52840/src/bin/temp.rs | 1 - examples/nrf52840/src/bin/timer.rs | 1 - examples/nrf52840/src/bin/twim.rs | 1 - examples/nrf52840/src/bin/twim_lowpower.rs | 1 - examples/nrf52840/src/bin/twis.rs | 1 - examples/nrf52840/src/bin/uart.rs | 1 - examples/nrf52840/src/bin/uart_idle.rs | 1 - examples/nrf52840/src/bin/uart_split.rs | 1 - examples/nrf52840/src/bin/usb_ethernet.rs | 1 - examples/nrf52840/src/bin/usb_hid_keyboard.rs | 1 - examples/nrf52840/src/bin/usb_hid_mouse.rs | 1 - examples/nrf52840/src/bin/usb_serial.rs | 1 - .../nrf52840/src/bin/usb_serial_multitask.rs | 1 - .../nrf52840/src/bin/usb_serial_winusb.rs | 1 - examples/nrf52840/src/bin/wdt.rs | 1 - examples/nrf52840/src/bin/wifi_esp_hosted.rs | 1 - examples/nrf5340/Cargo.toml | 4 +- examples/nrf5340/src/bin/blinky.rs | 1 - examples/nrf5340/src/bin/gpiote_channel.rs | 1 - examples/nrf5340/src/bin/uart.rs | 1 - examples/rp/Cargo.toml | 4 +- examples/rp/src/bin/adc.rs | 1 - examples/rp/src/bin/blinky.rs | 1 - examples/rp/src/bin/button.rs | 1 - .../rp/src/bin/ethernet_w5500_multisocket.rs | 1 - .../rp/src/bin/ethernet_w5500_tcp_client.rs | 1 - .../rp/src/bin/ethernet_w5500_tcp_server.rs | 1 - examples/rp/src/bin/ethernet_w5500_udp.rs | 1 - examples/rp/src/bin/flash.rs | 1 - examples/rp/src/bin/gpio_async.rs | 1 - examples/rp/src/bin/gpout.rs | 1 - examples/rp/src/bin/i2c_async.rs | 1 - examples/rp/src/bin/i2c_blocking.rs | 1 - examples/rp/src/bin/i2c_slave.rs | 1 - examples/rp/src/bin/multicore.rs | 1 - examples/rp/src/bin/multiprio.rs | 1 - examples/rp/src/bin/pio_async.rs | 1 - examples/rp/src/bin/pio_dma.rs | 1 - examples/rp/src/bin/pio_hd44780.rs | 1 - examples/rp/src/bin/pio_rotary_encoder.rs | 1 - examples/rp/src/bin/pio_stepper.rs | 1 - examples/rp/src/bin/pio_uart.rs | 1 - examples/rp/src/bin/pio_ws2812.rs | 1 - examples/rp/src/bin/pwm.rs | 1 - examples/rp/src/bin/pwm_input.rs | 1 - examples/rp/src/bin/rosc.rs | 1 - examples/rp/src/bin/rtc.rs | 1 - examples/rp/src/bin/spi.rs | 1 - examples/rp/src/bin/spi_async.rs | 1 - examples/rp/src/bin/spi_display.rs | 1 - examples/rp/src/bin/uart.rs | 1 - examples/rp/src/bin/uart_buffered_split.rs | 1 - examples/rp/src/bin/uart_unidir.rs | 1 - examples/rp/src/bin/usb_ethernet.rs | 1 - examples/rp/src/bin/usb_hid_keyboard.rs | 1 - examples/rp/src/bin/usb_logger.rs | 1 - examples/rp/src/bin/usb_midi.rs | 1 - examples/rp/src/bin/usb_raw.rs | 1 - examples/rp/src/bin/usb_raw_bulk.rs | 1 - examples/rp/src/bin/usb_serial.rs | 1 - examples/rp/src/bin/watchdog.rs | 1 - examples/rp/src/bin/wifi_ap_tcp_server.rs | 1 - examples/rp/src/bin/wifi_blinky.rs | 1 - examples/rp/src/bin/wifi_scan.rs | 1 - examples/rp/src/bin/wifi_tcp_server.rs | 1 - examples/std/Cargo.toml | 4 +- examples/std/src/bin/net.rs | 2 - examples/std/src/bin/net_dns.rs | 2 - examples/std/src/bin/net_ppp.rs | 1 - examples/std/src/bin/net_udp.rs | 2 - examples/std/src/bin/serial.rs | 2 - examples/std/src/bin/tcp_accept.rs | 2 - examples/std/src/bin/tick.rs | 2 - examples/stm32c0/Cargo.toml | 2 +- examples/stm32c0/src/bin/blinky.rs | 1 - examples/stm32c0/src/bin/button.rs | 1 - examples/stm32c0/src/bin/button_exti.rs | 1 - examples/stm32f0/Cargo.toml | 4 +- examples/stm32f0/src/bin/adc.rs | 1 - examples/stm32f0/src/bin/blinky.rs | 1 - .../src/bin/button_controlled_blink.rs | 1 - examples/stm32f0/src/bin/button_exti.rs | 1 - examples/stm32f0/src/bin/hello.rs | 1 - examples/stm32f0/src/bin/multiprio.rs | 1 - examples/stm32f0/src/bin/wdg.rs | 1 - examples/stm32f1/Cargo.toml | 2 +- examples/stm32f1/src/bin/adc.rs | 1 - examples/stm32f1/src/bin/blinky.rs | 1 - examples/stm32f1/src/bin/can.rs | 1 - examples/stm32f1/src/bin/hello.rs | 1 - examples/stm32f1/src/bin/usb_serial.rs | 1 - examples/stm32f2/Cargo.toml | 2 +- examples/stm32f2/src/bin/blinky.rs | 1 - examples/stm32f2/src/bin/pll.rs | 1 - examples/stm32f3/Cargo.toml | 4 +- examples/stm32f3/src/bin/blinky.rs | 1 - examples/stm32f3/src/bin/button.rs | 1 - examples/stm32f3/src/bin/button_events.rs | 1 - examples/stm32f3/src/bin/button_exti.rs | 1 - examples/stm32f3/src/bin/flash.rs | 1 - examples/stm32f3/src/bin/hello.rs | 1 - examples/stm32f3/src/bin/multiprio.rs | 1 - examples/stm32f3/src/bin/spi_dma.rs | 1 - examples/stm32f3/src/bin/usart_dma.rs | 1 - examples/stm32f3/src/bin/usb_serial.rs | 1 - examples/stm32f334/Cargo.toml | 4 +- examples/stm32f334/src/bin/adc.rs | 1 - examples/stm32f334/src/bin/button.rs | 1 - examples/stm32f334/src/bin/hello.rs | 1 - examples/stm32f334/src/bin/opamp.rs | 1 - examples/stm32f334/src/bin/pwm.rs | 1 - examples/stm32f4/Cargo.toml | 4 +- examples/stm32f4/src/bin/adc.rs | 1 - examples/stm32f4/src/bin/blinky.rs | 1 - examples/stm32f4/src/bin/button.rs | 1 - examples/stm32f4/src/bin/button_exti.rs | 1 - examples/stm32f4/src/bin/can.rs | 1 - examples/stm32f4/src/bin/dac.rs | 1 - examples/stm32f4/src/bin/eth.rs | 1 - examples/stm32f4/src/bin/flash.rs | 1 - examples/stm32f4/src/bin/flash_async.rs | 1 - examples/stm32f4/src/bin/hello.rs | 1 - examples/stm32f4/src/bin/i2c.rs | 1 - examples/stm32f4/src/bin/i2c_async.rs | 1 - examples/stm32f4/src/bin/i2c_comparison.rs | 1 - examples/stm32f4/src/bin/i2s_dma.rs | 1 - examples/stm32f4/src/bin/mco.rs | 1 - examples/stm32f4/src/bin/multiprio.rs | 1 - examples/stm32f4/src/bin/pwm.rs | 1 - examples/stm32f4/src/bin/pwm_complementary.rs | 1 - examples/stm32f4/src/bin/rtc.rs | 1 - examples/stm32f4/src/bin/sdmmc.rs | 1 - examples/stm32f4/src/bin/spi.rs | 1 - examples/stm32f4/src/bin/spi_dma.rs | 1 - examples/stm32f4/src/bin/usart.rs | 1 - examples/stm32f4/src/bin/usart_buffered.rs | 1 - examples/stm32f4/src/bin/usart_dma.rs | 1 - examples/stm32f4/src/bin/usb_ethernet.rs | 1 - examples/stm32f4/src/bin/usb_raw.rs | 1 - examples/stm32f4/src/bin/usb_serial.rs | 1 - examples/stm32f4/src/bin/wdt.rs | 1 - examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 1 - examples/stm32f7/Cargo.toml | 4 +- examples/stm32f7/src/bin/adc.rs | 1 - examples/stm32f7/src/bin/blinky.rs | 1 - examples/stm32f7/src/bin/button.rs | 1 - examples/stm32f7/src/bin/button_exti.rs | 1 - examples/stm32f7/src/bin/can.rs | 1 - examples/stm32f7/src/bin/eth.rs | 1 - examples/stm32f7/src/bin/flash.rs | 1 - examples/stm32f7/src/bin/hello.rs | 1 - examples/stm32f7/src/bin/sdmmc.rs | 1 - examples/stm32f7/src/bin/usart_dma.rs | 1 - examples/stm32f7/src/bin/usb_serial.rs | 1 - examples/stm32g0/Cargo.toml | 2 +- examples/stm32g0/src/bin/blinky.rs | 1 - examples/stm32g0/src/bin/button.rs | 1 - examples/stm32g0/src/bin/button_exti.rs | 1 - examples/stm32g0/src/bin/flash.rs | 1 - examples/stm32g0/src/bin/spi_neopixel.rs | 1 - examples/stm32g4/Cargo.toml | 2 +- examples/stm32g4/src/bin/adc.rs | 1 - examples/stm32g4/src/bin/blinky.rs | 1 - examples/stm32g4/src/bin/button.rs | 1 - examples/stm32g4/src/bin/button_exti.rs | 1 - examples/stm32g4/src/bin/pll.rs | 1 - examples/stm32g4/src/bin/pwm.rs | 1 - examples/stm32g4/src/bin/usb_serial.rs | 1 - examples/stm32h5/Cargo.toml | 4 +- examples/stm32h5/src/bin/blinky.rs | 1 - examples/stm32h5/src/bin/button_exti.rs | 1 - examples/stm32h5/src/bin/eth.rs | 1 - examples/stm32h5/src/bin/i2c.rs | 1 - examples/stm32h5/src/bin/rng.rs | 1 - examples/stm32h5/src/bin/usart.rs | 1 - examples/stm32h5/src/bin/usart_dma.rs | 1 - examples/stm32h5/src/bin/usart_split.rs | 1 - examples/stm32h5/src/bin/usb_serial.rs | 1 - examples/stm32h7/Cargo.toml | 4 +- examples/stm32h7/src/bin/adc.rs | 1 - examples/stm32h7/src/bin/blinky.rs | 1 - examples/stm32h7/src/bin/button_exti.rs | 1 - examples/stm32h7/src/bin/camera.rs | 1 - examples/stm32h7/src/bin/dac.rs | 1 - examples/stm32h7/src/bin/dac_dma.rs | 1 - examples/stm32h7/src/bin/eth.rs | 1 - examples/stm32h7/src/bin/eth_client.rs | 1 - examples/stm32h7/src/bin/flash.rs | 1 - examples/stm32h7/src/bin/fmc.rs | 1 - examples/stm32h7/src/bin/i2c.rs | 1 - .../stm32h7/src/bin/low_level_timer_api.rs | 1 - examples/stm32h7/src/bin/mco.rs | 1 - examples/stm32h7/src/bin/pwm.rs | 1 - examples/stm32h7/src/bin/rng.rs | 1 - examples/stm32h7/src/bin/rtc.rs | 1 - examples/stm32h7/src/bin/sdmmc.rs | 1 - examples/stm32h7/src/bin/signal.rs | 1 - examples/stm32h7/src/bin/spi.rs | 1 - examples/stm32h7/src/bin/spi_dma.rs | 1 - examples/stm32h7/src/bin/usart.rs | 1 - examples/stm32h7/src/bin/usart_dma.rs | 1 - examples/stm32h7/src/bin/usart_split.rs | 1 - examples/stm32h7/src/bin/usb_serial.rs | 1 - examples/stm32h7/src/bin/wdg.rs | 1 - examples/stm32l0/Cargo.toml | 4 - examples/stm32l0/src/bin/blinky.rs | 1 - examples/stm32l0/src/bin/button.rs | 1 - examples/stm32l0/src/bin/button_exti.rs | 1 - examples/stm32l0/src/bin/flash.rs | 1 - examples/stm32l0/src/bin/spi.rs | 1 - examples/stm32l0/src/bin/usart_dma.rs | 1 - examples/stm32l0/src/bin/usart_irq.rs | 1 - examples/stm32l1/Cargo.toml | 2 +- examples/stm32l1/src/bin/blinky.rs | 1 - examples/stm32l1/src/bin/flash.rs | 1 - examples/stm32l1/src/bin/spi.rs | 1 - examples/stm32l4/Cargo.toml | 4 +- examples/stm32l4/src/bin/adc.rs | 1 - examples/stm32l4/src/bin/blinky.rs | 1 - examples/stm32l4/src/bin/button.rs | 1 - examples/stm32l4/src/bin/button_exti.rs | 1 - examples/stm32l4/src/bin/dac.rs | 1 - examples/stm32l4/src/bin/dac_dma.rs | 1 - examples/stm32l4/src/bin/i2c.rs | 1 - .../stm32l4/src/bin/i2c_blocking_async.rs | 1 - examples/stm32l4/src/bin/i2c_dma.rs | 1 - examples/stm32l4/src/bin/mco.rs | 1 - examples/stm32l4/src/bin/rng.rs | 1 - examples/stm32l4/src/bin/rtc.rs | 1 - .../src/bin/spe_adin1110_http_server.rs | 7 +- examples/stm32l4/src/bin/spi.rs | 1 - .../stm32l4/src/bin/spi_blocking_async.rs | 1 - examples/stm32l4/src/bin/spi_dma.rs | 1 - examples/stm32l4/src/bin/usart.rs | 1 - examples/stm32l4/src/bin/usart_dma.rs | 1 - examples/stm32l4/src/bin/usb_serial.rs | 1 - examples/stm32l5/Cargo.toml | 4 +- examples/stm32l5/src/bin/button_exti.rs | 1 - examples/stm32l5/src/bin/rng.rs | 1 - examples/stm32l5/src/bin/usb_ethernet.rs | 1 - examples/stm32l5/src/bin/usb_hid_mouse.rs | 1 - examples/stm32l5/src/bin/usb_serial.rs | 1 - examples/stm32u5/Cargo.toml | 2 +- examples/stm32u5/src/bin/blinky.rs | 1 - examples/stm32u5/src/bin/boot.rs | 1 - examples/stm32u5/src/bin/usb_serial.rs | 1 - examples/stm32wb/Cargo.toml | 4 +- examples/stm32wb/src/bin/blinky.rs | 1 - examples/stm32wb/src/bin/button_exti.rs | 1 - examples/stm32wb/src/bin/eddystone_beacon.rs | 1 - examples/stm32wb/src/bin/gatt_server.rs | 1 - examples/stm32wb/src/bin/mac_ffd.rs | 1 - examples/stm32wb/src/bin/mac_ffd_net.rs | 1 - examples/stm32wb/src/bin/mac_rfd.rs | 1 - examples/stm32wb/src/bin/tl_mbox.rs | 1 - examples/stm32wb/src/bin/tl_mbox_ble.rs | 1 - examples/stm32wb/src/bin/tl_mbox_mac.rs | 1 - examples/stm32wba/Cargo.toml | 4 +- examples/stm32wba/src/bin/blinky.rs | 1 - examples/stm32wba/src/bin/button_exti.rs | 1 - examples/stm32wl/Cargo.toml | 2 +- examples/stm32wl/src/bin/blinky.rs | 1 - examples/stm32wl/src/bin/button.rs | 1 - examples/stm32wl/src/bin/button_exti.rs | 1 - examples/stm32wl/src/bin/flash.rs | 1 - examples/stm32wl/src/bin/random.rs | 1 - examples/stm32wl/src/bin/rtc.rs | 1 - examples/stm32wl/src/bin/uart_async.rs | 1 - examples/wasm/Cargo.toml | 2 +- examples/wasm/src/lib.rs | 2 - rust-toolchain-nightly.toml | 12 +++ rust-toolchain.toml | 8 +- tests/nrf/Cargo.toml | 2 +- tests/nrf/src/bin/ethernet_enc28j60_perf.rs | 1 - tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 1 - tests/rp/Cargo.toml | 2 +- tests/rp/src/bin/cyw43-perf.rs | 1 - tests/rp/src/bin/ethernet_w5100s_perf.rs | 1 - tests/stm32/Cargo.toml | 2 +- tests/stm32/src/bin/eth.rs | 1 - tests/stm32/src/bin/stop.rs | 1 - 364 files changed, 148 insertions(+), 508 deletions(-) rename .github/ci/{build-stable.sh => build-nightly.sh} (90%) create mode 100755 .github/ci/rustfmt.sh create mode 100755 .github/ci/test-nightly.sh create mode 100755 ci-nightly.sh delete mode 100755 ci_stable.sh create mode 100644 rust-toolchain-nightly.toml diff --git a/.github/ci/build-stable.sh b/.github/ci/build-nightly.sh similarity index 90% rename from .github/ci/build-stable.sh rename to .github/ci/build-nightly.sh index e0bd77867..95cb4100c 100755 --- a/.github/ci/build-stable.sh +++ b/.github/ci/build-nightly.sh @@ -7,6 +7,7 @@ set -euo pipefail export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target +mv rust-toolchain-nightly.toml rust-toolchain.toml # needed for "dumb HTTP" transport support # used when pointing stm32-metapac to a CI-built one. @@ -21,9 +22,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -sed -i 's/channel.*/channel = "beta"/g' rust-toolchain.toml - -./ci_stable.sh +./ci-nightly.sh # Save lockfiles echo Saving lockfiles... diff --git a/.github/ci/rustfmt.sh b/.github/ci/rustfmt.sh new file mode 100755 index 000000000..369239cfe --- /dev/null +++ b/.github/ci/rustfmt.sh @@ -0,0 +1,12 @@ +#!/bin/bash +## on push branch~=gh-readonly-queue/main/.* +## on pull_request + +set -euo pipefail + +export RUSTUP_HOME=/ci/cache/rustup +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 diff --git a/.github/ci/test-nightly.sh b/.github/ci/test-nightly.sh new file mode 100755 index 000000000..d6e5dc574 --- /dev/null +++ b/.github/ci/test-nightly.sh @@ -0,0 +1,13 @@ +#!/bin/bash +## on push branch~=gh-readonly-queue/main/.* +## on pull_request + +set -euo pipefail + +export RUSTUP_HOME=/ci/cache/rustup +export CARGO_HOME=/ci/cache/cargo +export CARGO_TARGET_DIR=/ci/cache/target +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 diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 0ec65d2a1..369f6d221 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -8,9 +8,6 @@ export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target -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 - 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 diff --git a/.vscode/settings.json b/.vscode/settings.json index d46ce603b..a5b23175a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,14 +15,10 @@ //"rust-analyzer.cargo.target": "thumbv7m-none-eabi", "rust-analyzer.cargo.target": "thumbv7em-none-eabi", //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", - "rust-analyzer.cargo.features": [ - // Uncomment if the example has a "nightly" feature. - "nightly", - ], "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. - "examples/nrf52840/Cargo.toml", + "examples/stm32l4/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", @@ -49,4 +45,4 @@ // "examples/stm32wl/Cargo.toml", // "examples/wasm/Cargo.toml", ], -} \ No newline at end of file +} diff --git a/ci-nightly.sh b/ci-nightly.sh new file mode 100755 index 000000000..1fc9692b5 --- /dev/null +++ b/ci-nightly.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -eo pipefail + +export RUSTFLAGS=-Dwarnings +export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info +if [[ -z "${CARGO_TARGET_DIR}" ]]; then + export CARGO_TARGET_DIR=target_ci +fi + +cargo batch \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \ + --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \ + diff --git a/ci.sh b/ci.sh index e3918783f..933e54a80 100755 --- a/ci.sh +++ b/ci.sh @@ -15,26 +15,24 @@ if [ $TARGET = "x86_64-unknown-linux-gnu" ]; then BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std" fi -find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021 - cargo batch \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ @@ -140,7 +138,6 @@ cargo batch \ --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ - --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \ --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ diff --git a/ci_stable.sh b/ci_stable.sh deleted file mode 100755 index 66ed8f79d..000000000 --- a/ci_stable.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -export RUSTFLAGS=-Dwarnings -export DEFMT_LOG=trace - -cargo batch \ - --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ - --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ - --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi \ - --- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \ - --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ - --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ - --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,log,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,defmt,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features defmt \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features log \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features qspi-as-gpio \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf52840 --bin raw_spawn \ - --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \ diff --git a/docs/modules/ROOT/examples/basic/src/main.rs b/docs/modules/ROOT/examples/basic/src/main.rs index 04170db55..2a4ee5968 100644 --- a/docs/modules/ROOT/examples/basic/src/main.rs +++ b/docs/modules/ROOT/examples/basic/src/main.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml index dcdb71e7b..2d47dccf4 100644 --- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" cortex-m = "0.7" cortex-m-rt = "0.7" embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } -embassy-executor = { version = "0.4.0", features = ["nightly", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.4.0", features = ["arch-cortex-m", "executor-thread"] } defmt = "0.3.0" defmt-rtt = "0.3.0" diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs index 8df632240..e6753be28 100644 --- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs +++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index ec5aca46d..4dcd03b0f 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -14,7 +14,7 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" -features = ["nightly", "defmt"] +features = ["defmt"] flavors = [ { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] }, { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] }, @@ -25,7 +25,7 @@ flavors = [ [package.metadata.docs.rs] default-target = "thumbv7em-none-eabi" targets = ["thumbv7em-none-eabi"] -features = ["nightly", "defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"] +features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"] [dependencies] defmt = { version = "0.3", optional = true } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index c557940b1..93dad68ce 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -87,5 +87,5 @@ pio = {version= "0.2.1" } rp2040-boot2 = "0.3" [dev-dependencies] -embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] } +embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 004b94589..fdacf4965 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -247,7 +247,6 @@ select_bootloader! { /// # Usage /// /// ```no_run -/// #![feature(type_alias_impl_trait)] /// use embassy_rp::install_core0_stack_guard; /// use embassy_executor::{Executor, Spawner}; /// diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 915761801..252f30dc1 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -11,7 +11,6 @@ //! # Usage //! //! ```no_run -//! # #![feature(type_alias_impl_trait)] //! use embassy_rp::multicore::Stack; //! use static_cell::StaticCell; //! use embassy_executor::Executor; diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index f887b8171..1780688cd 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -26,7 +26,7 @@ aligned = "0.4.1" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } -stm32wb-hci = { version = "0.1.4", optional = true } +stm32wb-hci = { git = "https://github.com/Dirbaio/stm32wb-hci", rev = "0aff47e009c30c5fc5d520672625173d75f7505c", optional = true } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } bitflags = { version = "2.3.3", optional = true } diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 574d715da..2705ba03f 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -47,9 +47,6 @@ impl Timer { /// /// Example: /// ``` no_run - /// # #![feature(type_alias_impl_trait)] - /// # - /// # fn foo() {} /// use embassy_time::{Duration, Timer}; /// /// #[embassy_executor::task] @@ -132,8 +129,6 @@ impl Future for Timer { /// /// For instance, consider the following code fragment. /// ``` no_run -/// # #![feature(type_alias_impl_trait)] -/// # /// use embassy_time::{Duration, Timer}; /// # fn foo() {} /// @@ -152,8 +147,6 @@ impl Future for Timer { /// Example using ticker, which will consistently call `foo` once a second. /// /// ``` no_run -/// # #![feature(type_alias_impl_trait)] -/// # /// use embassy_time::{Duration, Ticker}; /// # fn foo(){} /// diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 5f11750b2..b52bac650 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] } diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 8b510ed35..f3abfddbc 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] #![macro_use] -#![feature(type_alias_impl_trait)] use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; use embassy_embedded_hal::adapter::BlockingAsync; diff --git a/examples/boot/application/nrf/src/bin/b.rs b/examples/boot/application/nrf/src/bin/b.rs index a88c3c56c..de97b6a22 100644 --- a/examples/boot/application/nrf/src/bin/b.rs +++ b/examples/boot/application/nrf/src/bin/b.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] #![macro_use] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_nrf::gpio::{Level, Output, OutputDrive}; diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 89ac5a8f6..08ce16877 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] } diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs index 6fd5d7f60..3f0bf90e2 100644 --- a/examples/boot/application/rp/src/bin/a.rs +++ b/examples/boot/application/rp/src/bin/a.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::cell::RefCell; diff --git a/examples/boot/application/rp/src/bin/b.rs b/examples/boot/application/rp/src/bin/b.rs index 1eca5b4a2..a46d095bf 100644 --- a/examples/boot/application/rp/src/bin/b.rs +++ b/examples/boot/application/rp/src/bin/b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_rp::gpio; diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 1a0f8cee5..248ec6dce 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs index 8be39bfb7..96ae5c47b 100644 --- a/examples/boot/application/stm32f3/src/bin/a.rs +++ b/examples/boot/application/stm32f3/src/bin/a.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32f3/src/bin/b.rs b/examples/boot/application/stm32f3/src/bin/b.rs index 8411f384c..22ba82d5e 100644 --- a/examples/boot/application/stm32f3/src/bin/b.rs +++ b/examples/boot/application/stm32f3/src/bin/b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index e42d1d421..aa5f87615 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs index 0c3819bed..a6107386a 100644 --- a/examples/boot/application/stm32f7/src/bin/a.rs +++ b/examples/boot/application/stm32f7/src/bin/a.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::cell::RefCell; diff --git a/examples/boot/application/stm32f7/src/bin/b.rs b/examples/boot/application/stm32f7/src/bin/b.rs index 4c2ad06a2..190477204 100644 --- a/examples/boot/application/stm32f7/src/bin/b.rs +++ b/examples/boot/application/stm32f7/src/bin/b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 8450d8639..78e33de28 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs index f239e3732..b73506cf3 100644 --- a/examples/boot/application/stm32h7/src/bin/a.rs +++ b/examples/boot/application/stm32h7/src/bin/a.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::cell::RefCell; diff --git a/examples/boot/application/stm32h7/src/bin/b.rs b/examples/boot/application/stm32h7/src/bin/b.rs index 5c03e2d0c..5f3f35207 100644 --- a/examples/boot/application/stm32h7/src/bin/b.rs +++ b/examples/boot/application/stm32h7/src/bin/b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index d6684bedb..240afe4c6 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs index 42e1a71eb..02f74bdef 100644 --- a/examples/boot/application/stm32l0/src/bin/a.rs +++ b/examples/boot/application/stm32l0/src/bin/a.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32l0/src/bin/b.rs b/examples/boot/application/stm32l0/src/bin/b.rs index 52d42395f..6bf00f41a 100644 --- a/examples/boot/application/stm32l0/src/bin/b.rs +++ b/examples/boot/application/stm32l0/src/bin/b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index cca8bf443..97f1e277b 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs index 42e1a71eb..02f74bdef 100644 --- a/examples/boot/application/stm32l1/src/bin/a.rs +++ b/examples/boot/application/stm32l1/src/bin/a.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32l1/src/bin/b.rs b/examples/boot/application/stm32l1/src/bin/b.rs index 52d42395f..6bf00f41a 100644 --- a/examples/boot/application/stm32l1/src/bin/b.rs +++ b/examples/boot/application/stm32l1/src/bin/b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 30d61056c..0c3830f97 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs index eefa25f75..892446968 100644 --- a/examples/boot/application/stm32l4/src/bin/a.rs +++ b/examples/boot/application/stm32l4/src/bin/a.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32l4/src/bin/b.rs b/examples/boot/application/stm32l4/src/bin/b.rs index 8411f384c..22ba82d5e 100644 --- a/examples/boot/application/stm32l4/src/bin/b.rs +++ b/examples/boot/application/stm32l4/src/bin/b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index f6beea498..cdaee802e 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index fbecbf23b..b2ccb9e1a 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::cell::RefCell; diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 7489a2fe9..b5677e148 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index c837e47b5..d9665e6ee 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs index 1ca3c6ea8..8dd15d8cd 100644 --- a/examples/boot/application/stm32wl/src/bin/b.rs +++ b/examples/boot/application/stm32wl/src/bin/b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[cfg(feature = "defmt-rtt")] use defmt_rtt::*; diff --git a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs index 888375693..41cc06417 100644 --- a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs +++ b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::future::poll_fn; use core::task::Poll; diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 1c49c32e1..bc8a7f2d6 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -4,12 +4,6 @@ name = "embassy-nrf52840-examples" version = "0.1.0" license = "MIT OR Apache-2.0" -[features] -default = ["nightly"] -nightly = [ - "static_cell/nightly", -] - [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } diff --git a/examples/nrf52840/src/bin/blinky.rs b/examples/nrf52840/src/bin/blinky.rs index d3d1a7122..58a3d2cd9 100644 --- a/examples/nrf52840/src/bin/blinky.rs +++ b/examples/nrf52840/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_nrf::gpio::{Level, Output, OutputDrive}; diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs index d9c505786..6ac72bcaf 100644 --- a/examples/nrf52840/src/bin/buffered_uart.rs +++ b/examples/nrf52840/src/bin/buffered_uart.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs index d3c7b47d2..7fcea9dbd 100644 --- a/examples/nrf52840/src/bin/channel.rs +++ b/examples/nrf52840/src/bin/channel.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::unwrap; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs index 79d2c4048..3095a04ec 100644 --- a/examples/nrf52840/src/bin/channel_sender_receiver.rs +++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::unwrap; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index 840a16556..a8e64b38a 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/executor_fairness_test.rs b/examples/nrf52840/src/bin/executor_fairness_test.rs index f111b272e..df6e7af3f 100644 --- a/examples/nrf52840/src/bin/executor_fairness_test.rs +++ b/examples/nrf52840/src/bin/executor_fairness_test.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::future::poll_fn; use core::task::Poll; diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs index 5bfd02465..e254d613d 100644 --- a/examples/nrf52840/src/bin/gpiote_channel.rs +++ b/examples/nrf52840/src/bin/gpiote_channel.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/gpiote_port.rs b/examples/nrf52840/src/bin/gpiote_port.rs index 0155d539e..c1afe2f20 100644 --- a/examples/nrf52840/src/bin/gpiote_port.rs +++ b/examples/nrf52840/src/bin/gpiote_port.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs index 391514d93..9eadeb4e4 100644 --- a/examples/nrf52840/src/bin/i2s_effect.rs +++ b/examples/nrf52840/src/bin/i2s_effect.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::f32::consts::PI; diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs index 4ed597c0d..799be351f 100644 --- a/examples/nrf52840/src/bin/i2s_monitor.rs +++ b/examples/nrf52840/src/bin/i2s_monitor.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{debug, error, info}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs index f2c1166b1..137d82840 100644 --- a/examples/nrf52840/src/bin/i2s_waveform.rs +++ b/examples/nrf52840/src/bin/i2s_waveform.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::f32::consts::PI; diff --git a/examples/nrf52840/src/bin/manually_create_executor.rs b/examples/nrf52840/src/bin/manually_create_executor.rs index 80364d34a..7ca39348e 100644 --- a/examples/nrf52840/src/bin/manually_create_executor.rs +++ b/examples/nrf52840/src/bin/manually_create_executor.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::{info, unwrap}; diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs index 352f62bf2..b634d8569 100644 --- a/examples/nrf52840/src/bin/multiprio.rs +++ b/examples/nrf52840/src/bin/multiprio.rs @@ -55,7 +55,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::{info, unwrap}; diff --git a/examples/nrf52840/src/bin/mutex.rs b/examples/nrf52840/src/bin/mutex.rs index 11b47d991..5c22279b5 100644 --- a/examples/nrf52840/src/bin/mutex.rs +++ b/examples/nrf52840/src/bin/mutex.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/nvmc.rs b/examples/nrf52840/src/bin/nvmc.rs index 624829863..a79385b98 100644 --- a/examples/nrf52840/src/bin/nvmc.rs +++ b/examples/nrf52840/src/bin/nvmc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/pdm.rs b/examples/nrf52840/src/bin/pdm.rs index bff323974..52dadc805 100644 --- a/examples/nrf52840/src/bin/pdm.rs +++ b/examples/nrf52840/src/bin/pdm.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/pdm_continuous.rs b/examples/nrf52840/src/bin/pdm_continuous.rs index 7d8531475..e948203a5 100644 --- a/examples/nrf52840/src/bin/pdm_continuous.rs +++ b/examples/nrf52840/src/bin/pdm_continuous.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::cmp::Ordering; diff --git a/examples/nrf52840/src/bin/ppi.rs b/examples/nrf52840/src/bin/ppi.rs index d74ce4064..129ad06e7 100644 --- a/examples/nrf52840/src/bin/ppi.rs +++ b/examples/nrf52840/src/bin/ppi.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::future::pending; diff --git a/examples/nrf52840/src/bin/pubsub.rs b/examples/nrf52840/src/bin/pubsub.rs index 17d902227..5ebea9220 100644 --- a/examples/nrf52840/src/bin/pubsub.rs +++ b/examples/nrf52840/src/bin/pubsub.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::unwrap; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs index 9750935c8..a5bb1347a 100644 --- a/examples/nrf52840/src/bin/pwm.rs +++ b/examples/nrf52840/src/bin/pwm.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/pwm_double_sequence.rs b/examples/nrf52840/src/bin/pwm_double_sequence.rs index 1bfe6e15a..386c483b8 100644 --- a/examples/nrf52840/src/bin/pwm_double_sequence.rs +++ b/examples/nrf52840/src/bin/pwm_double_sequence.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/pwm_sequence.rs b/examples/nrf52840/src/bin/pwm_sequence.rs index f282cf910..87eda265f 100644 --- a/examples/nrf52840/src/bin/pwm_sequence.rs +++ b/examples/nrf52840/src/bin/pwm_sequence.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs index 6594fa348..60ea712b5 100644 --- a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs +++ b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::future::pending; diff --git a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs index 8596e6545..751cf4425 100644 --- a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs +++ b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs index 92ded1f88..d772d2f5d 100644 --- a/examples/nrf52840/src/bin/pwm_servo.rs +++ b/examples/nrf52840/src/bin/pwm_servo.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/qdec.rs b/examples/nrf52840/src/bin/qdec.rs index 59783d312..ea849be63 100644 --- a/examples/nrf52840/src/bin/qdec.rs +++ b/examples/nrf52840/src/bin/qdec.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs index 9e8a01f4e..4539dd0e3 100644 --- a/examples/nrf52840/src/bin/qspi.rs +++ b/examples/nrf52840/src/bin/qspi.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{assert_eq, info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs index 42b5454e0..516c9b481 100644 --- a/examples/nrf52840/src/bin/qspi_lowpower.rs +++ b/examples/nrf52840/src/bin/qspi_lowpower.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem; diff --git a/examples/nrf52840/src/bin/rng.rs b/examples/nrf52840/src/bin/rng.rs index 855743f50..326054c9a 100644 --- a/examples/nrf52840/src/bin/rng.rs +++ b/examples/nrf52840/src/bin/rng.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_nrf::rng::Rng; diff --git a/examples/nrf52840/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs index d651834f5..653b7d606 100644 --- a/examples/nrf52840/src/bin/saadc.rs +++ b/examples/nrf52840/src/bin/saadc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs index a5f8a4dd7..f76fa3570 100644 --- a/examples/nrf52840/src/bin/saadc_continuous.rs +++ b/examples/nrf52840/src/bin/saadc_continuous.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs index 8a58396a4..5bfefc2af 100644 --- a/examples/nrf52840/src/bin/self_spawn.rs +++ b/examples/nrf52840/src/bin/self_spawn.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/self_spawn_current_executor.rs b/examples/nrf52840/src/bin/self_spawn_current_executor.rs index 65d50f8c3..ec9569a64 100644 --- a/examples/nrf52840/src/bin/self_spawn_current_executor.rs +++ b/examples/nrf52840/src/bin/self_spawn_current_executor.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/spim.rs b/examples/nrf52840/src/bin/spim.rs index 9d1843a8f..131187660 100644 --- a/examples/nrf52840/src/bin/spim.rs +++ b/examples/nrf52840/src/bin/spim.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs index 77b6e8b64..613cd37ab 100644 --- a/examples/nrf52840/src/bin/spis.rs +++ b/examples/nrf52840/src/bin/spis.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/temp.rs b/examples/nrf52840/src/bin/temp.rs index d94dea38d..1d28f8ecf 100644 --- a/examples/nrf52840/src/bin/temp.rs +++ b/examples/nrf52840/src/bin/temp.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/timer.rs b/examples/nrf52840/src/bin/timer.rs index 9b9bb3eb4..365695a20 100644 --- a/examples/nrf52840/src/bin/timer.rs +++ b/examples/nrf52840/src/bin/timer.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs index 959e3a4be..a9a0765e8 100644 --- a/examples/nrf52840/src/bin/twim.rs +++ b/examples/nrf52840/src/bin/twim.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs index bf9f966ef..c743614b8 100644 --- a/examples/nrf52840/src/bin/twim_lowpower.rs +++ b/examples/nrf52840/src/bin/twim_lowpower.rs @@ -6,7 +6,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem; diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs index aa42b679e..88bd4cceb 100644 --- a/examples/nrf52840/src/bin/twis.rs +++ b/examples/nrf52840/src/bin/twis.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs index 50d5cab8c..accaccea1 100644 --- a/examples/nrf52840/src/bin/uart.rs +++ b/examples/nrf52840/src/bin/uart.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs index e1f42fa6c..fa93bcf21 100644 --- a/examples/nrf52840/src/bin/uart_idle.rs +++ b/examples/nrf52840/src/bin/uart_idle.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs index b748bfcd8..c7510a9a8 100644 --- a/examples/nrf52840/src/bin/uart_split.rs +++ b/examples/nrf52840/src/bin/uart_split.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index de661c019..3469c6e5f 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem; diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 7ccd2946a..45850b4a4 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem; use core::sync::atomic::{AtomicBool, Ordering}; diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 96fcf8a66..04ad841b7 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem; diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index dc95cde84..aff539b1b 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem; diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 7a7bf962b..4e8118fb8 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem; diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index 1d39d3841..060f9ba94 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem; diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs index 058746518..ede88cc26 100644 --- a/examples/nrf52840/src/bin/wdt.rs +++ b/examples/nrf52840/src/bin/wdt.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index b56c9bd8d..fc2086f75 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 17d3e30e4..fc0346f90 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } @@ -17,7 +17,7 @@ embedded-io-async = { version = "0.6.1" } defmt = "0.3" defmt-rtt = "0.4" -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/nrf5340/src/bin/blinky.rs b/examples/nrf5340/src/bin/blinky.rs index b784564a5..5c533c9b1 100644 --- a/examples/nrf5340/src/bin/blinky.rs +++ b/examples/nrf5340/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_nrf::gpio::{Level, Output, OutputDrive}; diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs index ceab1194a..c0a55142f 100644 --- a/examples/nrf5340/src/bin/gpiote_channel.rs +++ b/examples/nrf5340/src/bin/gpiote_channel.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/nrf5340/src/bin/uart.rs b/examples/nrf5340/src/bin/uart.rs index d68539702..7b41d7463 100644 --- a/examples/nrf5340/src/bin/uart.rs +++ b/examples/nrf5340/src/bin/uart.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 521f17b82..07de83203 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", 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"] } @@ -43,7 +43,7 @@ embedded-hal-async = "1.0.0-rc.3" embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-storage = { version = "0.3" } -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" pio-proc = "0.2" diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs index a579be139..1bb7c2249 100644 --- a/examples/rp/src/bin/adc.rs +++ b/examples/rp/src/bin/adc.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/blinky.rs b/examples/rp/src/bin/blinky.rs index 66c8773fa..60fc45a70 100644 --- a/examples/rp/src/bin/blinky.rs +++ b/examples/rp/src/bin/blinky.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs index a9f34ab5d..e9054fd48 100644 --- a/examples/rp/src/bin/button.rs +++ b/examples/rp/src/bin/button.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_rp::gpio::{Input, Level, Output, Pull}; diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index b9dba0f1d..a16ea0007 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 36073f20b..975b3d385 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::str::FromStr; diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index d523a8772..489af2c76 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -5,7 +5,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 0cc47cb56..41bd7d077 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs index 129a8497f..eb3e6a2b9 100644 --- a/examples/rp/src/bin/flash.rs +++ b/examples/rp/src/bin/flash.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/gpio_async.rs b/examples/rp/src/bin/gpio_async.rs index 98209fe41..b79fb2a15 100644 --- a/examples/rp/src/bin/gpio_async.rs +++ b/examples/rp/src/bin/gpio_async.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs index 896cc15ee..011359253 100644 --- a/examples/rp/src/bin/gpout.rs +++ b/examples/rp/src/bin/gpout.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/i2c_async.rs b/examples/rp/src/bin/i2c_async.rs index 7b53aae72..e31cc894c 100644 --- a/examples/rp/src/bin/i2c_async.rs +++ b/examples/rp/src/bin/i2c_async.rs @@ -5,7 +5,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/i2c_blocking.rs b/examples/rp/src/bin/i2c_blocking.rs index 9ddb48d69..c9c8a2760 100644 --- a/examples/rp/src/bin/i2c_blocking.rs +++ b/examples/rp/src/bin/i2c_blocking.rs @@ -5,7 +5,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs index 151b083a4..479f9a16a 100644 --- a/examples/rp/src/bin/i2c_slave.rs +++ b/examples/rp/src/bin/i2c_slave.rs @@ -1,7 +1,6 @@ //! This example shows how to use the 2040 as an i2c slave. #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index 43eaf8b0a..a1678d99a 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Executor; diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs index 28f621437..26b80c11d 100644 --- a/examples/rp/src/bin/multiprio.rs +++ b/examples/rp/src/bin/multiprio.rs @@ -55,7 +55,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::{info, unwrap}; diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index a6d6144be..ee248591b 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 86e5017ac..02700269c 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 5e5a6f9a3..3fab7b5f2 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs index 6d9d59df6..58bdadbc0 100644 --- a/examples/rp/src/bin/pio_rotary_encoder.rs +++ b/examples/rp/src/bin/pio_rotary_encoder.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index 02fb20699..ab9ecf623 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::mem::{self, MaybeUninit}; use defmt::info; diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index c0ea23607..a07f1c180 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -8,7 +8,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #![allow(async_fn_in_trait)] use defmt::{info, panic, trace}; diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index 7b3259538..9a97cb8a7 100644 --- a/examples/rp/src/bin/pio_ws2812.rs +++ b/examples/rp/src/bin/pio_ws2812.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index a99e88003..4fb62546d 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/pwm_input.rs b/examples/rp/src/bin/pwm_input.rs index 0fc2e40c3..e7bcbfbd4 100644 --- a/examples/rp/src/bin/pwm_input.rs +++ b/examples/rp/src/bin/pwm_input.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/rosc.rs b/examples/rp/src/bin/rosc.rs index f841043b6..942b72319 100644 --- a/examples/rp/src/bin/rosc.rs +++ b/examples/rp/src/bin/rosc.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/rtc.rs b/examples/rp/src/bin/rtc.rs index 667876db5..e9a5e43a8 100644 --- a/examples/rp/src/bin/rtc.rs +++ b/examples/rp/src/bin/rtc.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/spi.rs b/examples/rp/src/bin/spi.rs index 602348f7a..4cc4f5210 100644 --- a/examples/rp/src/bin/spi.rs +++ b/examples/rp/src/bin/spi.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/spi_async.rs b/examples/rp/src/bin/spi_async.rs index f5a2d334e..266584efc 100644 --- a/examples/rp/src/bin/spi_async.rs +++ b/examples/rp/src/bin/spi_async.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index 26c258e1c..e937b9d0a 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs @@ -5,7 +5,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::cell::RefCell; diff --git a/examples/rp/src/bin/uart.rs b/examples/rp/src/bin/uart.rs index 451c3c396..6a2816cd0 100644 --- a/examples/rp/src/bin/uart.rs +++ b/examples/rp/src/bin/uart.rs @@ -6,7 +6,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_rp::uart; diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs index dc57d89c7..fac61aa04 100644 --- a/examples/rp/src/bin/uart_buffered_split.rs +++ b/examples/rp/src/bin/uart_buffered_split.rs @@ -6,7 +6,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs index 42c8b432e..a45f40756 100644 --- a/examples/rp/src/bin/uart_unidir.rs +++ b/examples/rp/src/bin/uart_unidir.rs @@ -7,7 +7,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 674b83f5d..01f0d5967 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index 569c9b12b..b5ac16245 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::sync::atomic::{AtomicBool, Ordering}; diff --git a/examples/rp/src/bin/usb_logger.rs b/examples/rp/src/bin/usb_logger.rs index 791f15e56..af401ed63 100644 --- a/examples/rp/src/bin/usb_logger.rs +++ b/examples/rp/src/bin/usb_logger.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_rp::bind_interrupts; diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs index d5cdae319..95306a35c 100644 --- a/examples/rp/src/bin/usb_midi.rs +++ b/examples/rp/src/bin/usb_midi.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, panic}; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs index f59262e5c..a6c8a5b2e 100644 --- a/examples/rp/src/bin/usb_raw.rs +++ b/examples/rp/src/bin/usb_raw.rs @@ -48,7 +48,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs index 288be5a4e..0dc8e9f72 100644 --- a/examples/rp/src/bin/usb_raw_bulk.rs +++ b/examples/rp/src/bin/usb_raw_bulk.rs @@ -26,7 +26,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index 30347d920..ab24a994c 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, panic}; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/watchdog.rs b/examples/rp/src/bin/watchdog.rs index b6af518af..b9d4ef22f 100644 --- a/examples/rp/src/bin/watchdog.rs +++ b/examples/rp/src/bin/watchdog.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 20b8aad15..1bd75607e 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #![allow(async_fn_in_trait)] use core::str::from_utf8; diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index b89447b7d..1ed74993c 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cyw43_pio::PioSpi; use defmt::*; diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 0f7ad27dd..45bb5b76c 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #![allow(async_fn_in_trait)] use core::str; diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index f6cc48d8f..c346f1ded 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -3,7 +3,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #![allow(async_fn_in_trait)] use core::str::from_utf8; diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index ccc0a4afc..a4f306865 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } @@ -23,7 +23,7 @@ nix = "0.26.2" clap = { version = "3.0.0-beta.5", features = ["derive"] } rand_core = { version = "0.6.3", features = ["std"] } heapless = { version = "0.8", default-features = false } -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" [profile.release] debug = 2 diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index c62a38d07..dad93d0a1 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -1,5 +1,3 @@ -#![feature(type_alias_impl_trait)] - use std::default::Default; use clap::Parser; diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index e1e015bc8..fca1e076e 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs @@ -1,5 +1,3 @@ -#![feature(type_alias_impl_trait)] - use std::default::Default; use clap::Parser; diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index 8c80c4beb..9ec0ea91f 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -7,7 +7,6 @@ //! ping 192.168.7.10 //! nc 192.168.7.10 1234 -#![feature(type_alias_impl_trait)] #![allow(async_fn_in_trait)] #[path = "../serial_port.rs"] diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs index ac99ec626..bee91990d 100644 --- a/examples/std/src/bin/net_udp.rs +++ b/examples/std/src/bin/net_udp.rs @@ -1,5 +1,3 @@ -#![feature(type_alias_impl_trait)] - use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::udp::{PacketMetadata, UdpSocket}; diff --git a/examples/std/src/bin/serial.rs b/examples/std/src/bin/serial.rs index 0b289c74d..435089aad 100644 --- a/examples/std/src/bin/serial.rs +++ b/examples/std/src/bin/serial.rs @@ -1,5 +1,3 @@ -#![feature(type_alias_impl_trait)] - #[path = "../serial_port.rs"] mod serial_port; diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 54ef0156b..00ccd83a7 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs @@ -1,5 +1,3 @@ -#![feature(type_alias_impl_trait)] - use core::fmt::Write as _; use std::default::Default; diff --git a/examples/std/src/bin/tick.rs b/examples/std/src/bin/tick.rs index a3f99067e..f23cf3549 100644 --- a/examples/std/src/bin/tick.rs +++ b/examples/std/src/bin/tick.rs @@ -1,5 +1,3 @@ -#![feature(type_alias_impl_trait)] - use embassy_executor::Spawner; use embassy_time::Timer; use log::*; diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 2d831ba5d..0fd3939c6 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32c0/src/bin/blinky.rs b/examples/stm32c0/src/bin/blinky.rs index cbeb0dee1..90e479aae 100644 --- a/examples/stm32c0/src/bin/blinky.rs +++ b/examples/stm32c0/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32c0/src/bin/button.rs b/examples/stm32c0/src/bin/button.rs index 40c58013b..265200132 100644 --- a/examples/stm32c0/src/bin/button.rs +++ b/examples/stm32c0/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32c0/src/bin/button_exti.rs b/examples/stm32c0/src/bin/button_exti.rs index ef32d4c4a..1e970fdd6 100644 --- a/examples/stm32c0/src/bin/button_exti.rs +++ b/examples/stm32c0/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 2b066d731..9fdc4798a 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -15,9 +15,9 @@ defmt = "0.3" defmt-rtt = "0.4" panic-probe = "0.3" embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } [profile.release] diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 96f234402..8fef062b3 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f0/src/bin/blinky.rs b/examples/stm32f0/src/bin/blinky.rs index 899394546..2572be1bc 100644 --- a/examples/stm32f0/src/bin/blinky.rs +++ b/examples/stm32f0/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs index 306df1752..360d153c3 100644 --- a/examples/stm32f0/src/bin/button_controlled_blink.rs +++ b/examples/stm32f0/src/bin/button_controlled_blink.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::sync::atomic::{AtomicU32, Ordering}; diff --git a/examples/stm32f0/src/bin/button_exti.rs b/examples/stm32f0/src/bin/button_exti.rs index 40c0d5848..ce17c1a48 100644 --- a/examples/stm32f0/src/bin/button_exti.rs +++ b/examples/stm32f0/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f0/src/bin/hello.rs b/examples/stm32f0/src/bin/hello.rs index 0f98d9865..ccd6a0a39 100644 --- a/examples/stm32f0/src/bin/hello.rs +++ b/examples/stm32f0/src/bin/hello.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs index 870c7c45b..e49951726 100644 --- a/examples/stm32f0/src/bin/multiprio.rs +++ b/examples/stm32f0/src/bin/multiprio.rs @@ -55,7 +55,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32f0/src/bin/wdg.rs b/examples/stm32f0/src/bin/wdg.rs index b51dee8ee..b974bff91 100644 --- a/examples/stm32f0/src/bin/wdg.rs +++ b/examples/stm32f0/src/bin/wdg.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index f04d41317..c933a4368 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs index 1edac3d83..1440460a9 100644 --- a/examples/stm32f1/src/bin/adc.rs +++ b/examples/stm32f1/src/bin/adc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f1/src/bin/blinky.rs b/examples/stm32f1/src/bin/blinky.rs index 3425b0536..cc43f85f4 100644 --- a/examples/stm32f1/src/bin/blinky.rs +++ b/examples/stm32f1/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index a5ce819d4..c1c4f8359 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f1/src/bin/hello.rs b/examples/stm32f1/src/bin/hello.rs index e63bcaae0..7b761ecc1 100644 --- a/examples/stm32f1/src/bin/hello.rs +++ b/examples/stm32f1/src/bin/hello.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index 31519555f..e28381893 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use embassy_executor::Spawner; diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 66cc1e15b..eaaadeec5 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f2/src/bin/blinky.rs b/examples/stm32f2/src/bin/blinky.rs index f6d7a0005..d9833ba8b 100644 --- a/examples/stm32f2/src/bin/blinky.rs +++ b/examples/stm32f2/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index aae7637dc..e32f283d1 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::convert::TryFrom; diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index ed1367858..d5ab0b25a 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } @@ -24,7 +24,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" [profile.release] debug = 2 diff --git a/examples/stm32f3/src/bin/blinky.rs b/examples/stm32f3/src/bin/blinky.rs index e71031b30..0ea10522d 100644 --- a/examples/stm32f3/src/bin/blinky.rs +++ b/examples/stm32f3/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f3/src/bin/button.rs b/examples/stm32f3/src/bin/button.rs index 2f47d8f80..2cd356787 100644 --- a/examples/stm32f3/src/bin/button.rs +++ b/examples/stm32f3/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs index 9df6d680d..2f7da4ef5 100644 --- a/examples/stm32f3/src/bin/button_events.rs +++ b/examples/stm32f3/src/bin/button_events.rs @@ -8,7 +8,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f3/src/bin/button_exti.rs b/examples/stm32f3/src/bin/button_exti.rs index 1266778c1..86ff68492 100644 --- a/examples/stm32f3/src/bin/button_exti.rs +++ b/examples/stm32f3/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs index 236fb36c1..28125697d 100644 --- a/examples/stm32f3/src/bin/flash.rs +++ b/examples/stm32f3/src/bin/flash.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32f3/src/bin/hello.rs b/examples/stm32f3/src/bin/hello.rs index b3285f3c1..fd54da53d 100644 --- a/examples/stm32f3/src/bin/hello.rs +++ b/examples/stm32f3/src/bin/hello.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs index 74f3bb1c5..328447210 100644 --- a/examples/stm32f3/src/bin/multiprio.rs +++ b/examples/stm32f3/src/bin/multiprio.rs @@ -55,7 +55,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32f3/src/bin/spi_dma.rs b/examples/stm32f3/src/bin/spi_dma.rs index a27c1d547..54498d53d 100644 --- a/examples/stm32f3/src/bin/spi_dma.rs +++ b/examples/stm32f3/src/bin/spi_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; use core::str::from_utf8; diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index ce8c212ae..5234e53b9 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index d5d068d62..cf9ecedfa 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use embassy_executor::Spawner; diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 320cf7d7b..b29a08e7c 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } @@ -23,4 +23,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index f259135d2..063ee9dac 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/stm32f334/src/bin/button.rs b/examples/stm32f334/src/bin/button.rs index 501fb080c..256f9a44a 100644 --- a/examples/stm32f334/src/bin/button.rs +++ b/examples/stm32f334/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f334/src/bin/hello.rs b/examples/stm32f334/src/bin/hello.rs index b3285f3c1..fd54da53d 100644 --- a/examples/stm32f334/src/bin/hello.rs +++ b/examples/stm32f334/src/bin/hello.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 10e7b3543..850a0e335 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 8040c3f18..c149cad92 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index e24fbee82..a74e0f674 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } @@ -27,7 +27,7 @@ heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" micromath = "2.0.0" -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" chrono = { version = "^0.4", default-features = false} [profile.release] diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index f19328727..699c29c05 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs; use defmt::*; diff --git a/examples/stm32f4/src/bin/blinky.rs b/examples/stm32f4/src/bin/blinky.rs index 4bfc5a50d..31cce8225 100644 --- a/examples/stm32f4/src/bin/blinky.rs +++ b/examples/stm32f4/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/button.rs b/examples/stm32f4/src/bin/button.rs index aa1eed46f..ad30a56a2 100644 --- a/examples/stm32f4/src/bin/button.rs +++ b/examples/stm32f4/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32f4/src/bin/button_exti.rs b/examples/stm32f4/src/bin/button_exti.rs index dfe587d41..67751187d 100644 --- a/examples/stm32f4/src/bin/button_exti.rs +++ b/examples/stm32f4/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index 20ce4edce..d074b4265 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs index 8f14d6078..9c7754c4f 100644 --- a/examples/stm32f4/src/bin/dac.rs +++ b/examples/stm32f4/src/bin/dac.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 17a14aac4..7f5c8fdb1 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs index 56a35ddee..1e8cabab4 100644 --- a/examples/stm32f4/src/bin/flash.rs +++ b/examples/stm32f4/src/bin/flash.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs index 1624d842e..493a536f3 100644 --- a/examples/stm32f4/src/bin/flash_async.rs +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/hello.rs b/examples/stm32f4/src/bin/hello.rs index a2a287110..3c295612c 100644 --- a/examples/stm32f4/src/bin/hello.rs +++ b/examples/stm32f4/src/bin/hello.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs index 4f4adde28..4b5da774d 100644 --- a/examples/stm32f4/src/bin/i2c.rs +++ b/examples/stm32f4/src/bin/i2c.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/i2c_async.rs b/examples/stm32f4/src/bin/i2c_async.rs index 9f59e4d41..90d11d4b4 100644 --- a/examples/stm32f4/src/bin/i2c_async.rs +++ b/examples/stm32f4/src/bin/i2c_async.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] // Example originally designed for stm32f411ceu6 reading an A1454 hall effect sensor on I2C1 // DMA peripherals changed to compile for stm32f429zi, for the CI. diff --git a/examples/stm32f4/src/bin/i2c_comparison.rs b/examples/stm32f4/src/bin/i2c_comparison.rs index 6d23c0ed8..30cfbdf57 100644 --- a/examples/stm32f4/src/bin/i2c_comparison.rs +++ b/examples/stm32f4/src/bin/i2c_comparison.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] // Example originally designed for stm32f411ceu6 with three A1454 hall effect sensors, connected to I2C1, 2 and 3 // on the pins referenced in the peripheral definitions. diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs index e8d7b5f77..97a04b2aa 100644 --- a/examples/stm32f4/src/bin/i2s_dma.rs +++ b/examples/stm32f4/src/bin/i2s_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs index 3315e7652..eb7bb6261 100644 --- a/examples/stm32f4/src/bin/mco.rs +++ b/examples/stm32f4/src/bin/mco.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs index 74f3bb1c5..328447210 100644 --- a/examples/stm32f4/src/bin/multiprio.rs +++ b/examples/stm32f4/src/bin/multiprio.rs @@ -55,7 +55,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs index 8e41d0e78..8844a9f0e 100644 --- a/examples/stm32f4/src/bin/pwm.rs +++ b/examples/stm32f4/src/bin/pwm.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs index d925f26d9..161f43c48 100644 --- a/examples/stm32f4/src/bin/pwm_complementary.rs +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index 44b4303c0..abab07b6b 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 91747b2d5..66e4e527c 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs index 0919e9874..dc9141c62 100644 --- a/examples/stm32f4/src/bin/spi.rs +++ b/examples/stm32f4/src/bin/spi.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32f4/src/bin/spi_dma.rs b/examples/stm32f4/src/bin/spi_dma.rs index f291f7dba..7249c831a 100644 --- a/examples/stm32f4/src/bin/spi_dma.rs +++ b/examples/stm32f4/src/bin/spi_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; use core::str::from_utf8; diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 45e94715f..40d9d70f1 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs index 71abc2893..c99807f11 100644 --- a/examples/stm32f4/src/bin/usart_buffered.rs +++ b/examples/stm32f4/src/bin/usart_buffered.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index dca25a78c..dd6de599c 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 57ee35e97..a196259a8 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index 719b22bb9..afff55187 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -48,7 +48,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index e2ccc9142..58d994a61 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs index 0443b61c5..ea27ebce0 100644 --- a/examples/stm32f4/src/bin/wdt.rs +++ b/examples/stm32f4/src/bin/wdt.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index 39f5d3421..9835c07e4 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -8,7 +8,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 4cca0d93c..b76a848a8 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f767zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } @@ -27,7 +27,7 @@ nb = "1.0.0" rand_core = "0.6.3" critical-section = "1.1" embedded-storage = "0.3.1" -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" [profile.release] debug = 2 diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs index 48c59eaf0..f8d7b691f 100644 --- a/examples/stm32f7/src/bin/adc.rs +++ b/examples/stm32f7/src/bin/adc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/blinky.rs b/examples/stm32f7/src/bin/blinky.rs index 4bfc5a50d..31cce8225 100644 --- a/examples/stm32f7/src/bin/blinky.rs +++ b/examples/stm32f7/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/button.rs b/examples/stm32f7/src/bin/button.rs index aa1eed46f..ad30a56a2 100644 --- a/examples/stm32f7/src/bin/button.rs +++ b/examples/stm32f7/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32f7/src/bin/button_exti.rs b/examples/stm32f7/src/bin/button_exti.rs index dfe587d41..67751187d 100644 --- a/examples/stm32f7/src/bin/button_exti.rs +++ b/examples/stm32f7/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 06cd1ac7e..bcfdb67a8 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 86c709852..5bff48197 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs index 06a94f1c8..885570478 100644 --- a/examples/stm32f7/src/bin/flash.rs +++ b/examples/stm32f7/src/bin/flash.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/hello.rs b/examples/stm32f7/src/bin/hello.rs index a2a287110..3c295612c 100644 --- a/examples/stm32f7/src/bin/hello.rs +++ b/examples/stm32f7/src/bin/hello.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 990de0ab1..6d36ef518 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs index ba064081e..fb604b34f 100644 --- a/examples/stm32f7/src/bin/usart_dma.rs +++ b/examples/stm32f7/src/bin/usart_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 4991edbf0..97daf6bd1 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use embassy_executor::Spawner; diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index b1e749440..0abc0a638 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g071rb to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32g0/src/bin/blinky.rs b/examples/stm32g0/src/bin/blinky.rs index 4bfc5a50d..31cce8225 100644 --- a/examples/stm32g0/src/bin/blinky.rs +++ b/examples/stm32g0/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g0/src/bin/button.rs b/examples/stm32g0/src/bin/button.rs index 40c58013b..265200132 100644 --- a/examples/stm32g0/src/bin/button.rs +++ b/examples/stm32g0/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32g0/src/bin/button_exti.rs b/examples/stm32g0/src/bin/button_exti.rs index ef32d4c4a..1e970fdd6 100644 --- a/examples/stm32g0/src/bin/button_exti.rs +++ b/examples/stm32g0/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g0/src/bin/flash.rs b/examples/stm32g0/src/bin/flash.rs index ed9f2e843..acef87b92 100644 --- a/examples/stm32g0/src/bin/flash.rs +++ b/examples/stm32g0/src/bin/flash.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs index 214462d0e..c5ea51721 100644 --- a/examples/stm32g0/src/bin/spi_neopixel.rs +++ b/examples/stm32g0/src/bin/spi_neopixel.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index c56a63623..987f23b3a 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 63b20c0d4..35324d931 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g4/src/bin/blinky.rs b/examples/stm32g4/src/bin/blinky.rs index cbeb0dee1..90e479aae 100644 --- a/examples/stm32g4/src/bin/blinky.rs +++ b/examples/stm32g4/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g4/src/bin/button.rs b/examples/stm32g4/src/bin/button.rs index 127efb08a..6f3db0819 100644 --- a/examples/stm32g4/src/bin/button.rs +++ b/examples/stm32g4/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32g4/src/bin/button_exti.rs b/examples/stm32g4/src/bin/button_exti.rs index dfe587d41..67751187d 100644 --- a/examples/stm32g4/src/bin/button_exti.rs +++ b/examples/stm32g4/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs index 09ef59d44..46ebe0b0d 100644 --- a/examples/stm32g4/src/bin/pll.rs +++ b/examples/stm32g4/src/bin/pll.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index a84394005..d4809a481 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 565b25d60..c26fa76b7 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use embassy_executor::Spawner; diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index f714a3984..8815b8e47 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } @@ -31,7 +31,7 @@ critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" embedded-storage = "0.3.1" -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" # cargo build/run [profile.dev] diff --git a/examples/stm32h5/src/bin/blinky.rs b/examples/stm32h5/src/bin/blinky.rs index 1394f03fa..f37e8b1d8 100644 --- a/examples/stm32h5/src/bin/blinky.rs +++ b/examples/stm32h5/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h5/src/bin/button_exti.rs b/examples/stm32h5/src/bin/button_exti.rs index dfe587d41..67751187d 100644 --- a/examples/stm32h5/src/bin/button_exti.rs +++ b/examples/stm32h5/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 8789e4e0b..2370656e6 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs index 31783a2bf..31e83cbb5 100644 --- a/examples/stm32h5/src/bin/i2c.rs +++ b/examples/stm32h5/src/bin/i2c.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h5/src/bin/rng.rs b/examples/stm32h5/src/bin/rng.rs index 7c8c50eca..9c0d704b5 100644 --- a/examples/stm32h5/src/bin/rng.rs +++ b/examples/stm32h5/src/bin/rng.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs index db04d4e55..f9cbad6af 100644 --- a/examples/stm32h5/src/bin/usart.rs +++ b/examples/stm32h5/src/bin/usart.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs index bafe50839..caae0dd18 100644 --- a/examples/stm32h5/src/bin/usart_dma.rs +++ b/examples/stm32h5/src/bin/usart_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs index d9037c014..92047de8d 100644 --- a/examples/stm32h5/src/bin/usart_split.rs +++ b/examples/stm32h5/src/bin/usart_split.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 7d45818af..208493d8c 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use embassy_executor::Spawner; diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index c6aea3e11..31feeda45 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } @@ -31,7 +31,7 @@ critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" embedded-storage = "0.3.1" -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" chrono = { version = "^0.4", default-features = false } # cargo build/run diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index e367827e9..fe6fe69a1 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/blinky.rs b/examples/stm32h7/src/bin/blinky.rs index a9cab1ff4..1ee90a870 100644 --- a/examples/stm32h7/src/bin/blinky.rs +++ b/examples/stm32h7/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/button_exti.rs b/examples/stm32h7/src/bin/button_exti.rs index dfe587d41..67751187d 100644 --- a/examples/stm32h7/src/bin/button_exti.rs +++ b/examples/stm32h7/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index 489fb03dd..e5a104baf 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_stm32::dcmi::{self, *}; diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index f66268151..a9bf46de0 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index c19fdd623..1481dd967 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index a64b3253a..cd9a27fcd 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 8e84d9964..dcc6e36e2 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs index 89c0c8a66..4f9f6bb0a 100644 --- a/examples/stm32h7/src/bin/flash.rs +++ b/examples/stm32h7/src/bin/flash.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs index 54e2c3629..5e5e6ccc8 100644 --- a/examples/stm32h7/src/bin/fmc.rs +++ b/examples/stm32h7/src/bin/fmc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs index aea21ec6f..3bf39eb44 100644 --- a/examples/stm32h7/src/bin/i2c.rs +++ b/examples/stm32h7/src/bin/i2c.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 394ed3281..cc508c3cf 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs index c023f4584..a6ee27625 100644 --- a/examples/stm32h7/src/bin/mco.rs +++ b/examples/stm32h7/src/bin/mco.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index c55d780a0..1e48ba67b 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/rng.rs b/examples/stm32h7/src/bin/rng.rs index 1fb4cfec0..a9ef7200d 100644 --- a/examples/stm32h7/src/bin/rng.rs +++ b/examples/stm32h7/src/bin/rng.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs index 78cea9c89..c6b9cf57e 100644 --- a/examples/stm32h7/src/bin/rtc.rs +++ b/examples/stm32h7/src/bin/rtc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index be968ff77..abe2d4ba7 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/signal.rs b/examples/stm32h7/src/bin/signal.rs index b5f583289..b73360f32 100644 --- a/examples/stm32h7/src/bin/signal.rs +++ b/examples/stm32h7/src/bin/signal.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index a8db0ff77..aed27723a 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; use core::str::from_utf8; diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 561052e48..54d4d7656 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; use core::str::from_utf8; diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index db04d4e55..f9cbad6af 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index 249050fd1..ae1f3a2e9 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index 61c9f1954..b98c40877 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index f80cf63ec..d81efb541 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use embassy_executor::Spawner; diff --git a/examples/stm32h7/src/bin/wdg.rs b/examples/stm32h7/src/bin/wdg.rs index 76fd9dfc0..a4184aa96 100644 --- a/examples/stm32h7/src/bin/wdg.rs +++ b/examples/stm32h7/src/bin/wdg.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 7c8264739..739aa6cb1 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -4,10 +4,6 @@ name = "embassy-stm32l0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" -[features] -default = ["nightly"] -nightly = ["embassy-executor/nightly"] - [dependencies] # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } diff --git a/examples/stm32l0/src/bin/blinky.rs b/examples/stm32l0/src/bin/blinky.rs index ea40bfc48..caca5759f 100644 --- a/examples/stm32l0/src/bin/blinky.rs +++ b/examples/stm32l0/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l0/src/bin/button.rs b/examples/stm32l0/src/bin/button.rs index 3e56160e9..165a714a5 100644 --- a/examples/stm32l0/src/bin/button.rs +++ b/examples/stm32l0/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs index ffede253e..f517fce04 100644 --- a/examples/stm32l0/src/bin/button_exti.rs +++ b/examples/stm32l0/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs index 86f6c70b9..1865748fd 100644 --- a/examples/stm32l0/src/bin/flash.rs +++ b/examples/stm32l0/src/bin/flash.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs index 583e3d127..f23a537b8 100644 --- a/examples/stm32l0/src/bin/spi.rs +++ b/examples/stm32l0/src/bin/spi.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs index 62c9b5595..74889c838 100644 --- a/examples/stm32l0/src/bin/usart_dma.rs +++ b/examples/stm32l0/src/bin/usart_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index 5107a1a0a..2c96a8bc2 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 23dd0ef87..071d6a502 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } diff --git a/examples/stm32l1/src/bin/blinky.rs b/examples/stm32l1/src/bin/blinky.rs index 06f732eb7..da6777b2d 100644 --- a/examples/stm32l1/src/bin/blinky.rs +++ b/examples/stm32l1/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs index aeb535cca..e9ce4eae8 100644 --- a/examples/stm32l1/src/bin/flash.rs +++ b/examples/stm32l1/src/bin/flash.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs index 905b4d75c..8be686c5a 100644 --- a/examples/stm32l1/src/bin/spi.rs +++ b/examples/stm32l1/src/bin/spi.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 2861216d4..8a5fb5749 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } @@ -32,7 +32,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.8", default-features = false } chrono = { version = "^0.4", default-features = false } rand = { version = "0.8.5", default-features = false } -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" micromath = "2.0.0" diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index a0ec5c33e..d01e9f1b3 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_stm32::adc::{Adc, Resolution}; diff --git a/examples/stm32l4/src/bin/blinky.rs b/examples/stm32l4/src/bin/blinky.rs index 6202fe2f7..b55dfd35e 100644 --- a/examples/stm32l4/src/bin/blinky.rs +++ b/examples/stm32l4/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/src/bin/button.rs b/examples/stm32l4/src/bin/button.rs index 0a102c2d6..15288c61e 100644 --- a/examples/stm32l4/src/bin/button.rs +++ b/examples/stm32l4/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_stm32::gpio::{Input, Pull}; diff --git a/examples/stm32l4/src/bin/button_exti.rs b/examples/stm32l4/src/bin/button_exti.rs index ef32d4c4a..1e970fdd6 100644 --- a/examples/stm32l4/src/bin/button_exti.rs +++ b/examples/stm32l4/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs index d6a7ff624..fdbf1d374 100644 --- a/examples/stm32l4/src/bin/dac.rs +++ b/examples/stm32l4/src/bin/dac.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_stm32::dac::{DacCh1, Value}; diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index dc86dbf43..64c541caa 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs index 07dc12e8c..f553deb82 100644 --- a/examples/stm32l4/src/bin/i2c.rs +++ b/examples/stm32l4/src/bin/i2c.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs index 60a4e2eb3..1b8652bcc 100644 --- a/examples/stm32l4/src/bin/i2c_blocking_async.rs +++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_embedded_hal::adapter::BlockingAsync; diff --git a/examples/stm32l4/src/bin/i2c_dma.rs b/examples/stm32l4/src/bin/i2c_dma.rs index 4c2c224a6..794972a33 100644 --- a/examples/stm32l4/src/bin/i2c_dma.rs +++ b/examples/stm32l4/src/bin/i2c_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/src/bin/mco.rs b/examples/stm32l4/src/bin/mco.rs index 504879887..36c002952 100644 --- a/examples/stm32l4/src/bin/mco.rs +++ b/examples/stm32l4/src/bin/mco.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs index e5ad56fb9..638b3e9e4 100644 --- a/examples/stm32l4/src/bin/rng.rs +++ b/examples/stm32l4/src/bin/rng.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index d2a2aa1f2..526620bfb 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index eb04fe5e6..9565ae168 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -1,10 +1,7 @@ -#![deny(clippy::pedantic)] -#![allow(clippy::doc_markdown)] #![no_main] #![no_std] -// Needed unitl https://github.com/rust-lang/rust/issues/63063 is stablised. -#![feature(type_alias_impl_trait)] -#![feature(associated_type_bounds)] +#![deny(clippy::pedantic)] +#![allow(clippy::doc_markdown)] #![allow(clippy::missing_errors_doc)] // This example works on a ANALOG DEVICE EVAL-ADIN110EBZ board. diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs index 54cf68f7b..6653e4516 100644 --- a/examples/stm32l4/src/bin/spi.rs +++ b/examples/stm32l4/src/bin/spi.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_stm32::dma::NoDma; diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs index 903ca58df..a989a5a4a 100644 --- a/examples/stm32l4/src/bin/spi_blocking_async.rs +++ b/examples/stm32l4/src/bin/spi_blocking_async.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_embedded_hal::adapter::BlockingAsync; diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs index 58cf2e51e..7922165df 100644 --- a/examples/stm32l4/src/bin/spi_dma.rs +++ b/examples/stm32l4/src/bin/spi_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index f4da6b5ae..7bab23950 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_stm32::dma::NoDma; diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 2f3b2a0f0..031888f70 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::fmt::Write; diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 4baf5f05d..8cc9a7aed 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use defmt_rtt as _; // global logger diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 2557ef42d..0d236ec90 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } @@ -26,7 +26,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.8", default-features = false } rand_core = { version = "0.6.3", default-features = false } embedded-io-async = { version = "0.6.1" } -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" [profile.release] debug = 2 diff --git a/examples/stm32l5/src/bin/button_exti.rs b/examples/stm32l5/src/bin/button_exti.rs index e80ad2b3a..91d0ccc2e 100644 --- a/examples/stm32l5/src/bin/button_exti.rs +++ b/examples/stm32l5/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs index 279f4f65d..50da6c946 100644 --- a/examples/stm32l5/src/bin/rng.rs +++ b/examples/stm32l5/src/bin/rng.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 214235bd5..88060b6b0 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 3614a8e0a..7c8a8ebfb 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index f2b894b68..75053ce4b 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use embassy_executor::Spawner; diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 1afbd8db4..029b2cfe0 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u585ai to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32u5/src/bin/blinky.rs b/examples/stm32u5/src/bin/blinky.rs index 4b44cb12b..7fe88c183 100644 --- a/examples/stm32u5/src/bin/blinky.rs +++ b/examples/stm32u5/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32u5/src/bin/boot.rs b/examples/stm32u5/src/bin/boot.rs index e2112ce5c..23c7f8b22 100644 --- a/examples/stm32u5/src/bin/boot.rs +++ b/examples/stm32u5/src/bin/boot.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use {defmt_rtt as _, embassy_stm32 as _, panic_probe as _}; diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 839d6472f..44d1df4f1 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{panic, *}; use defmt_rtt as _; // global logger diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index ada1f32e9..bce53c440 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } @@ -22,7 +22,7 @@ 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 } -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" [features] default = ["ble", "mac"] diff --git a/examples/stm32wb/src/bin/blinky.rs b/examples/stm32wb/src/bin/blinky.rs index 1394f03fa..f37e8b1d8 100644 --- a/examples/stm32wb/src/bin/blinky.rs +++ b/examples/stm32wb/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wb/src/bin/button_exti.rs b/examples/stm32wb/src/bin/button_exti.rs index 3648db6ff..d34dde3e9 100644 --- a/examples/stm32wb/src/bin/button_exti.rs +++ b/examples/stm32wb/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs index e58da8e35..cf9a5aa28 100644 --- a/examples/stm32wb/src/bin/eddystone_beacon.rs +++ b/examples/stm32wb/src/bin/eddystone_beacon.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::time::Duration; diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index 80e835c1d..5ce620350 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use core::time::Duration; diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index 881dc488d..5cd660543 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index 454530c03..7a42bf577 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index 000355de6..7949211fb 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs index 9d0e0070c..cb92d462d 100644 --- a/examples/stm32wb/src/bin/tl_mbox.rs +++ b/examples/stm32wb/src/bin/tl_mbox.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs index 12c6aeebb..2599e1151 100644 --- a/examples/stm32wb/src/bin/tl_mbox_ble.rs +++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs index f32e07d96..5d868412a 100644 --- a/examples/stm32wb/src/bin/tl_mbox_mac.rs +++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index c97605937..84eb6c831 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } @@ -20,7 +20,7 @@ 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 } -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" [profile.release] debug = 2 diff --git a/examples/stm32wba/src/bin/blinky.rs b/examples/stm32wba/src/bin/blinky.rs index 6b9635e66..0d803b257 100644 --- a/examples/stm32wba/src/bin/blinky.rs +++ b/examples/stm32wba/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wba/src/bin/button_exti.rs b/examples/stm32wba/src/bin/button_exti.rs index ef32d4c4a..1e970fdd6 100644 --- a/examples/stm32wba/src/bin/button_exti.rs +++ b/examples/stm32wba/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 070d27cb6..62c34b792 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs index 5bd5745f0..347bd093f 100644 --- a/examples/stm32wl/src/bin/blinky.rs +++ b/examples/stm32wl/src/bin/blinky.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index 6c1f5a5ef..3397e5ba6 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use cortex_m_rt::entry; use defmt::*; diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs index 1f02db5cf..e6ad4b80b 100644 --- a/examples/stm32wl/src/bin/button_exti.rs +++ b/examples/stm32wl/src/bin/button_exti.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index 5e52d49ec..0b7417c01 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::{info, unwrap}; use embassy_executor::Spawner; diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 2fd234966..3610392be 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index 4ffb0bb58..4738d5770 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index 44e8f83a2..8e545834c 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use defmt::*; use embassy_executor::Spawner; diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index c96a428b9..305ebd526 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs index 1141096fb..71cf980dd 100644 --- a/examples/wasm/src/lib.rs +++ b/examples/wasm/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(type_alias_impl_trait)] - use embassy_executor::Spawner; use embassy_time::Timer; diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml new file mode 100644 index 000000000..b8a7db353 --- /dev/null +++ b/rust-toolchain-nightly.toml @@ -0,0 +1,12 @@ +[toolchain] +channel = "nightly-2023-12-20" +components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] +targets = [ + "thumbv7em-none-eabi", + "thumbv7m-none-eabi", + "thumbv6m-none-eabi", + "thumbv7em-none-eabihf", + "thumbv8m.main-none-eabihf", + "riscv32imac-unknown-none-elf", + "wasm32-unknown-unknown", +] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 11f53ee4a..e1af0b647 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,8 +1,6 @@ -# Before upgrading check that everything is available on all tier1 targets here: -# https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "nightly-2023-11-01" -components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] +channel = "beta-2023-12-17" +components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi", @@ -11,4 +9,4 @@ targets = [ "thumbv8m.main-none-eabihf", "riscv32imac-unknown-none-elf", "wasm32-unknown-unknown", -] \ No newline at end of file +] diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index b6067abcc..ccdca0844 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -18,7 +18,7 @@ embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-host embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } embedded-hal-async = { version = "1.0.0-rc.3" } embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] } -static_cell = { version = "2", features = [ "nightly" ] } +static_cell = "2" perf-client = { path = "../perf-client" } defmt = "0.3" diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs index c26c0d066..7dc1941d7 100644 --- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] teleprobe_meta::target!(b"ak-gwe-r7"); teleprobe_meta::timeout!(120); diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index 5b43b75d7..c96064f84 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] teleprobe_meta::target!(b"nrf52840-dk"); teleprobe_meta::timeout!(120); diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 028ce43ee..c38aa8004 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -31,7 +31,7 @@ panic-probe = { version = "0.3.0", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } embedded-io-async = { version = "0.6.1" } embedded-storage = { version = "0.3" } -static_cell = { version = "2", features = ["nightly"]} +static_cell = "2" portable-atomic = { version = "1.5", features = ["critical-section"] } pio = "0.2" pio-proc = "0.2" diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index d70ef8ef3..a1b2946e6 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] teleprobe_meta::target!(b"rpi-pico"); use cyw43_pio::PioSpi; diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs index 5588b6427..8c9089d0e 100644 --- a/tests/rp/src/bin/ethernet_w5100s_perf.rs +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] teleprobe_meta::target!(b"w5100s-evb-pico"); teleprobe_meta::timeout!(120); diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bdec41571..c60b28a7a 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -69,7 +69,7 @@ micromath = "2.0.0" panic-probe = { version = "0.3.0", features = ["print-defmt"] } rand_core = { version = "0.6", default-features = false } rand_chacha = { version = "0.3", default-features = false } -static_cell = { version = "2", features = ["nightly"] } +static_cell = "2" portable-atomic = { version = "1.5", features = [] } chrono = { version = "^0.4", default-features = false, optional = true} diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index c01f33a97..7c02f0354 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -1,7 +1,6 @@ // required-features: eth #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[path = "../common.rs"] mod common; diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index f8e3c43d7..000296d46 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -2,7 +2,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] #[path = "../common.rs"] mod common; From 53fc344e4d46388cc742c139a263c1cdf0c16589 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 22 Dec 2023 01:24:31 +0800 Subject: [PATCH 098/760] fix timing, turn TIM UDE on only necessary, clean DMA FEIF after each Transfer --- examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index dc397eff1..c4181d024 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -64,9 +64,6 @@ async fn main(_spawner: Spawner) { CountingMode::EdgeAlignedUp, ); - // PAC level hacking, enable timer-update-event trigger DMA - pac::TIM3.dier().modify(|v| v.set_ude(true)); - // construct ws2812 non-return-to-zero (NRZ) code bit by bit // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low @@ -104,13 +101,16 @@ async fn main(_spawner: Spawner) { dma_transfer_option.mburst = Burst::Incr8; // flip color at 2 Hz - let mut ticker = Ticker::every(Duration::from_micros(500)); + let mut ticker = Ticker::every(Duration::from_millis(500)); loop { for &color in color_list { // start PWM output ws2812_pwm.enable(pwm_channel); + // PAC level hacking, enable timer-update-event trigger DMA + pac::TIM3.dier().modify(|v| v.set_ude(true)); + unsafe { Transfer::new_write( // with &mut, we can easily reuse same DMA channel multiple times @@ -121,6 +121,14 @@ async fn main(_spawner: Spawner) { dma_transfer_option, ) .await; + + // Turn off timer-update-event trigger DMA as soon as possible. + // Then clean the FIFO Error Flag if set. + pac::TIM3.dier().modify(|v| v.set_ude(false)); + if pac::DMA1.isr(0).read().feif(2) { + pac::DMA1.ifcr(0).write(|v| v.set_feif(2, true)); + } + // ws2812 need at least 50 us low level input to confirm the input data and change it's state Timer::after_micros(50).await; } From 2f75ffb2333904e1370a845ead88442c45b5ba5d Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 22 Dec 2023 01:31:25 +0800 Subject: [PATCH 099/760] remove unused feature attribute --- examples/stm32f4/src/bin/ws2812_spi.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs index eca657900..a280a3b77 100644 --- a/examples/stm32f4/src/bin/ws2812_spi.rs +++ b/examples/stm32f4/src/bin/ws2812_spi.rs @@ -12,7 +12,6 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] use embassy_stm32::time::khz; use embassy_stm32::{dma, spi}; From 0fb57ef87d678830e2ccb3753432535897bbb1c3 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 22 Dec 2023 17:08:39 +0100 Subject: [PATCH 100/760] Improved documentation * Documented features including all tick rates * Corrected some out-of-date information * Sorted tick rate features * Removed gen_tick.py dependency on toml * Restructured README.md to better explain tick rate, more clearly prioritise time driver docs, correct header levels --- embassy-time/Cargo.toml | 366 ++++++++++++++++++++++++++---------- embassy-time/README.md | 54 +++--- embassy-time/gen_tick.py | 23 ++- embassy-time/src/lib.rs | 8 +- embassy-time/src/tick.rs | 396 +++++++++++++++++++-------------------- 5 files changed, 519 insertions(+), 328 deletions(-) diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 6d9b7aa69..534894b20 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -32,204 +32,376 @@ features = ["defmt", "std"] std = ["tick-hz-1_000_000", "critical-section/std"] wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"] -# Display a timestamp of the number of seconds since startup next to defmt log messages -# To use this you must have a time driver provided. +## Display a timestamp of the number of seconds since startup next to defmt log messages +## To use this you must have a time driver provided. defmt-timestamp-uptime = ["defmt"] -# Create a global, generic queue that can be used with any executor -# To use this you must have a time driver provided. -generic-queue = [] - -# Set the number of timers for the generic queue. -# -# At most 1 `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. -# -# When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the -# end user to pick. -generic-queue-8 = ["generic-queue"] -generic-queue-16 = ["generic-queue"] -generic-queue-32 = ["generic-queue"] -generic-queue-64 = ["generic-queue"] -generic-queue-128 = ["generic-queue"] - -# Create a `MockDriver` that can be manually advanced for testing purposes. +## Create a `MockDriver` that can be manually advanced for testing purposes. mock-driver = ["tick-hz-1_000_000"] -# Set the `embassy_time` tick rate. -# -# At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. -# -# If the time driver in use supports using arbitrary tick rates, you can enable one `tick-*` -# feature from your binary crate to set the tick rate. The driver will use configured tick rate. -# If the time driver supports a fixed tick rate, it will enable one feature itself, so you should -# not enable one. Check the time driver documentation for details. -# -# When using embassy-time from libraries, you should *not* enable any `tick-*` feature, to allow the -# end user or the driver to pick. +#! ### Generic Queue + +## Create a global, generic queue that can be used with any executor +## To use this you must have a time driver provided. +generic-queue = [] + +#! The following features set how many timers are used for the generic queue. At most 1 +#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. +#! +#! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the +#! end user to pick. + +## Generic Queue with 8 timers +generic-queue-8 = ["generic-queue"] +## Generic Queue with 16 timers +generic-queue-16 = ["generic-queue"] +## Generic Queue with 32 timers +generic-queue-32 = ["generic-queue"] +## Generic Queue with 64 timers +generic-queue-64 = ["generic-queue"] +## Generic Queue with 128 timers +generic-queue-128 = ["generic-queue"] + +#! ### Tick Rate +#! +#! At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. +#! +#! If the time driver in use supports using arbitrary tick rates, you can enable one `tick-*` +#! feature from your binary crate to set the tick rate. The driver will use configured tick rate. +#! If the time driver supports a fixed tick rate, it will enable one feature itself, so you should +#! not enable one. Check the time driver documentation for details. +#! +#! When using embassy-time from libraries, you should *not* enable any `tick-*` feature, to allow the +#! end user or the driver to pick. +#!

+#! Available tick rates: +#! +#! # BEGIN TICKS # Generated by gen_tick.py. DO NOT EDIT. +## 1Hz Tick Rate tick-hz-1 = [] -tick-hz-10 = [] -tick-hz-100 = [] -tick-hz-1_000 = [] -tick-hz-10_000 = [] -tick-hz-100_000 = [] -tick-hz-1_000_000 = [] -tick-hz-10_000_000 = [] -tick-hz-100_000_000 = [] -tick-hz-1_000_000_000 = [] +## 2Hz Tick Rate tick-hz-2 = [] +## 4Hz Tick Rate tick-hz-4 = [] +## 8Hz Tick Rate tick-hz-8 = [] +## 10Hz Tick Rate +tick-hz-10 = [] +## 16Hz Tick Rate tick-hz-16 = [] +## 32Hz Tick Rate tick-hz-32 = [] +## 64Hz Tick Rate tick-hz-64 = [] +## 100Hz Tick Rate +tick-hz-100 = [] +## 128Hz Tick Rate tick-hz-128 = [] +## 256Hz Tick Rate tick-hz-256 = [] +## 512Hz Tick Rate tick-hz-512 = [] +## 1.0kHz Tick Rate +tick-hz-1_000 = [] +## 1.024kHz Tick Rate tick-hz-1_024 = [] -tick-hz-2_048 = [] -tick-hz-4_096 = [] -tick-hz-8_192 = [] -tick-hz-16_384 = [] -tick-hz-32_768 = [] -tick-hz-65_536 = [] -tick-hz-131_072 = [] -tick-hz-262_144 = [] -tick-hz-524_288 = [] -tick-hz-1_048_576 = [] -tick-hz-2_097_152 = [] -tick-hz-4_194_304 = [] -tick-hz-8_388_608 = [] -tick-hz-16_777_216 = [] +## 2.0kHz Tick Rate tick-hz-2_000 = [] +## 2.048kHz Tick Rate +tick-hz-2_048 = [] +## 4.0kHz Tick Rate tick-hz-4_000 = [] +## 4.096kHz Tick Rate +tick-hz-4_096 = [] +## 8.0kHz Tick Rate tick-hz-8_000 = [] +## 8.192kHz Tick Rate +tick-hz-8_192 = [] +## 10.0kHz Tick Rate +tick-hz-10_000 = [] +## 16.0kHz Tick Rate tick-hz-16_000 = [] -tick-hz-32_000 = [] -tick-hz-64_000 = [] -tick-hz-128_000 = [] -tick-hz-256_000 = [] -tick-hz-512_000 = [] -tick-hz-1_024_000 = [] -tick-hz-2_048_000 = [] -tick-hz-4_096_000 = [] -tick-hz-8_192_000 = [] -tick-hz-16_384_000 = [] -tick-hz-32_768_000 = [] -tick-hz-65_536_000 = [] -tick-hz-131_072_000 = [] -tick-hz-262_144_000 = [] -tick-hz-524_288_000 = [] +## 16.384kHz Tick Rate +tick-hz-16_384 = [] +## 20.0kHz Tick Rate tick-hz-20_000 = [] +## 32.0kHz Tick Rate +tick-hz-32_000 = [] +## 32.768kHz Tick Rate +tick-hz-32_768 = [] +## 40.0kHz Tick Rate tick-hz-40_000 = [] +## 64.0kHz Tick Rate +tick-hz-64_000 = [] +## 65.536kHz Tick Rate +tick-hz-65_536 = [] +## 80.0kHz Tick Rate tick-hz-80_000 = [] +## 100.0kHz Tick Rate +tick-hz-100_000 = [] +## 128.0kHz Tick Rate +tick-hz-128_000 = [] +## 131.072kHz Tick Rate +tick-hz-131_072 = [] +## 160.0kHz Tick Rate tick-hz-160_000 = [] +## 256.0kHz Tick Rate +tick-hz-256_000 = [] +## 262.144kHz Tick Rate +tick-hz-262_144 = [] +## 320.0kHz Tick Rate tick-hz-320_000 = [] +## 512.0kHz Tick Rate +tick-hz-512_000 = [] +## 524.288kHz Tick Rate +tick-hz-524_288 = [] +## 640.0kHz Tick Rate tick-hz-640_000 = [] +## 1.0MHz Tick Rate +tick-hz-1_000_000 = [] +## 1.024MHz Tick Rate +tick-hz-1_024_000 = [] +## 1.048576MHz Tick Rate +tick-hz-1_048_576 = [] +## 1.28MHz Tick Rate tick-hz-1_280_000 = [] -tick-hz-2_560_000 = [] -tick-hz-5_120_000 = [] -tick-hz-10_240_000 = [] -tick-hz-20_480_000 = [] -tick-hz-40_960_000 = [] -tick-hz-81_920_000 = [] -tick-hz-163_840_000 = [] -tick-hz-327_680_000 = [] -tick-hz-655_360_000 = [] -tick-hz-1_310_720_000 = [] -tick-hz-2_621_440_000 = [] -tick-hz-5_242_880_000 = [] +## 2.0MHz Tick Rate tick-hz-2_000_000 = [] +## 2.048MHz Tick Rate +tick-hz-2_048_000 = [] +## 2.097152MHz Tick Rate +tick-hz-2_097_152 = [] +## 2.56MHz Tick Rate +tick-hz-2_560_000 = [] +## 3.0MHz Tick Rate tick-hz-3_000_000 = [] +## 4.0MHz Tick Rate tick-hz-4_000_000 = [] +## 4.096MHz Tick Rate +tick-hz-4_096_000 = [] +## 4.194304MHz Tick Rate +tick-hz-4_194_304 = [] +## 5.12MHz Tick Rate +tick-hz-5_120_000 = [] +## 6.0MHz Tick Rate tick-hz-6_000_000 = [] +## 8.0MHz Tick Rate tick-hz-8_000_000 = [] +## 8.192MHz Tick Rate +tick-hz-8_192_000 = [] +## 8.388608MHz Tick Rate +tick-hz-8_388_608 = [] +## 9.0MHz Tick Rate tick-hz-9_000_000 = [] +## 10.0MHz Tick Rate +tick-hz-10_000_000 = [] +## 10.24MHz Tick Rate +tick-hz-10_240_000 = [] +## 12.0MHz Tick Rate tick-hz-12_000_000 = [] +## 16.0MHz Tick Rate tick-hz-16_000_000 = [] +## 16.384MHz Tick Rate +tick-hz-16_384_000 = [] +## 16.777216MHz Tick Rate +tick-hz-16_777_216 = [] +## 18.0MHz Tick Rate tick-hz-18_000_000 = [] -tick-hz-24_000_000 = [] -tick-hz-32_000_000 = [] -tick-hz-36_000_000 = [] -tick-hz-48_000_000 = [] -tick-hz-64_000_000 = [] -tick-hz-72_000_000 = [] -tick-hz-96_000_000 = [] -tick-hz-128_000_000 = [] -tick-hz-144_000_000 = [] -tick-hz-192_000_000 = [] -tick-hz-256_000_000 = [] -tick-hz-288_000_000 = [] -tick-hz-384_000_000 = [] -tick-hz-512_000_000 = [] -tick-hz-576_000_000 = [] -tick-hz-768_000_000 = [] +## 20.0MHz Tick Rate tick-hz-20_000_000 = [] +## 20.48MHz Tick Rate +tick-hz-20_480_000 = [] +## 24.0MHz Tick Rate +tick-hz-24_000_000 = [] +## 30.0MHz Tick Rate tick-hz-30_000_000 = [] +## 32.0MHz Tick Rate +tick-hz-32_000_000 = [] +## 32.768MHz Tick Rate +tick-hz-32_768_000 = [] +## 36.0MHz Tick Rate +tick-hz-36_000_000 = [] +## 40.0MHz Tick Rate tick-hz-40_000_000 = [] +## 40.96MHz Tick Rate +tick-hz-40_960_000 = [] +## 48.0MHz Tick Rate +tick-hz-48_000_000 = [] +## 50.0MHz Tick Rate tick-hz-50_000_000 = [] +## 60.0MHz Tick Rate tick-hz-60_000_000 = [] +## 64.0MHz Tick Rate +tick-hz-64_000_000 = [] +## 65.536MHz Tick Rate +tick-hz-65_536_000 = [] +## 70.0MHz Tick Rate tick-hz-70_000_000 = [] +## 72.0MHz Tick Rate +tick-hz-72_000_000 = [] +## 80.0MHz Tick Rate tick-hz-80_000_000 = [] +## 81.92MHz Tick Rate +tick-hz-81_920_000 = [] +## 90.0MHz Tick Rate tick-hz-90_000_000 = [] +## 96.0MHz Tick Rate +tick-hz-96_000_000 = [] +## 100.0MHz Tick Rate +tick-hz-100_000_000 = [] +## 110.0MHz Tick Rate tick-hz-110_000_000 = [] +## 120.0MHz Tick Rate tick-hz-120_000_000 = [] +## 128.0MHz Tick Rate +tick-hz-128_000_000 = [] +## 130.0MHz Tick Rate tick-hz-130_000_000 = [] +## 131.072MHz Tick Rate +tick-hz-131_072_000 = [] +## 140.0MHz Tick Rate tick-hz-140_000_000 = [] +## 144.0MHz Tick Rate +tick-hz-144_000_000 = [] +## 150.0MHz Tick Rate tick-hz-150_000_000 = [] +## 160.0MHz Tick Rate tick-hz-160_000_000 = [] +## 163.84MHz Tick Rate +tick-hz-163_840_000 = [] +## 170.0MHz Tick Rate tick-hz-170_000_000 = [] +## 180.0MHz Tick Rate tick-hz-180_000_000 = [] +## 190.0MHz Tick Rate tick-hz-190_000_000 = [] +## 192.0MHz Tick Rate +tick-hz-192_000_000 = [] +## 200.0MHz Tick Rate tick-hz-200_000_000 = [] +## 210.0MHz Tick Rate tick-hz-210_000_000 = [] +## 220.0MHz Tick Rate tick-hz-220_000_000 = [] +## 230.0MHz Tick Rate tick-hz-230_000_000 = [] +## 240.0MHz Tick Rate tick-hz-240_000_000 = [] +## 250.0MHz Tick Rate tick-hz-250_000_000 = [] +## 256.0MHz Tick Rate +tick-hz-256_000_000 = [] +## 260.0MHz Tick Rate tick-hz-260_000_000 = [] +## 262.144MHz Tick Rate +tick-hz-262_144_000 = [] +## 270.0MHz Tick Rate tick-hz-270_000_000 = [] +## 280.0MHz Tick Rate tick-hz-280_000_000 = [] +## 288.0MHz Tick Rate +tick-hz-288_000_000 = [] +## 290.0MHz Tick Rate tick-hz-290_000_000 = [] +## 300.0MHz Tick Rate tick-hz-300_000_000 = [] +## 320.0MHz Tick Rate tick-hz-320_000_000 = [] +## 327.68MHz Tick Rate +tick-hz-327_680_000 = [] +## 340.0MHz Tick Rate tick-hz-340_000_000 = [] +## 360.0MHz Tick Rate tick-hz-360_000_000 = [] +## 380.0MHz Tick Rate tick-hz-380_000_000 = [] +## 384.0MHz Tick Rate +tick-hz-384_000_000 = [] +## 400.0MHz Tick Rate tick-hz-400_000_000 = [] +## 420.0MHz Tick Rate tick-hz-420_000_000 = [] +## 440.0MHz Tick Rate tick-hz-440_000_000 = [] +## 460.0MHz Tick Rate tick-hz-460_000_000 = [] +## 480.0MHz Tick Rate tick-hz-480_000_000 = [] +## 500.0MHz Tick Rate tick-hz-500_000_000 = [] +## 512.0MHz Tick Rate +tick-hz-512_000_000 = [] +## 520.0MHz Tick Rate tick-hz-520_000_000 = [] +## 524.288MHz Tick Rate +tick-hz-524_288_000 = [] +## 540.0MHz Tick Rate tick-hz-540_000_000 = [] +## 560.0MHz Tick Rate tick-hz-560_000_000 = [] +## 576.0MHz Tick Rate +tick-hz-576_000_000 = [] +## 580.0MHz Tick Rate tick-hz-580_000_000 = [] +## 600.0MHz Tick Rate tick-hz-600_000_000 = [] +## 620.0MHz Tick Rate tick-hz-620_000_000 = [] +## 640.0MHz Tick Rate tick-hz-640_000_000 = [] +## 655.36MHz Tick Rate +tick-hz-655_360_000 = [] +## 660.0MHz Tick Rate tick-hz-660_000_000 = [] +## 680.0MHz Tick Rate tick-hz-680_000_000 = [] +## 700.0MHz Tick Rate tick-hz-700_000_000 = [] +## 720.0MHz Tick Rate tick-hz-720_000_000 = [] +## 740.0MHz Tick Rate tick-hz-740_000_000 = [] +## 760.0MHz Tick Rate tick-hz-760_000_000 = [] +## 768.0MHz Tick Rate +tick-hz-768_000_000 = [] +## 780.0MHz Tick Rate tick-hz-780_000_000 = [] +## 800.0MHz Tick Rate tick-hz-800_000_000 = [] +## 820.0MHz Tick Rate tick-hz-820_000_000 = [] +## 840.0MHz Tick Rate tick-hz-840_000_000 = [] +## 860.0MHz Tick Rate tick-hz-860_000_000 = [] +## 880.0MHz Tick Rate tick-hz-880_000_000 = [] +## 900.0MHz Tick Rate tick-hz-900_000_000 = [] +## 920.0MHz Tick Rate tick-hz-920_000_000 = [] +## 940.0MHz Tick Rate tick-hz-940_000_000 = [] +## 960.0MHz Tick Rate tick-hz-960_000_000 = [] +## 980.0MHz Tick Rate tick-hz-980_000_000 = [] +## 1.0GHz Tick Rate +tick-hz-1_000_000_000 = [] +## 1.31072GHz Tick Rate +tick-hz-1_310_720_000 = [] +## 2.62144GHz Tick Rate +tick-hz-2_621_440_000 = [] +## 5.24288GHz Tick Rate +tick-hz-5_242_880_000 = [] # END TICKS +#!
+ [dependencies] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } @@ -243,6 +415,8 @@ critical-section = "1.1" cfg-if = "1.0.0" heapless = "0.8" +document-features = "0.2.7" + # WASM dependencies wasm-bindgen = { version = "0.2.81", optional = true } js-sys = { version = "0.3", optional = true } diff --git a/embassy-time/README.md b/embassy-time/README.md index 2be80ff9c..a4a622700 100644 --- a/embassy-time/README.md +++ b/embassy-time/README.md @@ -3,35 +3,16 @@ Timekeeping, delays and timeouts. Timekeeping is done with elapsed time since system boot. Time is represented in -ticks, where the tick rate is defined by the current driver, usually to match -the tick rate of the hardware. +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 +timing resolution of (1 / tick_rate) seconds. -Tick counts are 64 bits. At the highest supported tick rate of 1Mhz this supports +Tick counts are 64 bits. The default tick rate of 1Mhz supports representing time spans of up to ~584558 years, which is big enough for all practical purposes and allows not having to worry about overflows. -[`Instant`] represents a given instant of time (relative to system boot), and [`Duration`] -represents the duration of a span of time. They implement the math operations you'd expect, -like addition and substraction. - -# Delays and timeouts - -[`Timer`] allows performing async delays. [`Ticker`] allows periodic delays without drifting over time. - -An implementation of the `embedded-hal` delay traits is provided by [`Delay`], for compatibility -with libraries from the ecosystem. - -# Wall-clock time - -The `time` module deals exclusively with a monotonically increasing tick count. -Therefore it has no direct support for wall-clock time ("real life" datetimes -like `2021-08-24 13:33:21`). - -If persistence across reboots is not needed, support can be built on top of -`embassy_time` by storing the offset between "seconds elapsed since boot" -and "seconds since unix epoch". - -# Time driver +## Time driver The `time` module is backed by a global "time driver" specified at build time. Only one driver can be active in a program. @@ -41,3 +22,26 @@ possible for libraries to use `embassy_time` in a driver-agnostic way without requiring generic parameters. For more details, check the [`driver`] module. + +## Instants and Durations + +[`Instant`] represents a given instant of time (relative to system boot), and [`Duration`] +represents the duration of a span of time. They implement the math operations you'd expect, +like addition and substraction. + +## Delays and timeouts + +[`Timer`] allows performing async delays. [`Ticker`] allows periodic delays without drifting over time. + +An implementation of the `embedded-hal` delay traits is provided by [`Delay`], for compatibility +with libraries from the ecosystem. + +## Wall-clock time + +The `time` module deals exclusively with a monotonically increasing tick count. +Therefore it has no direct support for wall-clock time ("real life" datetimes +like `2021-08-24 13:33:21`). + +If persistence across reboots is not needed, support can be built on top of +`embassy_time` by storing the offset between "seconds elapsed since boot" +and "seconds since unix epoch". diff --git a/embassy-time/gen_tick.py b/embassy-time/gen_tick.py index d4a175914..8961fb7e6 100644 --- a/embassy-time/gen_tick.py +++ b/embassy-time/gen_tick.py @@ -1,5 +1,4 @@ import os -import toml from glob import glob abspath = os.path.abspath(__file__) @@ -25,11 +24,11 @@ for i in range(15, 50): ticks.append(20 * i * 1_000_000) seen = set() -ticks = [x for x in ticks if not (x in seen or seen.add(x))] +ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))]) # ========= Update Cargo.toml -things = {f'tick-hz-{hz:_}': [] for hz in ticks} +things = [(hz, f'tick-hz-{hz:_}') for hz in ticks] SEPARATOR_START = '# BEGIN TICKS\n' SEPARATOR_END = '# END TICKS\n' @@ -38,8 +37,22 @@ with open('Cargo.toml', 'r') as f: data = f.read() before, data = data.split(SEPARATOR_START, maxsplit=1) _, after = data.split(SEPARATOR_END, maxsplit=1) -data = before + SEPARATOR_START + HELP + \ - toml.dumps(things) + SEPARATOR_END + after + +data = before + SEPARATOR_START + HELP +for freq, feature in things: + if freq >= 1_000_000_000: + freq_human = f"{freq / 1_000_000_000}GHz" + elif freq >= 1_000_000: + freq_human = f"{freq / 1_000_000}MHz" + elif freq >= 1_000: + freq_human = f"{freq / 1000}kHz" + else: + freq_human = f"{freq}Hz" + + data += f"## {freq_human} Tick Rate\n" + data += f"{feature} = []\n" +data += SEPARATOR_END + after + with open('Cargo.toml', 'w') as f: f.write(data) diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index 82a7ee0df..a59ee68d2 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -6,6 +6,9 @@ #![allow(clippy::new_without_default)] #![warn(missing_docs)] +//! ## Feature flags +#![doc = document_features::document_features!(feature_label = r#"{feature}"#)] + // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -37,10 +40,7 @@ pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; /// Ticks per second of the global timebase. /// -/// This value is specified by the `tick-*` Cargo features, which -/// should be set by the time driver. Some drivers support a fixed tick rate, others -/// allow you to choose a tick rate with Cargo features of their own. You should not -/// set the `tick-*` features for embassy yourself as an end user. +/// This value is specified by the [`tick-*` Cargo features](crate#tick-rate) pub const TICK_HZ: u64 = tick::TICK_HZ; const fn gcd(a: u64, b: u64) -> u64 { diff --git a/embassy-time/src/tick.rs b/embassy-time/src/tick.rs index 834e7c095..916ae9498 100644 --- a/embassy-time/src/tick.rs +++ b/embassy-time/src/tick.rs @@ -2,232 +2,204 @@ #[cfg(feature = "tick-hz-1")] pub const TICK_HZ: u64 = 1; -#[cfg(feature = "tick-hz-10")] -pub const TICK_HZ: u64 = 10; -#[cfg(feature = "tick-hz-100")] -pub const TICK_HZ: u64 = 100; -#[cfg(feature = "tick-hz-1_000")] -pub const TICK_HZ: u64 = 1_000; -#[cfg(feature = "tick-hz-10_000")] -pub const TICK_HZ: u64 = 10_000; -#[cfg(feature = "tick-hz-100_000")] -pub const TICK_HZ: u64 = 100_000; -#[cfg(feature = "tick-hz-1_000_000")] -pub const TICK_HZ: u64 = 1_000_000; -#[cfg(feature = "tick-hz-10_000_000")] -pub const TICK_HZ: u64 = 10_000_000; -#[cfg(feature = "tick-hz-100_000_000")] -pub const TICK_HZ: u64 = 100_000_000; -#[cfg(feature = "tick-hz-1_000_000_000")] -pub const TICK_HZ: u64 = 1_000_000_000; #[cfg(feature = "tick-hz-2")] pub const TICK_HZ: u64 = 2; #[cfg(feature = "tick-hz-4")] pub const TICK_HZ: u64 = 4; #[cfg(feature = "tick-hz-8")] pub const TICK_HZ: u64 = 8; +#[cfg(feature = "tick-hz-10")] +pub const TICK_HZ: u64 = 10; #[cfg(feature = "tick-hz-16")] pub const TICK_HZ: u64 = 16; #[cfg(feature = "tick-hz-32")] pub const TICK_HZ: u64 = 32; #[cfg(feature = "tick-hz-64")] pub const TICK_HZ: u64 = 64; +#[cfg(feature = "tick-hz-100")] +pub const TICK_HZ: u64 = 100; #[cfg(feature = "tick-hz-128")] pub const TICK_HZ: u64 = 128; #[cfg(feature = "tick-hz-256")] pub const TICK_HZ: u64 = 256; #[cfg(feature = "tick-hz-512")] pub const TICK_HZ: u64 = 512; +#[cfg(feature = "tick-hz-1_000")] +pub const TICK_HZ: u64 = 1_000; #[cfg(feature = "tick-hz-1_024")] pub const TICK_HZ: u64 = 1_024; -#[cfg(feature = "tick-hz-2_048")] -pub const TICK_HZ: u64 = 2_048; -#[cfg(feature = "tick-hz-4_096")] -pub const TICK_HZ: u64 = 4_096; -#[cfg(feature = "tick-hz-8_192")] -pub const TICK_HZ: u64 = 8_192; -#[cfg(feature = "tick-hz-16_384")] -pub const TICK_HZ: u64 = 16_384; -#[cfg(feature = "tick-hz-32_768")] -pub const TICK_HZ: u64 = 32_768; -#[cfg(feature = "tick-hz-65_536")] -pub const TICK_HZ: u64 = 65_536; -#[cfg(feature = "tick-hz-131_072")] -pub const TICK_HZ: u64 = 131_072; -#[cfg(feature = "tick-hz-262_144")] -pub const TICK_HZ: u64 = 262_144; -#[cfg(feature = "tick-hz-524_288")] -pub const TICK_HZ: u64 = 524_288; -#[cfg(feature = "tick-hz-1_048_576")] -pub const TICK_HZ: u64 = 1_048_576; -#[cfg(feature = "tick-hz-2_097_152")] -pub const TICK_HZ: u64 = 2_097_152; -#[cfg(feature = "tick-hz-4_194_304")] -pub const TICK_HZ: u64 = 4_194_304; -#[cfg(feature = "tick-hz-8_388_608")] -pub const TICK_HZ: u64 = 8_388_608; -#[cfg(feature = "tick-hz-16_777_216")] -pub const TICK_HZ: u64 = 16_777_216; #[cfg(feature = "tick-hz-2_000")] pub const TICK_HZ: u64 = 2_000; +#[cfg(feature = "tick-hz-2_048")] +pub const TICK_HZ: u64 = 2_048; #[cfg(feature = "tick-hz-4_000")] pub const TICK_HZ: u64 = 4_000; +#[cfg(feature = "tick-hz-4_096")] +pub const TICK_HZ: u64 = 4_096; #[cfg(feature = "tick-hz-8_000")] pub const TICK_HZ: u64 = 8_000; +#[cfg(feature = "tick-hz-8_192")] +pub const TICK_HZ: u64 = 8_192; +#[cfg(feature = "tick-hz-10_000")] +pub const TICK_HZ: u64 = 10_000; #[cfg(feature = "tick-hz-16_000")] pub const TICK_HZ: u64 = 16_000; -#[cfg(feature = "tick-hz-32_000")] -pub const TICK_HZ: u64 = 32_000; -#[cfg(feature = "tick-hz-64_000")] -pub const TICK_HZ: u64 = 64_000; -#[cfg(feature = "tick-hz-128_000")] -pub const TICK_HZ: u64 = 128_000; -#[cfg(feature = "tick-hz-256_000")] -pub const TICK_HZ: u64 = 256_000; -#[cfg(feature = "tick-hz-512_000")] -pub const TICK_HZ: u64 = 512_000; -#[cfg(feature = "tick-hz-1_024_000")] -pub const TICK_HZ: u64 = 1_024_000; -#[cfg(feature = "tick-hz-2_048_000")] -pub const TICK_HZ: u64 = 2_048_000; -#[cfg(feature = "tick-hz-4_096_000")] -pub const TICK_HZ: u64 = 4_096_000; -#[cfg(feature = "tick-hz-8_192_000")] -pub const TICK_HZ: u64 = 8_192_000; -#[cfg(feature = "tick-hz-16_384_000")] -pub const TICK_HZ: u64 = 16_384_000; -#[cfg(feature = "tick-hz-32_768_000")] -pub const TICK_HZ: u64 = 32_768_000; -#[cfg(feature = "tick-hz-65_536_000")] -pub const TICK_HZ: u64 = 65_536_000; -#[cfg(feature = "tick-hz-131_072_000")] -pub const TICK_HZ: u64 = 131_072_000; -#[cfg(feature = "tick-hz-262_144_000")] -pub const TICK_HZ: u64 = 262_144_000; -#[cfg(feature = "tick-hz-524_288_000")] -pub const TICK_HZ: u64 = 524_288_000; +#[cfg(feature = "tick-hz-16_384")] +pub const TICK_HZ: u64 = 16_384; #[cfg(feature = "tick-hz-20_000")] pub const TICK_HZ: u64 = 20_000; +#[cfg(feature = "tick-hz-32_000")] +pub const TICK_HZ: u64 = 32_000; +#[cfg(feature = "tick-hz-32_768")] +pub const TICK_HZ: u64 = 32_768; #[cfg(feature = "tick-hz-40_000")] pub const TICK_HZ: u64 = 40_000; +#[cfg(feature = "tick-hz-64_000")] +pub const TICK_HZ: u64 = 64_000; +#[cfg(feature = "tick-hz-65_536")] +pub const TICK_HZ: u64 = 65_536; #[cfg(feature = "tick-hz-80_000")] pub const TICK_HZ: u64 = 80_000; +#[cfg(feature = "tick-hz-100_000")] +pub const TICK_HZ: u64 = 100_000; +#[cfg(feature = "tick-hz-128_000")] +pub const TICK_HZ: u64 = 128_000; +#[cfg(feature = "tick-hz-131_072")] +pub const TICK_HZ: u64 = 131_072; #[cfg(feature = "tick-hz-160_000")] pub const TICK_HZ: u64 = 160_000; +#[cfg(feature = "tick-hz-256_000")] +pub const TICK_HZ: u64 = 256_000; +#[cfg(feature = "tick-hz-262_144")] +pub const TICK_HZ: u64 = 262_144; #[cfg(feature = "tick-hz-320_000")] pub const TICK_HZ: u64 = 320_000; +#[cfg(feature = "tick-hz-512_000")] +pub const TICK_HZ: u64 = 512_000; +#[cfg(feature = "tick-hz-524_288")] +pub const TICK_HZ: u64 = 524_288; #[cfg(feature = "tick-hz-640_000")] pub const TICK_HZ: u64 = 640_000; +#[cfg(feature = "tick-hz-1_000_000")] +pub const TICK_HZ: u64 = 1_000_000; +#[cfg(feature = "tick-hz-1_024_000")] +pub const TICK_HZ: u64 = 1_024_000; +#[cfg(feature = "tick-hz-1_048_576")] +pub const TICK_HZ: u64 = 1_048_576; #[cfg(feature = "tick-hz-1_280_000")] pub const TICK_HZ: u64 = 1_280_000; -#[cfg(feature = "tick-hz-2_560_000")] -pub const TICK_HZ: u64 = 2_560_000; -#[cfg(feature = "tick-hz-5_120_000")] -pub const TICK_HZ: u64 = 5_120_000; -#[cfg(feature = "tick-hz-10_240_000")] -pub const TICK_HZ: u64 = 10_240_000; -#[cfg(feature = "tick-hz-20_480_000")] -pub const TICK_HZ: u64 = 20_480_000; -#[cfg(feature = "tick-hz-40_960_000")] -pub const TICK_HZ: u64 = 40_960_000; -#[cfg(feature = "tick-hz-81_920_000")] -pub const TICK_HZ: u64 = 81_920_000; -#[cfg(feature = "tick-hz-163_840_000")] -pub const TICK_HZ: u64 = 163_840_000; -#[cfg(feature = "tick-hz-327_680_000")] -pub const TICK_HZ: u64 = 327_680_000; -#[cfg(feature = "tick-hz-655_360_000")] -pub const TICK_HZ: u64 = 655_360_000; -#[cfg(feature = "tick-hz-1_310_720_000")] -pub const TICK_HZ: u64 = 1_310_720_000; -#[cfg(feature = "tick-hz-2_621_440_000")] -pub const TICK_HZ: u64 = 2_621_440_000; -#[cfg(feature = "tick-hz-5_242_880_000")] -pub const TICK_HZ: u64 = 5_242_880_000; #[cfg(feature = "tick-hz-2_000_000")] pub const TICK_HZ: u64 = 2_000_000; +#[cfg(feature = "tick-hz-2_048_000")] +pub const TICK_HZ: u64 = 2_048_000; +#[cfg(feature = "tick-hz-2_097_152")] +pub const TICK_HZ: u64 = 2_097_152; +#[cfg(feature = "tick-hz-2_560_000")] +pub const TICK_HZ: u64 = 2_560_000; #[cfg(feature = "tick-hz-3_000_000")] pub const TICK_HZ: u64 = 3_000_000; #[cfg(feature = "tick-hz-4_000_000")] pub const TICK_HZ: u64 = 4_000_000; +#[cfg(feature = "tick-hz-4_096_000")] +pub const TICK_HZ: u64 = 4_096_000; +#[cfg(feature = "tick-hz-4_194_304")] +pub const TICK_HZ: u64 = 4_194_304; +#[cfg(feature = "tick-hz-5_120_000")] +pub const TICK_HZ: u64 = 5_120_000; #[cfg(feature = "tick-hz-6_000_000")] pub const TICK_HZ: u64 = 6_000_000; #[cfg(feature = "tick-hz-8_000_000")] pub const TICK_HZ: u64 = 8_000_000; +#[cfg(feature = "tick-hz-8_192_000")] +pub const TICK_HZ: u64 = 8_192_000; +#[cfg(feature = "tick-hz-8_388_608")] +pub const TICK_HZ: u64 = 8_388_608; #[cfg(feature = "tick-hz-9_000_000")] pub const TICK_HZ: u64 = 9_000_000; +#[cfg(feature = "tick-hz-10_000_000")] +pub const TICK_HZ: u64 = 10_000_000; +#[cfg(feature = "tick-hz-10_240_000")] +pub const TICK_HZ: u64 = 10_240_000; #[cfg(feature = "tick-hz-12_000_000")] pub const TICK_HZ: u64 = 12_000_000; #[cfg(feature = "tick-hz-16_000_000")] pub const TICK_HZ: u64 = 16_000_000; +#[cfg(feature = "tick-hz-16_384_000")] +pub const TICK_HZ: u64 = 16_384_000; +#[cfg(feature = "tick-hz-16_777_216")] +pub const TICK_HZ: u64 = 16_777_216; #[cfg(feature = "tick-hz-18_000_000")] pub const TICK_HZ: u64 = 18_000_000; -#[cfg(feature = "tick-hz-24_000_000")] -pub const TICK_HZ: u64 = 24_000_000; -#[cfg(feature = "tick-hz-32_000_000")] -pub const TICK_HZ: u64 = 32_000_000; -#[cfg(feature = "tick-hz-36_000_000")] -pub const TICK_HZ: u64 = 36_000_000; -#[cfg(feature = "tick-hz-48_000_000")] -pub const TICK_HZ: u64 = 48_000_000; -#[cfg(feature = "tick-hz-64_000_000")] -pub const TICK_HZ: u64 = 64_000_000; -#[cfg(feature = "tick-hz-72_000_000")] -pub const TICK_HZ: u64 = 72_000_000; -#[cfg(feature = "tick-hz-96_000_000")] -pub const TICK_HZ: u64 = 96_000_000; -#[cfg(feature = "tick-hz-128_000_000")] -pub const TICK_HZ: u64 = 128_000_000; -#[cfg(feature = "tick-hz-144_000_000")] -pub const TICK_HZ: u64 = 144_000_000; -#[cfg(feature = "tick-hz-192_000_000")] -pub const TICK_HZ: u64 = 192_000_000; -#[cfg(feature = "tick-hz-256_000_000")] -pub const TICK_HZ: u64 = 256_000_000; -#[cfg(feature = "tick-hz-288_000_000")] -pub const TICK_HZ: u64 = 288_000_000; -#[cfg(feature = "tick-hz-384_000_000")] -pub const TICK_HZ: u64 = 384_000_000; -#[cfg(feature = "tick-hz-512_000_000")] -pub const TICK_HZ: u64 = 512_000_000; -#[cfg(feature = "tick-hz-576_000_000")] -pub const TICK_HZ: u64 = 576_000_000; -#[cfg(feature = "tick-hz-768_000_000")] -pub const TICK_HZ: u64 = 768_000_000; #[cfg(feature = "tick-hz-20_000_000")] pub const TICK_HZ: u64 = 20_000_000; +#[cfg(feature = "tick-hz-20_480_000")] +pub const TICK_HZ: u64 = 20_480_000; +#[cfg(feature = "tick-hz-24_000_000")] +pub const TICK_HZ: u64 = 24_000_000; #[cfg(feature = "tick-hz-30_000_000")] pub const TICK_HZ: u64 = 30_000_000; +#[cfg(feature = "tick-hz-32_000_000")] +pub const TICK_HZ: u64 = 32_000_000; +#[cfg(feature = "tick-hz-32_768_000")] +pub const TICK_HZ: u64 = 32_768_000; +#[cfg(feature = "tick-hz-36_000_000")] +pub const TICK_HZ: u64 = 36_000_000; #[cfg(feature = "tick-hz-40_000_000")] pub const TICK_HZ: u64 = 40_000_000; +#[cfg(feature = "tick-hz-40_960_000")] +pub const TICK_HZ: u64 = 40_960_000; +#[cfg(feature = "tick-hz-48_000_000")] +pub const TICK_HZ: u64 = 48_000_000; #[cfg(feature = "tick-hz-50_000_000")] pub const TICK_HZ: u64 = 50_000_000; #[cfg(feature = "tick-hz-60_000_000")] pub const TICK_HZ: u64 = 60_000_000; +#[cfg(feature = "tick-hz-64_000_000")] +pub const TICK_HZ: u64 = 64_000_000; +#[cfg(feature = "tick-hz-65_536_000")] +pub const TICK_HZ: u64 = 65_536_000; #[cfg(feature = "tick-hz-70_000_000")] pub const TICK_HZ: u64 = 70_000_000; +#[cfg(feature = "tick-hz-72_000_000")] +pub const TICK_HZ: u64 = 72_000_000; #[cfg(feature = "tick-hz-80_000_000")] pub const TICK_HZ: u64 = 80_000_000; +#[cfg(feature = "tick-hz-81_920_000")] +pub const TICK_HZ: u64 = 81_920_000; #[cfg(feature = "tick-hz-90_000_000")] pub const TICK_HZ: u64 = 90_000_000; +#[cfg(feature = "tick-hz-96_000_000")] +pub const TICK_HZ: u64 = 96_000_000; +#[cfg(feature = "tick-hz-100_000_000")] +pub const TICK_HZ: u64 = 100_000_000; #[cfg(feature = "tick-hz-110_000_000")] pub const TICK_HZ: u64 = 110_000_000; #[cfg(feature = "tick-hz-120_000_000")] pub const TICK_HZ: u64 = 120_000_000; +#[cfg(feature = "tick-hz-128_000_000")] +pub const TICK_HZ: u64 = 128_000_000; #[cfg(feature = "tick-hz-130_000_000")] pub const TICK_HZ: u64 = 130_000_000; +#[cfg(feature = "tick-hz-131_072_000")] +pub const TICK_HZ: u64 = 131_072_000; #[cfg(feature = "tick-hz-140_000_000")] pub const TICK_HZ: u64 = 140_000_000; +#[cfg(feature = "tick-hz-144_000_000")] +pub const TICK_HZ: u64 = 144_000_000; #[cfg(feature = "tick-hz-150_000_000")] pub const TICK_HZ: u64 = 150_000_000; #[cfg(feature = "tick-hz-160_000_000")] pub const TICK_HZ: u64 = 160_000_000; +#[cfg(feature = "tick-hz-163_840_000")] +pub const TICK_HZ: u64 = 163_840_000; #[cfg(feature = "tick-hz-170_000_000")] pub const TICK_HZ: u64 = 170_000_000; #[cfg(feature = "tick-hz-180_000_000")] pub const TICK_HZ: u64 = 180_000_000; #[cfg(feature = "tick-hz-190_000_000")] pub const TICK_HZ: u64 = 190_000_000; +#[cfg(feature = "tick-hz-192_000_000")] +pub const TICK_HZ: u64 = 192_000_000; #[cfg(feature = "tick-hz-200_000_000")] pub const TICK_HZ: u64 = 200_000_000; #[cfg(feature = "tick-hz-210_000_000")] @@ -240,24 +212,34 @@ pub const TICK_HZ: u64 = 230_000_000; pub const TICK_HZ: u64 = 240_000_000; #[cfg(feature = "tick-hz-250_000_000")] pub const TICK_HZ: u64 = 250_000_000; +#[cfg(feature = "tick-hz-256_000_000")] +pub const TICK_HZ: u64 = 256_000_000; #[cfg(feature = "tick-hz-260_000_000")] pub const TICK_HZ: u64 = 260_000_000; +#[cfg(feature = "tick-hz-262_144_000")] +pub const TICK_HZ: u64 = 262_144_000; #[cfg(feature = "tick-hz-270_000_000")] pub const TICK_HZ: u64 = 270_000_000; #[cfg(feature = "tick-hz-280_000_000")] pub const TICK_HZ: u64 = 280_000_000; +#[cfg(feature = "tick-hz-288_000_000")] +pub const TICK_HZ: u64 = 288_000_000; #[cfg(feature = "tick-hz-290_000_000")] pub const TICK_HZ: u64 = 290_000_000; #[cfg(feature = "tick-hz-300_000_000")] pub const TICK_HZ: u64 = 300_000_000; #[cfg(feature = "tick-hz-320_000_000")] pub const TICK_HZ: u64 = 320_000_000; +#[cfg(feature = "tick-hz-327_680_000")] +pub const TICK_HZ: u64 = 327_680_000; #[cfg(feature = "tick-hz-340_000_000")] pub const TICK_HZ: u64 = 340_000_000; #[cfg(feature = "tick-hz-360_000_000")] pub const TICK_HZ: u64 = 360_000_000; #[cfg(feature = "tick-hz-380_000_000")] pub const TICK_HZ: u64 = 380_000_000; +#[cfg(feature = "tick-hz-384_000_000")] +pub const TICK_HZ: u64 = 384_000_000; #[cfg(feature = "tick-hz-400_000_000")] pub const TICK_HZ: u64 = 400_000_000; #[cfg(feature = "tick-hz-420_000_000")] @@ -270,12 +252,18 @@ pub const TICK_HZ: u64 = 460_000_000; pub const TICK_HZ: u64 = 480_000_000; #[cfg(feature = "tick-hz-500_000_000")] pub const TICK_HZ: u64 = 500_000_000; +#[cfg(feature = "tick-hz-512_000_000")] +pub const TICK_HZ: u64 = 512_000_000; #[cfg(feature = "tick-hz-520_000_000")] pub const TICK_HZ: u64 = 520_000_000; +#[cfg(feature = "tick-hz-524_288_000")] +pub const TICK_HZ: u64 = 524_288_000; #[cfg(feature = "tick-hz-540_000_000")] pub const TICK_HZ: u64 = 540_000_000; #[cfg(feature = "tick-hz-560_000_000")] pub const TICK_HZ: u64 = 560_000_000; +#[cfg(feature = "tick-hz-576_000_000")] +pub const TICK_HZ: u64 = 576_000_000; #[cfg(feature = "tick-hz-580_000_000")] pub const TICK_HZ: u64 = 580_000_000; #[cfg(feature = "tick-hz-600_000_000")] @@ -284,6 +272,8 @@ pub const TICK_HZ: u64 = 600_000_000; pub const TICK_HZ: u64 = 620_000_000; #[cfg(feature = "tick-hz-640_000_000")] pub const TICK_HZ: u64 = 640_000_000; +#[cfg(feature = "tick-hz-655_360_000")] +pub const TICK_HZ: u64 = 655_360_000; #[cfg(feature = "tick-hz-660_000_000")] pub const TICK_HZ: u64 = 660_000_000; #[cfg(feature = "tick-hz-680_000_000")] @@ -296,6 +286,8 @@ pub const TICK_HZ: u64 = 720_000_000; pub const TICK_HZ: u64 = 740_000_000; #[cfg(feature = "tick-hz-760_000_000")] pub const TICK_HZ: u64 = 760_000_000; +#[cfg(feature = "tick-hz-768_000_000")] +pub const TICK_HZ: u64 = 768_000_000; #[cfg(feature = "tick-hz-780_000_000")] pub const TICK_HZ: u64 = 780_000_000; #[cfg(feature = "tick-hz-800_000_000")] @@ -318,155 +310,159 @@ pub const TICK_HZ: u64 = 940_000_000; pub const TICK_HZ: u64 = 960_000_000; #[cfg(feature = "tick-hz-980_000_000")] pub const TICK_HZ: u64 = 980_000_000; +#[cfg(feature = "tick-hz-1_000_000_000")] +pub const TICK_HZ: u64 = 1_000_000_000; +#[cfg(feature = "tick-hz-1_310_720_000")] +pub const TICK_HZ: u64 = 1_310_720_000; +#[cfg(feature = "tick-hz-2_621_440_000")] +pub const TICK_HZ: u64 = 2_621_440_000; +#[cfg(feature = "tick-hz-5_242_880_000")] +pub const TICK_HZ: u64 = 5_242_880_000; #[cfg(not(any( feature = "tick-hz-1", - feature = "tick-hz-10", - feature = "tick-hz-100", - feature = "tick-hz-1_000", - feature = "tick-hz-10_000", - feature = "tick-hz-100_000", - feature = "tick-hz-1_000_000", - feature = "tick-hz-10_000_000", - feature = "tick-hz-100_000_000", - feature = "tick-hz-1_000_000_000", feature = "tick-hz-2", feature = "tick-hz-4", feature = "tick-hz-8", + feature = "tick-hz-10", feature = "tick-hz-16", feature = "tick-hz-32", feature = "tick-hz-64", + feature = "tick-hz-100", feature = "tick-hz-128", feature = "tick-hz-256", feature = "tick-hz-512", + feature = "tick-hz-1_000", feature = "tick-hz-1_024", - feature = "tick-hz-2_048", - feature = "tick-hz-4_096", - feature = "tick-hz-8_192", - feature = "tick-hz-16_384", - feature = "tick-hz-32_768", - feature = "tick-hz-65_536", - feature = "tick-hz-131_072", - feature = "tick-hz-262_144", - feature = "tick-hz-524_288", - feature = "tick-hz-1_048_576", - feature = "tick-hz-2_097_152", - feature = "tick-hz-4_194_304", - feature = "tick-hz-8_388_608", - feature = "tick-hz-16_777_216", feature = "tick-hz-2_000", + feature = "tick-hz-2_048", feature = "tick-hz-4_000", + feature = "tick-hz-4_096", feature = "tick-hz-8_000", + feature = "tick-hz-8_192", + feature = "tick-hz-10_000", feature = "tick-hz-16_000", - feature = "tick-hz-32_000", - feature = "tick-hz-64_000", - feature = "tick-hz-128_000", - feature = "tick-hz-256_000", - feature = "tick-hz-512_000", - feature = "tick-hz-1_024_000", - feature = "tick-hz-2_048_000", - feature = "tick-hz-4_096_000", - feature = "tick-hz-8_192_000", - feature = "tick-hz-16_384_000", - feature = "tick-hz-32_768_000", - feature = "tick-hz-65_536_000", - feature = "tick-hz-131_072_000", - feature = "tick-hz-262_144_000", - feature = "tick-hz-524_288_000", + feature = "tick-hz-16_384", feature = "tick-hz-20_000", + feature = "tick-hz-32_000", + feature = "tick-hz-32_768", feature = "tick-hz-40_000", + feature = "tick-hz-64_000", + feature = "tick-hz-65_536", feature = "tick-hz-80_000", + feature = "tick-hz-100_000", + feature = "tick-hz-128_000", + feature = "tick-hz-131_072", feature = "tick-hz-160_000", + feature = "tick-hz-256_000", + feature = "tick-hz-262_144", feature = "tick-hz-320_000", + feature = "tick-hz-512_000", + feature = "tick-hz-524_288", feature = "tick-hz-640_000", + feature = "tick-hz-1_000_000", + feature = "tick-hz-1_024_000", + feature = "tick-hz-1_048_576", feature = "tick-hz-1_280_000", - feature = "tick-hz-2_560_000", - feature = "tick-hz-5_120_000", - feature = "tick-hz-10_240_000", - feature = "tick-hz-20_480_000", - feature = "tick-hz-40_960_000", - feature = "tick-hz-81_920_000", - feature = "tick-hz-163_840_000", - feature = "tick-hz-327_680_000", - feature = "tick-hz-655_360_000", - feature = "tick-hz-1_310_720_000", - feature = "tick-hz-2_621_440_000", - feature = "tick-hz-5_242_880_000", feature = "tick-hz-2_000_000", + feature = "tick-hz-2_048_000", + feature = "tick-hz-2_097_152", + feature = "tick-hz-2_560_000", feature = "tick-hz-3_000_000", feature = "tick-hz-4_000_000", + feature = "tick-hz-4_096_000", + feature = "tick-hz-4_194_304", + feature = "tick-hz-5_120_000", feature = "tick-hz-6_000_000", feature = "tick-hz-8_000_000", + feature = "tick-hz-8_192_000", + feature = "tick-hz-8_388_608", feature = "tick-hz-9_000_000", + feature = "tick-hz-10_000_000", + feature = "tick-hz-10_240_000", feature = "tick-hz-12_000_000", feature = "tick-hz-16_000_000", + feature = "tick-hz-16_384_000", + feature = "tick-hz-16_777_216", feature = "tick-hz-18_000_000", - feature = "tick-hz-24_000_000", - feature = "tick-hz-32_000_000", - feature = "tick-hz-36_000_000", - feature = "tick-hz-48_000_000", - feature = "tick-hz-64_000_000", - feature = "tick-hz-72_000_000", - feature = "tick-hz-96_000_000", - feature = "tick-hz-128_000_000", - feature = "tick-hz-144_000_000", - feature = "tick-hz-192_000_000", - feature = "tick-hz-256_000_000", - feature = "tick-hz-288_000_000", - feature = "tick-hz-384_000_000", - feature = "tick-hz-512_000_000", - feature = "tick-hz-576_000_000", - feature = "tick-hz-768_000_000", feature = "tick-hz-20_000_000", + feature = "tick-hz-20_480_000", + feature = "tick-hz-24_000_000", feature = "tick-hz-30_000_000", + feature = "tick-hz-32_000_000", + feature = "tick-hz-32_768_000", + feature = "tick-hz-36_000_000", feature = "tick-hz-40_000_000", + feature = "tick-hz-40_960_000", + feature = "tick-hz-48_000_000", feature = "tick-hz-50_000_000", feature = "tick-hz-60_000_000", + feature = "tick-hz-64_000_000", + feature = "tick-hz-65_536_000", feature = "tick-hz-70_000_000", + feature = "tick-hz-72_000_000", feature = "tick-hz-80_000_000", + feature = "tick-hz-81_920_000", feature = "tick-hz-90_000_000", + feature = "tick-hz-96_000_000", + feature = "tick-hz-100_000_000", feature = "tick-hz-110_000_000", feature = "tick-hz-120_000_000", + feature = "tick-hz-128_000_000", feature = "tick-hz-130_000_000", + feature = "tick-hz-131_072_000", feature = "tick-hz-140_000_000", + feature = "tick-hz-144_000_000", feature = "tick-hz-150_000_000", feature = "tick-hz-160_000_000", + feature = "tick-hz-163_840_000", feature = "tick-hz-170_000_000", feature = "tick-hz-180_000_000", feature = "tick-hz-190_000_000", + feature = "tick-hz-192_000_000", feature = "tick-hz-200_000_000", feature = "tick-hz-210_000_000", feature = "tick-hz-220_000_000", feature = "tick-hz-230_000_000", feature = "tick-hz-240_000_000", feature = "tick-hz-250_000_000", + feature = "tick-hz-256_000_000", feature = "tick-hz-260_000_000", + feature = "tick-hz-262_144_000", feature = "tick-hz-270_000_000", feature = "tick-hz-280_000_000", + feature = "tick-hz-288_000_000", feature = "tick-hz-290_000_000", feature = "tick-hz-300_000_000", feature = "tick-hz-320_000_000", + feature = "tick-hz-327_680_000", feature = "tick-hz-340_000_000", feature = "tick-hz-360_000_000", feature = "tick-hz-380_000_000", + feature = "tick-hz-384_000_000", feature = "tick-hz-400_000_000", feature = "tick-hz-420_000_000", feature = "tick-hz-440_000_000", feature = "tick-hz-460_000_000", feature = "tick-hz-480_000_000", feature = "tick-hz-500_000_000", + feature = "tick-hz-512_000_000", feature = "tick-hz-520_000_000", + feature = "tick-hz-524_288_000", feature = "tick-hz-540_000_000", feature = "tick-hz-560_000_000", + feature = "tick-hz-576_000_000", feature = "tick-hz-580_000_000", feature = "tick-hz-600_000_000", feature = "tick-hz-620_000_000", feature = "tick-hz-640_000_000", + feature = "tick-hz-655_360_000", feature = "tick-hz-660_000_000", feature = "tick-hz-680_000_000", feature = "tick-hz-700_000_000", feature = "tick-hz-720_000_000", feature = "tick-hz-740_000_000", feature = "tick-hz-760_000_000", + feature = "tick-hz-768_000_000", feature = "tick-hz-780_000_000", feature = "tick-hz-800_000_000", feature = "tick-hz-820_000_000", @@ -478,5 +474,9 @@ pub const TICK_HZ: u64 = 980_000_000; feature = "tick-hz-940_000_000", feature = "tick-hz-960_000_000", feature = "tick-hz-980_000_000", + feature = "tick-hz-1_000_000_000", + feature = "tick-hz-1_310_720_000", + feature = "tick-hz-2_621_440_000", + feature = "tick-hz-5_242_880_000", )))] pub const TICK_HZ: u64 = 1_000_000; From 5150deb70b171ef536d1d08946e72199c458180b Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 22 Dec 2023 17:33:24 +0100 Subject: [PATCH 101/760] Minor typo corrections --- embassy-time/Cargo.toml | 4 ++-- embassy-time/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 534894b20..7259169cd 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -41,11 +41,11 @@ mock-driver = ["tick-hz-1_000_000"] #! ### Generic Queue -## Create a global, generic queue that can be used with any executor +## Create a global, generic queue that can be used with any executor. ## To use this you must have a time driver provided. generic-queue = [] -#! The following features set how many timers are used for the generic queue. At most 1 +#! The following features set how many timers are used for the generic queue. At most one #! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. #! #! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the diff --git a/embassy-time/README.md b/embassy-time/README.md index a4a622700..a4e150c14 100644 --- a/embassy-time/README.md +++ b/embassy-time/README.md @@ -3,8 +3,8 @@ 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 +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 timing resolution of (1 / tick_rate) seconds. From 6bbc316312b2ba372ea05c52924d99bc4fb5382a Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 22 Dec 2023 19:05:16 +0100 Subject: [PATCH 102/760] [embassy-executor] improved documentation * Feature auto-documentation * Task arena sizes in a
list * Non-documented comment explaining turbowakers with see-also link Further improvements: * Are the task-arena-size-* numbers sizes in bytes? or something else? * Task arena section could benefit from advice about how to choose a suitable size --- embassy-executor/Cargo.toml | 88 +++++++++++++++++++++++++++++----- embassy-executor/README.md | 2 +- embassy-executor/gen_config.py | 6 +++ embassy-executor/src/lib.rs | 3 ++ 4 files changed, 85 insertions(+), 14 deletions(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 4dcd03b0f..c71452398 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -36,6 +36,8 @@ embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macro embassy-time = { version = "0.2", path = "../embassy-time", optional = true} critical-section = "1.1" +document-features = "0.2.7" + # needed for riscv # remove when https://github.com/rust-lang/rust/pull/114499 is merged portable-atomic = { version = "1.5", optional = true } @@ -53,66 +55,126 @@ critical-section = { version = "1.1", features = ["std"] } [features] -# Architecture -_arch = [] # some arch was picked -arch-std = ["_arch", "critical-section/std"] -arch-cortex-m = ["_arch", "dep:cortex-m"] -arch-riscv32 = ["_arch", "dep:portable-atomic"] -arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] - -# Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs) -executor-thread = [] -# Enable the interrupt-mode executor (available in Cortex-M only) -executor-interrupt = [] - -# Enable nightly-only features +## Enable nightly-only features nightly = ["embassy-executor-macros/nightly"] +# Enables turbo wakers, which requires patching core. Not surfaced in the docs by default due to +# being an complicated advanced and undocumented feature. +# See: https://github.com/embassy-rs/embassy/pull/1263 turbowakers = [] +## Use timers from `embassy-time` integrated-timers = ["dep:embassy-time"] +#! ### Architecture +_arch = [] # some arch was picked +## std +arch-std = ["_arch", "critical-section/std"] +## Cortex-M +arch-cortex-m = ["_arch", "dep:cortex-m"] +## RISC-V 32 +arch-riscv32 = ["_arch", "dep:portable-atomic"] +## WASM +arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] + +#! ### Executor + +## Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs) +executor-thread = [] +## Enable the interrupt-mode executor (available in Cortex-M only) +executor-interrupt = [] + +#! ### Task Arena Size +#! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`. +#! +#!
+#! Preconfigured Task Arena Sizes: +#! +#! + # BEGIN AUTOGENERATED CONFIG FEATURES # Generated by gen_config.py. DO NOT EDIT. +## 64 task-arena-size-64 = [] +## 128 task-arena-size-128 = [] +## 192 task-arena-size-192 = [] +## 256 task-arena-size-256 = [] +## 320 task-arena-size-320 = [] +## 384 task-arena-size-384 = [] +## 512 task-arena-size-512 = [] +## 640 task-arena-size-640 = [] +## 768 task-arena-size-768 = [] +## 1024 task-arena-size-1024 = [] +## 1280 task-arena-size-1280 = [] +## 1536 task-arena-size-1536 = [] +## 2048 task-arena-size-2048 = [] +## 2560 task-arena-size-2560 = [] +## 3072 task-arena-size-3072 = [] +## 4096 (default) task-arena-size-4096 = [] # Default +## 5120 task-arena-size-5120 = [] +## 6144 task-arena-size-6144 = [] +## 8192 task-arena-size-8192 = [] +## 10240 task-arena-size-10240 = [] +## 12288 task-arena-size-12288 = [] +## 16384 task-arena-size-16384 = [] +## 20480 task-arena-size-20480 = [] +## 24576 task-arena-size-24576 = [] +## 32768 task-arena-size-32768 = [] +## 40960 task-arena-size-40960 = [] +## 49152 task-arena-size-49152 = [] +## 65536 task-arena-size-65536 = [] +## 81920 task-arena-size-81920 = [] +## 98304 task-arena-size-98304 = [] +## 131072 task-arena-size-131072 = [] +## 163840 task-arena-size-163840 = [] +## 196608 task-arena-size-196608 = [] +## 262144 task-arena-size-262144 = [] +## 327680 task-arena-size-327680 = [] +## 393216 task-arena-size-393216 = [] +## 524288 task-arena-size-524288 = [] +## 655360 task-arena-size-655360 = [] +## 786432 task-arena-size-786432 = [] +## 1048576 task-arena-size-1048576 = [] # END AUTOGENERATED CONFIG FEATURES + +#!
\ No newline at end of file diff --git a/embassy-executor/README.md b/embassy-executor/README.md index 80ecfc71a..aa9d59907 100644 --- a/embassy-executor/README.md +++ b/embassy-executor/README.md @@ -22,7 +22,7 @@ Tasks are allocated from the arena when spawned for the first time. If the task The arena size can be configured in two ways: - Via Cargo features: enable a Cargo feature like `task-arena-size-8192`. Only a selection of values - is available, check `Cargo.toml` for the list. + is available, see [Task Area Sizes](#task-arena-size) for reference. - Via environment variables at build time: set the variable named `EMBASSY_EXECUTOR_TASK_ARENA_SIZE`. For example `EMBASSY_EXECUTOR_TASK_ARENA_SIZE=4321 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`. Any value can be set, unlike with Cargo features. diff --git a/embassy-executor/gen_config.py b/embassy-executor/gen_config.py index e427d29f4..cf32bd530 100644 --- a/embassy-executor/gen_config.py +++ b/embassy-executor/gen_config.py @@ -45,6 +45,12 @@ things = "" for f in features: name = f["name"].replace("_", "-") for val in f["vals"]: + things += f"## {val}" + if val == f["default"]: + things += " (default)\n" + else: + things += "\n" + things += f"{name}-{val} = []" if val == f["default"]: things += " # Default" diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 4c6900a6d..eea118ade 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -3,6 +3,9 @@ #![doc = include_str!("../README.md")] #![warn(missing_docs)] +//! ## Feature flags +#![doc = document_features::document_features!(feature_label = r#"{feature}"#)] + // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; From c1156d73d3f15f8f6c364faabdc2ea7432d21da6 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 22 Dec 2023 19:40:41 +0100 Subject: [PATCH 103/760] Updated driver implementation docs --- embassy-time/src/driver.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs index 81ee1b0f5..2afa454fe 100644 --- a/embassy-time/src/driver.rs +++ b/embassy-time/src/driver.rs @@ -7,11 +7,16 @@ //! - Define a struct `MyDriver` //! - Implement [`Driver`] for it //! - Register it as the global driver with [`time_driver_impl`](crate::time_driver_impl). -//! - Enable the Cargo features `embassy-executor/time` and one of `embassy-time/tick-*` corresponding to the -//! tick rate of your driver. +//! - Enable the Cargo feature `embassy-executor/time` //! -//! If you wish to make the tick rate configurable by the end user, you should do so by exposing your own -//! Cargo features and having each enable the corresponding `embassy-time/tick-*`. +//! If your driver has a single set tick rate, enable the corresponding [`tick-hz-*`](crate#tick-rate) feature, +//! which will prevent users from needing to configure it themselves (or selecting an incorrect configuration). +//! +//! If your driver supports a small number of set tick rates, expose your own cargo features and have each one +//! enable the corresponding `embassy-time/tick-*`. +//! +//! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by +//! enabling a feature on `embassy-time`. //! //! # Linkage details //! From d63590cb61e0fb9164996677be790c4213ef4a9e Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 22 Dec 2023 23:20:43 +0100 Subject: [PATCH 104/760] [embassy-net] Auto-documented feature flags --- embassy-net/Cargo.toml | 17 +++++++++++++++++ embassy-net/src/lib.rs | 3 +++ 2 files changed, 20 insertions(+) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 0c07e3651..e6c5ea74f 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -25,18 +25,34 @@ features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethern default = [] std = [] +## Enable defmt defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03"] +#! Many of the following feature flags are re-exports of smoltcp feature flags. See +#! the [smoltcp feature flag documentation](https://github.com/smoltcp-rs/smoltcp#feature-flags) +#! for more details + +## Enable UDP support udp = ["smoltcp/socket-udp"] +## Enable TCP support tcp = ["smoltcp/socket-tcp"] +## Enable DNS support dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] +## Enable DHCPv4 support dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"] +## Enable DHCPv4 support with hostname dhcpv4-hostname = ["dhcpv4"] +## Enable IPv4 support proto-ipv4 = ["smoltcp/proto-ipv4"] +## Enable IPv6 support proto-ipv6 = ["smoltcp/proto-ipv6"] +## Enable the Ethernet medium medium-ethernet = ["smoltcp/medium-ethernet"] +## Enable the IP medium medium-ip = ["smoltcp/medium-ip"] +## Enable the IEEE 802.15.4 medium medium-ieee802154 = ["smoltcp/medium-ieee802154"] +## Enable IGMP support igmp = ["smoltcp/proto-igmp"] [dependencies] @@ -62,3 +78,4 @@ stable_deref_trait = { version = "1.2.0", default-features = false } futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } atomic-pool = "1.0" embedded-nal-async = { version = "0.7.1" } +document-features = "0.2.7" diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index d970d0332..2cef2232c 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -5,6 +5,9 @@ #![warn(missing_docs)] #![doc = include_str!("../README.md")] +//! ## Feature flags +#![doc = document_features::document_features!(feature_label = r#"{feature}"#)] + #[cfg(not(any(feature = "proto-ipv4", feature = "proto-ipv6")))] compile_error!("You must enable at least one of the following features: proto-ipv4, proto-ipv6"); From 05c8d410a229f838c1acbe415f44f6f0574e1562 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 22 Dec 2023 23:37:29 +0100 Subject: [PATCH 105/760] [embassy-nrf] auto-documented features --- embassy-nrf/Cargo.toml | 63 +++++++++++++++++++++++++++--------------- embassy-nrf/src/lib.rs | 3 ++ 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 970f62b0c..4648d56d9 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -17,6 +17,7 @@ flavors = [ [features] default = ["rt"] +## Cortex-M runtime (enabled by default) rt = [ "nrf52805-pac?/rt", "nrf52810-pac?/rt", @@ -30,45 +31,62 @@ rt = [ "nrf9160-pac?/rt", ] +## Enable features requiring `embassy-time` time = ["dep:embassy-time"] +## Enable defmt defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver/defmt", "embassy-embedded-hal/defmt"] -# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. +## Reexport the PAC for the currently enabled chip at `embassy_nrf::pac` (unstable) +unstable-pac = [] # This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. # If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. # There are no plans to make this stable. -unstable-pac = [] - -nrf52805 = ["nrf52805-pac", "_nrf52"] -nrf52810 = ["nrf52810-pac", "_nrf52"] -nrf52811 = ["nrf52811-pac", "_nrf52"] -nrf52820 = ["nrf52820-pac", "_nrf52"] -nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] -nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] -nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] -nrf5340-app-s = ["_nrf5340-app", "_s"] -nrf5340-app-ns = ["_nrf5340-app", "_ns"] -nrf5340-net = ["_nrf5340-net"] -nrf9160-s = ["_nrf9160", "_s"] -nrf9160-ns = ["_nrf9160", "_ns"] +## Enable GPIO tasks and events gpiote = [] + +## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz time-driver-rtc1 = ["_time-driver"] -# Allow using the NFC pins as regular GPIO pins (P0_09/P0_10 on nRF52, P0_02/P0_03 on nRF53) +## Allow using the NFC pins as regular GPIO pins (P0_09/P0_10 on nRF52, P0_02/P0_03 on nRF53) nfc-pins-as-gpio = [] -# Allow using the RST pin as a regular GPIO pin. -# nrf52805, nrf52810, nrf52811, nrf52832: P0_21 -# nrf52820, nrf52833, nrf52840: P0_18 +## Allow using the RST pin as a regular GPIO pin. +## * nrf52805, nrf52810, nrf52811, nrf52832: P0_21 +## * nrf52820, nrf52833, nrf52840: P0_18 reset-pin-as-gpio = [] -# Implements the MultiwriteNorFlash trait for QSPI. Should only be enabled if your external -# flash supports the semantics described in -# https://docs.rs/embedded-storage/0.3.1/embedded_storage/nor_flash/trait.MultiwriteNorFlash.html +## Implements the MultiwriteNorFlash trait for QSPI. Should only be enabled if your external +## flash supports the semantics described [here](https://docs.rs/embedded-storage/0.3.1/embedded_storage/nor_flash/trait.MultiwriteNorFlash.html) qspi-multiwrite-flash = [] +#! ### Chip selection features +## NRF52805 +nrf52805 = ["nrf52805-pac", "_nrf52"] +## NRF52810 +nrf52810 = ["nrf52810-pac", "_nrf52"] +## NRF52811 +nrf52811 = ["nrf52811-pac", "_nrf52"] +## NRF52820 +nrf52820 = ["nrf52820-pac", "_nrf52"] +## NRF52832 +nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] +## NRF52833 +nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] +## NRF52840 +nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] +## NRF5340-app-s +nrf5340-app-s = ["_nrf5340-app", "_s"] +## NRF5340-app-ns +nrf5340-app-ns = ["_nrf5340-app", "_ns"] +## NRF5340-net +nrf5340-net = ["_nrf5340-net"] +## NRF9160-s +nrf9160-s = ["_nrf9160", "_s"] +## NRF9160-ns +nrf9160-ns = ["_nrf9160", "_ns"] + # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. @@ -114,6 +132,7 @@ fixed = "1.10.0" embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" cfg-if = "1.0.0" +document-features = "0.2.7" nrf52805-pac = { version = "0.12.0", optional = true } nrf52810-pac = { version = "0.12.0", optional = true } diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index e3458e2de..1510b7265 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -3,6 +3,9 @@ #![doc = include_str!("../README.md")] #![warn(missing_docs)] +//! ## Feature flags +#![doc = document_features::document_features!(feature_label = r#"{feature}"#)] + #[cfg(not(any( feature = "nrf51", feature = "nrf52805", From 6a1bdb7e3b86b066e9fa8c0a4c08cc5e7212c6b9 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 22 Dec 2023 23:50:37 +0100 Subject: [PATCH 106/760] [embassy-rp] auto-documented feature flags --- embassy-rp/Cargo.toml | 53 +++++++++++++++++++++++++++---------------- embassy-rp/src/lib.rs | 3 +++ 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 93dad68ce..d185090db 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -14,43 +14,57 @@ flavors = [ [features] default = [ "rt" ] +## Enable the RP runtime. On by default rt = [ "rp-pac/rt" ] +## Enable defmt defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] -# critical section that is safe for multicore use +## critical section that is safe for multicore use critical-section-impl = ["critical-section/restore-state-u8"] -# Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. -# This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. -# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. -# There are no plans to make this stable. +## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. +## This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. +## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. +## There are no plans to make this stable. unstable-pac = [] +## Enable the timer for use with `embassy-time` with a 1MHz tick rate time-driver = [] +## Enable ROM function cache rom-func-cache = [] +## Enable intrinsics intrinsics = [] +## Enable ROM v2 intrinsics rom-v2-intrinsics = [] -# boot2 flash chip support. if none of these is enabled we'll default to w25q080 (used on the pico) -boot2-at25sf128a = [] -boot2-gd25q64cs = [] -boot2-generic-03h = [] -boot2-is25lp080 = [] -boot2-ram-memcpy = [] -boot2-w25q080 = [] -boot2-w25x10cl = [] - -# Allow using QSPI pins as GPIO pins. This is mostly not what you want (because your flash lives there) -# and would add both code and memory overhead when enabled needlessly. +## Allow using QSPI pins as GPIO pins. This is mostly not what you want (because your flash lives there) +## and would add both code and memory overhead when enabled needlessly. qspi-as-gpio = [] -# Indicate code is running from RAM. -# Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP. -# This allows the flash driver to not force pausing execution on both cores when doing flash operations. +## Indicate code is running from RAM. +## Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP. +## This allows the flash driver to not force pausing execution on both cores when doing flash operations. run-from-ram = [] +#! ### boot2 flash chip support +#! If none of these are enabled, w25q080 is used by default (used on the pico) +## AT25SF128a +boot2-at25sf128a = [] +## GD25Q64cs +boot2-gd25q64cs = [] +## generic-03h +boot2-generic-03h = [] +## IS25LP080 +boot2-is25lp080 = [] +## ram-memcpy +boot2-ram-memcpy = [] +## W25Q080 +boot2-w25q080 = [] +## W25X10cl +boot2-w25x10cl = [] + [dependencies] embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-time = { version = "0.2", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } @@ -85,6 +99,7 @@ embedded-hal-nb = { version = "=1.0.0-rc.3" } pio-proc = {version= "0.2" } pio = {version= "0.2.1" } rp2040-boot2 = "0.3" +document-features = "0.2.7" [dev-dependencies] embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index fdacf4965..0a3714777 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -3,6 +3,9 @@ #![doc = include_str!("../README.md")] #![warn(missing_docs)] +//! ## Feature flags +#![doc = document_features::document_features!(feature_label = r#"{feature}"#)] + // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; From 562680cb139fc39d2fbb728c36ea3ce76731ca50 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 22 Dec 2023 23:51:10 +0100 Subject: [PATCH 107/760] Removed unnecessary note --- embassy-rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index d185090db..669d79f40 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -14,7 +14,7 @@ flavors = [ [features] default = [ "rt" ] -## Enable the RP runtime. On by default +## Enable the RP runtime. rt = [ "rp-pac/rt" ] ## Enable defmt From 487a6324ef3897a283bff5356bd511c7f570ed12 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sat, 23 Dec 2023 00:14:10 +0000 Subject: [PATCH 108/760] stm32: make time provider public again --- embassy-stm32/src/rtc/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 40cd752a2..65e8713f0 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -102,7 +102,8 @@ pub enum RtcError { NotRunning, } -pub(crate) struct RtcTimeProvider { +/// Provides immutable access to the current time of the RTC. +pub struct RtcTimeProvider { _private: (), } @@ -243,7 +244,7 @@ impl Rtc { } /// Acquire a [`RtcTimeProvider`] instance. - pub(crate) const fn time_provider(&self) -> RtcTimeProvider { + pub const fn time_provider(&self) -> RtcTimeProvider { RtcTimeProvider { _private: () } } From dcd4e6384e3fab32809d01738ecd84011b4f0cc7 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 23 Dec 2023 19:45:56 +0800 Subject: [PATCH 109/760] enable output compare preload for TIM keep output waveform integrity --- examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index c4181d024..cdce36f2e 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -21,6 +21,7 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::pac; +use embassy_stm32::pac::timer::vals::Ocpe; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::{Channel, CountingMode}; @@ -89,6 +90,12 @@ async fn main(_spawner: Spawner) { let pwm_channel = Channel::Ch1; + // PAC level hacking, enable output compare preload + // keep output waveform integrity + pac::TIM3 + .ccmr_output(pwm_channel.index()) + .modify(|v| v.set_ocpe(0, Ocpe::ENABLED)); + // make sure PWM output keep low on first start ws2812_pwm.set_duty(pwm_channel, 0); From c46b076d5b40ddbe74ddeb7f9296b394c078538f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Dec 2023 15:48:47 +0100 Subject: [PATCH 110/760] nrf: some doc fixes. --- embassy-nrf/Cargo.toml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 4648d56d9..837a941a9 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -53,8 +53,8 @@ time-driver-rtc1 = ["_time-driver"] nfc-pins-as-gpio = [] ## Allow using the RST pin as a regular GPIO pin. -## * nrf52805, nrf52810, nrf52811, nrf52832: P0_21 -## * nrf52820, nrf52833, nrf52840: P0_18 +## * nRF52805, nRF52810, nRF52811, nRF52832: P0_21 +## * nRF52820, nRF52833, nRF52840: P0_18 reset-pin-as-gpio = [] ## Implements the MultiwriteNorFlash trait for QSPI. Should only be enabled if your external @@ -62,29 +62,29 @@ reset-pin-as-gpio = [] qspi-multiwrite-flash = [] #! ### Chip selection features -## NRF52805 +## nRF52805 nrf52805 = ["nrf52805-pac", "_nrf52"] -## NRF52810 +## nRF52810 nrf52810 = ["nrf52810-pac", "_nrf52"] -## NRF52811 +## nRF52811 nrf52811 = ["nrf52811-pac", "_nrf52"] -## NRF52820 +## nRF52820 nrf52820 = ["nrf52820-pac", "_nrf52"] -## NRF52832 +## nRF52832 nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] -## NRF52833 +## nRF52833 nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] -## NRF52840 +## nRF52840 nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] -## NRF5340-app-s +## nRF5340 application core in Secure mode nrf5340-app-s = ["_nrf5340-app", "_s"] -## NRF5340-app-ns +## nRF5340 application core in Non-Secure mode nrf5340-app-ns = ["_nrf5340-app", "_ns"] -## NRF5340-net +## nRF5340 network core nrf5340-net = ["_nrf5340-net"] -## NRF9160-s +## nRF9160 in Secure mode nrf9160-s = ["_nrf9160", "_s"] -## NRF9160-ns +## nRF9160 in Non-Secure mode nrf9160-ns = ["_nrf9160", "_ns"] # Features starting with `_` are for internal use only. They're not intended From 92758c3119739b80373428f0a640e08c1db7e27c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Dec 2023 16:01:08 +0100 Subject: [PATCH 111/760] ci: use nightly for building docs. --- .github/ci/doc.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index ed3036f2f..fbed2752a 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -8,6 +8,7 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target export BUILDER_THREADS=4 export BUILDER_COMPRESS=true +mv rust-toolchain-nightly.toml rust-toolchain.toml # force rustup to download the toolchain before starting building. # Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently. From f625f6b89328a14b0bc31ff35841cff1cf6380d9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Dec 2023 20:41:33 +0100 Subject: [PATCH 112/760] Upgrade to smoltcp v0.11. --- embassy-net/Cargo.toml | 2 +- embassy-net/src/udp.rs | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index e6c5ea74f..612a3d689 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -60,7 +60,7 @@ igmp = ["smoltcp/proto-igmp"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp.git", rev = "b57e2f9e70e82a13f31d5ea17e55232c11cc2b2d", default-features = false, features = [ +smoltcp = { version = "0.11.0", default-features = false, features = [ "socket", "async", ] } diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 61058c1ba..d9df5b29d 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -26,13 +26,21 @@ pub enum BindError { /// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Error { +pub enum SendError { /// No route to host. NoRoute, /// Socket not bound to an outgoing port. SocketNotBound, } +/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. +#[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 UDP socket. pub struct UdpSocket<'a> { stack: &'a RefCell, @@ -103,7 +111,7 @@ impl<'a> UdpSocket<'a> { /// This method will wait until a datagram is received. /// /// Returns the number of bytes received and the remote endpoint. - pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> { + pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), RecvError> { poll_fn(move |cx| self.poll_recv_from(buf, cx)).await } @@ -114,10 +122,11 @@ impl<'a> UdpSocket<'a> { /// /// When a datagram is received, this method will return `Poll::Ready` with the /// number of bytes received and the remote endpoint. - pub fn poll_recv_from(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll> { + pub fn poll_recv_from(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll> { self.with_mut(|s, _| match s.recv_slice(buf) { Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))), // No data ready + Err(udp::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)), Err(udp::RecvError::Exhausted) => { s.register_recv_waker(cx.waker()); Poll::Pending @@ -129,8 +138,8 @@ impl<'a> UdpSocket<'a> { /// /// This method will wait until the datagram has been sent. /// - /// When the remote endpoint is not reachable, this method will return `Err(Error::NoRoute)` - pub async fn send_to(&self, buf: &[u8], remote_endpoint: T) -> Result<(), Error> + /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` + pub async fn send_to(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError> where T: Into, { @@ -146,7 +155,7 @@ impl<'a> UdpSocket<'a> { /// and register the current task to be notified when the buffer has space available. /// /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`. - pub fn poll_send_to(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll> + pub fn poll_send_to(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll> where T: Into, { @@ -160,9 +169,9 @@ impl<'a> UdpSocket<'a> { Err(udp::SendError::Unaddressable) => { // If no sender/outgoing port is specified, there is not really "no route" if s.endpoint().port == 0 { - Poll::Ready(Err(Error::SocketNotBound)) + Poll::Ready(Err(SendError::SocketNotBound)) } else { - Poll::Ready(Err(Error::NoRoute)) + Poll::Ready(Err(SendError::NoRoute)) } } }) From 9ea7a245e9f74faa1ba1f35988d98fc914414609 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Sun, 24 Dec 2023 11:51:16 -0800 Subject: [PATCH 113/760] add some generation resources, add some feature descriptions --- docs/modules/ROOT/pages/new_project.adoc | 25 +++++++++++++------ .../modules/ROOT/pages/project_structure.adoc | 9 +++++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/modules/ROOT/pages/new_project.adoc b/docs/modules/ROOT/pages/new_project.adoc index ce139ed8d..320966bb6 100644 --- a/docs/modules/ROOT/pages/new_project.adoc +++ b/docs/modules/ROOT/pages/new_project.adoc @@ -1,6 +1,17 @@ = Starting a new Embassy project -Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. The easiest way to do this is to adapt an example for a similar chip to the one you’re targeting. +Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. + +There are some tools for generating Embassy projects: (WIP) + +==== CLI +- link:https://github.com/adinack/cargo-embassy[cargo-embassy] (STM32 and NRF) + +==== cargo-generate +- link:https://github.com/lulf/embassy-template[embassy-template] (STM32, NRF, and RP) +- link:https://github.com/bentwire/embassy-rp2040-template[embassy-rp2040-template] (RP) + +But if you want to start from scratch: As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes. @@ -166,13 +177,13 @@ should result in a blinking LED (if there’s one attached to the pin in `src/ma Erasing sectors ✔ [00:00:00] [#########################################################] 18.00 KiB/18.00 KiB @ 54.09 KiB/s (eta 0s ) Programming pages ✔ [00:00:00] [#########################################################] 17.00 KiB/17.00 KiB @ 35.91 KiB/s (eta 0s ) Finished in 0.817s 0.000000 TRACE BDCR configured: 00008200 -└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117 +└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117 0.000000 DEBUG rcc: Clocks { sys: Hertz(16000000), pclk1: Hertz(16000000), pclk1_tim: Hertz(16000000), pclk2: Hertz(16000000), pclk2_tim: Hertz(16000000), hclk1: Hertz(16000000), hclk2: Hertz(16000000), pll1_p: None, adc: None, adc34: None, rtc: Some(Hertz(32000)) } -└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130 +└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130 0.000000 INFO Hello World! -└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14 +└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14 0.000091 INFO high -└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19 +└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19 0.300201 INFO low -└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23 ----- \ No newline at end of file +└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23 +---- diff --git a/docs/modules/ROOT/pages/project_structure.adoc b/docs/modules/ROOT/pages/project_structure.adoc index 3e6008ec4..bdb41d328 100644 --- a/docs/modules/ROOT/pages/project_structure.adoc +++ b/docs/modules/ROOT/pages/project_structure.adoc @@ -38,13 +38,18 @@ DEFMT_LOG = "trace" # <- can change to info, warn, or error === build.rs -This is the build script for your project. It links defmt (what is defmt?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example]. +This is the build script for your project. It links defmt (what is link:https://defmt.ferrous-systems.com[defmt]?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example]. === Cargo.toml This is your manifest file, where you can configure all of the embassy components to use the features you need. -TODO: someone should exhaustively describe every feature for every component! +==== Features +===== Time +- tick-hz-x: Configures the tick rate of `embassy-time`. Higher tick rate means higher precision, and higher CPU wakes. +- defmt-timestamp-uptime: defmt log entries will display the uptime in seconds. + +...more to come === memory.x From d90a97aa4c5977e3d071fb4ed94656e6666d965c Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Mon, 25 Dec 2023 21:29:17 +0800 Subject: [PATCH 114/760] update metapac after stm32-data PR323 and refactor a few code with cargo clippy --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/can/bxcan.rs | 21 ++++++++++----------- embassy-stm32/src/rtc/v2.rs | 8 ++++---- embassy-stm32/src/rtc/v3.rs | 8 ++++---- embassy-stm32/src/spi/mod.rs | 2 +- examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 3 +-- examples/stm32h7/src/bin/dac_dma.rs | 6 +++--- examples/stm32l4/src/bin/dac_dma.rs | 6 +++--- 8 files changed, 28 insertions(+), 30 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 83db7c4bf..16d1cca4c 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2234f380f51d16d0398b8e547088b33ea623cc7c" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8caf2f0bda28baf4393899dc67ba57f058087f5a" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2234f380f51d16d0398b8e547088b33ea623cc7c", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8caf2f0bda28baf4393899dc67ba57f058087f5a", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 3c663b452..cc87b2565 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -1,3 +1,4 @@ +use core::convert::AsMut; use core::future::poll_fn; use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; @@ -10,7 +11,7 @@ use futures::FutureExt; use crate::gpio::sealed::AFType; use crate::interrupt::typelevel::Interrupt; -use crate::pac::can::vals::{Lec, RirIde}; +use crate::pac::can::vals::{Ide, Lec}; use crate::rcc::RccPeripheral; use crate::time::Hertz; use crate::{interrupt, peripherals, Peripheral}; @@ -148,15 +149,11 @@ impl<'d, T: Instance> Can<'d, T> { T::enable_and_reset(); { - use crate::pac::can::vals::{Errie, Fmpie, Tmeie}; - T::regs().ier().write(|w| { - // TODO: fix metapac - - w.set_errie(Errie::from_bits(1)); - w.set_fmpie(0, Fmpie::from_bits(1)); - w.set_fmpie(1, Fmpie::from_bits(1)); - w.set_tmeie(Tmeie::from_bits(1)); + w.set_errie(true); + w.set_fmpie(0, true); + w.set_fmpie(1, true); + w.set_tmeie(true); }); T::regs().mcr().write(|w| { @@ -276,7 +273,7 @@ impl<'d, T: Instance> Can<'d, T> { } let rir = fifo.rir().read(); - let id = if rir.ide() == RirIde::STANDARD { + let id = if rir.ide() == Ide::STANDARD { Id::from(StandardId::new_unchecked(rir.stid())) } else { let stid = (rir.stid() & 0x7FF) as u32; @@ -403,9 +400,11 @@ impl<'d, T: Instance> Can<'d, T> { let (tx, rx0, rx1) = self.can.split_by_ref(); (CanTx { tx }, CanRx { rx0, rx1 }) } +} +impl<'d, T: Instance> AsMut>> for Can<'d, T> { /// Get mutable access to the lower-level driver from the `bxcan` crate. - pub fn as_mut(&mut self) -> &mut bxcan::Can> { + fn as_mut(&mut self) -> &mut bxcan::Can> { &mut self.can } } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 91f08fae4..1eda097a7 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,4 +1,4 @@ -use stm32_metapac::rtc::vals::{Init, Osel, Pol}; +use stm32_metapac::rtc::vals::{Osel, Pol}; use super::sealed; use crate::pac::rtc::Rtc; @@ -49,7 +49,7 @@ impl super::Rtc { clock_drift = RTC_CALR_MAX_PPM; } - clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; + clock_drift /= RTC_CALR_RESOLUTION_PPM; self.write(false, |rtc| { rtc.calr().write(|w| { @@ -107,7 +107,7 @@ impl super::Rtc { // true if initf bit indicates RTC peripheral is in init mode if init_mode && !r.isr().read().initf() { // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode - r.isr().modify(|w| w.set_init(Init::INITMODE)); + r.isr().modify(|w| w.set_init(true)); // wait till init state entered // ~2 RTCCLK cycles while !r.isr().read().initf() {} @@ -116,7 +116,7 @@ impl super::Rtc { let result = f(&r); if init_mode { - r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode + r.isr().modify(|w| w.set_init(false)); // Exits init mode } // Re-enable write protection. diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index d2d0d9309..902776b0a 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,4 +1,4 @@ -use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; +use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; use super::{sealed, RtcCalibrationCyclePeriod}; use crate::pac::rtc::Rtc; @@ -26,7 +26,7 @@ impl super::Rtc { rtc.cr().modify(|w| { w.set_out2en(false); w.set_tampalrm_type(TampalrmType::PUSHPULL); - w.set_tampalrm_pu(TampalrmPu::NOPULLUP); + w.set_tampalrm_pu(false); }); }); } @@ -106,7 +106,7 @@ impl super::Rtc { r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); if init_mode && !r.icsr().read().initf() { - r.icsr().modify(|w| w.set_init(Init::INITMODE)); + r.icsr().modify(|w| w.set_init(true)); // wait till init state entered // ~2 RTCCLK cycles while !r.icsr().read().initf() {} @@ -115,7 +115,7 @@ impl super::Rtc { let result = f(&r); if init_mode { - r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode + r.icsr().modify(|w| w.set_init(false)); // Exits init mode } // Re-enable write protection. diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 674a5d316..23f027e70 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -311,7 +311,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { w.set_ssom(vals::Ssom::ASSERTED); w.set_midi(0); w.set_mssi(0); - w.set_afcntr(vals::Afcntr::CONTROLLED); + w.set_afcntr(true); w.set_ssiop(vals::Ssiop::ACTIVEHIGH); }); T::REGS.cfg1().modify(|w| { diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index cdce36f2e..4458b643f 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs @@ -21,7 +21,6 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::pac; -use embassy_stm32::pac::timer::vals::Ocpe; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::{Channel, CountingMode}; @@ -94,7 +93,7 @@ async fn main(_spawner: Spawner) { // keep output waveform integrity pac::TIM3 .ccmr_output(pwm_channel.index()) - .modify(|v| v.set_ocpe(0, Ocpe::ENABLED)); + .modify(|v| v.set_ocpe(0, true)); // make sure PWM output keep low on first start ws2812_pwm.set_duty(pwm_channel, 0); diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index 1481dd967..8e5c41a43 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; -use embassy_stm32::pac::timer::vals::{Mms, Opm}; +use embassy_stm32::pac::timer::vals::Mms; use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; use embassy_stm32::rcc::low_level::RccPeripheral; use embassy_stm32::time::Hertz; @@ -78,7 +78,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); TIM6::regs().cr1().modify(|w| { - w.set_opm(Opm::DISABLED); + w.set_opm(false); w.set_cen(true); }); @@ -115,7 +115,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); TIM7::regs().cr1().modify(|w| { - w.set_opm(Opm::DISABLED); + w.set_opm(false); w.set_cen(true); }); diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index 64c541caa..8e5098557 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; -use embassy_stm32::pac::timer::vals::{Mms, Opm}; +use embassy_stm32::pac::timer::vals::Mms; use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; use embassy_stm32::rcc::low_level::RccPeripheral; use embassy_stm32::time::Hertz; @@ -49,7 +49,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); TIM6::regs().cr1().modify(|w| { - w.set_opm(Opm::DISABLED); + w.set_opm(false); w.set_cen(true); }); @@ -86,7 +86,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); TIM7::regs().cr1().modify(|w| { - w.set_opm(Opm::DISABLED); + w.set_opm(false); w.set_cen(true); }); From 30023c3bcccaffe4ff16d6600ba5ff80cf1ee488 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Tue, 26 Dec 2023 11:58:38 +0100 Subject: [PATCH 115/760] Add low-power support for stm32l5 --- embassy-stm32/src/rtc/mod.rs | 20 +++++++++++++------- embassy-stm32/src/rtc/v3.rs | 6 ++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 65e8713f0..1ffb567b3 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -24,7 +24,7 @@ use crate::time::Hertz; ), path = "v2.rs" )] -#[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")] +#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5), path = "v3.rs")] mod _version; #[allow(unused_imports)] pub use _version::*; @@ -43,7 +43,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] +#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -57,7 +57,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] +#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -348,7 +348,7 @@ impl Rtc { ) { use embassy_time::{Duration, TICK_HZ}; - #[cfg(any(rtc_v3, rtc_v3u5))] + #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] use crate::pac::rtc::vals::Calrf; // Panic if the rcc mod knows we're not using low-power rtc @@ -375,7 +375,7 @@ impl Rtc { while !regs.isr().read().wutwf() {} } - #[cfg(any(rtc_v3, rtc_v3u5))] + #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] { regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); while !regs.icsr().read().wutwf() {} @@ -404,7 +404,7 @@ impl Rtc { /// was called, otherwise none pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option { use crate::interrupt::typelevel::Interrupt; - #[cfg(any(rtc_v3, rtc_v3u5))] + #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] use crate::pac::rtc::vals::Calrf; let instant = self.instant().unwrap(); @@ -420,13 +420,19 @@ impl Rtc { ))] regs.isr().modify(|w| w.set_wutf(false)); - #[cfg(any(rtc_v3, rtc_v3u5))] + #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); + #[cfg(not(stm32l5))] crate::pac::EXTI .pr(0) .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + #[cfg(stm32l5)] + crate::pac::EXTI + .fpr(0) + .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + ::WakeupInterrupt::unpend(); }); } diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 902776b0a..114141b64 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -135,6 +135,12 @@ impl sealed::Instance for crate::peripherals::RTC { #[cfg(all(feature = "low-power", stm32g4))] type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; + #[cfg(all(feature = "low-power", stm32l5))] + const EXTI_WAKEUP_LINE: usize = 17; + + #[cfg(all(feature = "low-power", stm32l5))] + type WakeupInterrupt = crate::interrupt::typelevel::RTC; + fn read_backup_register(_rtc: &Rtc, register: usize) -> Option { #[allow(clippy::if_same_then_else)] if register < Self::BACKUP_REGISTER_COUNT { From 7fa954c0273623a9ab5181800fe1bb1273bb7982 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Dec 2023 17:35:49 +0100 Subject: [PATCH 116/760] nrf/gpio: add toggle. --- embassy-nrf/src/gpio.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index a47fb8350..27c18383f 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -152,6 +152,12 @@ impl<'d, T: Pin> Output<'d, T> { self.pin.set_low() } + /// Toggle the output level. + #[inline] + pub fn toggle(&mut self) { + self.pin.toggle() + } + /// Set the output level. #[inline] pub fn set_level(&mut self, level: Level) { @@ -310,6 +316,16 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.set_low() } + /// Toggle the output level. + #[inline] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } + } + /// Set the output level. #[inline] pub fn set_level(&mut self, level: Level) { @@ -538,6 +554,15 @@ mod eh02 { } } + impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> { + type Error = Infallible; + #[inline] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } + } + /// Implement [`embedded_hal_02::digital::v2::InputPin`] for [`Flex`]; /// /// If the pin is not in input mode the result is unspecified. @@ -574,6 +599,15 @@ mod eh02 { Ok(self.ref_is_set_low()) } } + + impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> { + type Error = Infallible; + #[inline] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } + } } impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { From dc295fa1db1245ca5ea5241104140ae1e62ea5ac Mon Sep 17 00:00:00 2001 From: lights0123 Date: Tue, 26 Dec 2023 16:34:04 -0500 Subject: [PATCH 117/760] stm32: add half duplex USART driver --- embassy-stm32/src/usart/mod.rs | 87 +++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 8a0c85d2c..ea727b010 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -743,7 +743,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { T::enable_and_reset(); T::enable_and_reset(); - Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) + Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config) } /// Create a new bidirectional UART with request-to-send and clear-to-send pins @@ -770,7 +770,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { w.set_rtse(true); w.set_ctse(true); }); - Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) + Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config) } #[cfg(not(any(usart_v1, usart_v2)))] @@ -795,10 +795,76 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { T::regs().cr3().write(|w| { w.set_dem(true); }); - Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) + Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config) } - fn new_inner( + /// Create a single-wire half-duplex Uart transceiver on a single Tx pin. + /// + /// See [`new_half_duplex_on_rx`][`Self::new_half_duplex_on_rx`] if you would prefer to use an Rx pin. + /// There is no functional difference between these methods, as both allow bidirectional communication. + /// + /// The pin is always released when no data is transmitted. Thus, it acts as a standard + /// I/O in idle or in reception. + /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict + /// on the line must be managed by software (for instance by using a centralized arbiter). + #[cfg(not(any(usart_v1, usart_v2)))] + #[doc(alias("HDSEL"))] + pub fn new_half_duplex( + peri: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + tx_dma: impl Peripheral

+ 'd, + rx_dma: impl Peripheral

+ 'd, + mut config: Config, + ) -> Result { + // UartRx and UartTx have one refcount ea. + T::enable_and_reset(); + T::enable_and_reset(); + + config.swap_rx_tx = false; + + into_ref!(peri, tx, tx_dma, rx_dma); + + T::regs().cr3().write(|w| w.set_hdsel(true)); + tx.set_as_af(tx.af_num(), AFType::OutputPushPull); + + Self::new_inner(peri, tx_dma, rx_dma, config) + } + + /// Create a single-wire half-duplex Uart transceiver on a single Rx pin. + /// + /// See [`new_half_duplex`][`Self::new_half_duplex`] if you would prefer to use an Tx pin. + /// There is no functional difference between these methods, as both allow bidirectional communication. + /// + /// The pin is always released when no data is transmitted. Thus, it acts as a standard + /// I/O in idle or in reception. + /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict + /// on the line must be managed by software (for instance by using a centralized arbiter). + #[cfg(not(any(usart_v1, usart_v2)))] + #[doc(alias("HDSEL"))] + pub fn new_half_duplex_on_rx( + peri: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + tx_dma: impl Peripheral

+ 'd, + rx_dma: impl Peripheral

+ 'd, + mut config: Config, + ) -> Result { + // UartRx and UartTx have one refcount ea. + T::enable_and_reset(); + T::enable_and_reset(); + + config.swap_rx_tx = true; + + into_ref!(peri, rx, tx_dma, rx_dma); + + T::regs().cr3().write(|w| w.set_hdsel(true)); + rx.set_as_af(rx.af_num(), AFType::OutputPushPull); + + Self::new_inner(peri, tx_dma, rx_dma, config) + } + + fn new_inner_configure( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, @@ -808,8 +874,6 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { ) -> Result { into_ref!(peri, rx, tx, tx_dma, rx_dma); - let r = T::regs(); - // Some chips do not have swap_rx_tx bit cfg_if::cfg_if! { if #[cfg(any(usart_v3, usart_v4))] { @@ -827,6 +891,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } + Self::new_inner(peri, tx_dma, rx_dma, config) + } + + fn new_inner( + peri: PeripheralRef<'d, T>, + tx_dma: PeripheralRef<'d, TxDma>, + rx_dma: PeripheralRef<'d, RxDma>, + config: Config, + ) -> Result { + let r = T::regs(); + configure(r, &config, T::frequency(), T::KIND, true, true)?; T::Interrupt::unpend(); From 211f3357b7dcc3a3ff1c956f053917c3c69c5ec3 Mon Sep 17 00:00:00 2001 From: Ben Schattinger Date: Tue, 26 Dec 2023 18:22:54 -0500 Subject: [PATCH 118/760] stm32: USB IN endpoints use IN wakers fixes #2360 --- embassy-stm32/src/usb/usb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index a8aebfe1f..39538beb7 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -704,7 +704,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { trace!("wait_enabled OUT WAITING"); let index = self.info.addr.index(); poll_fn(|cx| { - EP_OUT_WAKERS[index].register(cx.waker()); + EP_IN_WAKERS[index].register(cx.waker()); let regs = T::regs(); if regs.epr(index).read().stat_tx() == Stat::DISABLED { Poll::Pending From 87b23f9037aedb4720ded089d481de1696d91e26 Mon Sep 17 00:00:00 2001 From: Ben Schattinger Date: Tue, 26 Dec 2023 18:26:01 -0500 Subject: [PATCH 119/760] stm32: fix USB wait_enabled IN messages --- embassy-stm32/src/usb/usb.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 39538beb7..04b1b35e8 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -701,7 +701,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { } async fn wait_enabled(&mut self) { - trace!("wait_enabled OUT WAITING"); + trace!("wait_enabled IN WAITING"); let index = self.info.addr.index(); poll_fn(|cx| { EP_IN_WAKERS[index].register(cx.waker()); @@ -713,7 +713,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { } }) .await; - trace!("wait_enabled OUT OK"); + trace!("wait_enabled IN OK"); } } From a142be8bb8f90ea9935d452bbac692e678f0c9e7 Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 27 Dec 2023 19:12:44 +0100 Subject: [PATCH 120/760] Seems to help --- embassy-stm32/src/i2c/v1.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index df5b44c2d..231d08f18 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -375,6 +375,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { T::regs().sr2().read(); Poll::Ready(Ok(())) } else { + // If we need to go around, then re-enable the interrupts, otherwise nothing + // can wake us up and we'll hang. + Self::enable_interrupts(); Poll::Pending } } From da31aa44c0b9f1a9358e4ebf7e3a0b2a63828e8b Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 28 Dec 2023 10:52:23 +0100 Subject: [PATCH 121/760] dbgmcu: set bits to false when disabled --- embassy-stm32/src/lib.rs | 50 +++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 207f7ed8f..f10e9d50d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -208,32 +208,30 @@ pub fn init(config: Config) -> Peripherals { let p = Peripherals::take_with_cs(cs); #[cfg(dbgmcu)] - if config.enable_debug_during_sleep { - crate::pac::DBGMCU.cr().modify(|cr| { - #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] - { - cr.set_dbg_stop(true); - cr.set_dbg_standby(true); - } - #[cfg(any( - dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, - dbgmcu_l4, dbgmcu_wb, dbgmcu_wl - ))] - { - cr.set_dbg_sleep(true); - cr.set_dbg_stop(true); - cr.set_dbg_standby(true); - } - #[cfg(dbgmcu_h7)] - { - cr.set_d1dbgcken(true); - cr.set_d3dbgcken(true); - cr.set_dbgsleep_d1(true); - cr.set_dbgstby_d1(true); - cr.set_dbgstop_d1(true); - } - }); - } + crate::pac::DBGMCU.cr().modify(|cr| { + #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] + { + cr.set_dbg_stop(config.enable_debug_during_sleep); + cr.set_dbg_standby(config.enable_debug_during_sleep); + } + #[cfg(any( + dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, + dbgmcu_l4, dbgmcu_wb, dbgmcu_wl + ))] + { + cr.set_dbg_sleep(config.enable_debug_during_sleep); + cr.set_dbg_stop(config.enable_debug_during_sleep); + cr.set_dbg_standby(config.enable_debug_during_sleep); + } + #[cfg(dbgmcu_h7)] + { + cr.set_d1dbgcken(config.enable_debug_during_sleep); + cr.set_d3dbgcken(config.enable_debug_during_sleep); + cr.set_dbgsleep_d1(config.enable_debug_during_sleep); + cr.set_dbgstby_d1(config.enable_debug_during_sleep); + cr.set_dbgstop_d1(config.enable_debug_during_sleep); + } + }); #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] peripherals::SYSCFG::enable_and_reset_with_cs(cs); From 8c2a6df03b852233ef6c774896cbb00c2a15040f Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 28 Dec 2023 16:23:47 +0800 Subject: [PATCH 122/760] implement PWM waveform generating with DMA --- embassy-stm32/build.rs | 11 ++ embassy-stm32/src/timer/mod.rs | 18 +++- embassy-stm32/src/timer/simple_pwm.rs | 100 +++++++++++++++--- examples/stm32f4/src/bin/pwm.rs | 12 ++- .../bin/{ws2812_pwm_dma.rs => ws2812_pwm.rs} | 75 +++---------- examples/stm32g4/src/bin/pwm.rs | 12 ++- examples/stm32h7/src/bin/pwm.rs | 13 ++- 7 files changed, 159 insertions(+), 82 deletions(-) rename examples/stm32f4/src/bin/{ws2812_pwm_dma.rs => ws2812_pwm.rs} (50%) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 058b8a0fc..de03827e9 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1008,6 +1008,7 @@ fn main() { (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), (("dac", "CH1"), quote!(crate::dac::DacDma1)), (("dac", "CH2"), quote!(crate::dac::DacDma2)), + (("timer", "UP"), quote!(crate::timer::UpDma)), ] .into(); @@ -1023,6 +1024,16 @@ fn main() { } if let Some(tr) = signals.get(&(regs.kind, ch.signal)) { + // TIM6 of stm32f334 is special, DMA channel for TIM6 depending on SYSCFG state + if chip_name.starts_with("stm32f334") && p.name == "TIM6" { + continue; + } + + // TIM6 of stm32f378 is special, DMA channel for TIM6 depending on SYSCFG state + if chip_name.starts_with("stm32f378") && p.name == "TIM6" { + continue; + } + let peri = format_ident!("{}", p.name); let channel = if let Some(channel) = &ch.channel { diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 74120adad..05a0564a3 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -91,7 +91,12 @@ pub(crate) mod sealed { /// Enable/disable the update interrupt. fn enable_update_interrupt(&mut self, enable: bool) { - Self::regs().dier().write(|r| r.set_uie(enable)); + Self::regs().dier().modify(|r| r.set_uie(enable)); + } + + /// Enable/disable the update dma. + fn enable_update_dma(&mut self, enable: bool) { + Self::regs().dier().modify(|r| r.set_ude(enable)); } /// Enable/disable autoreload preload. @@ -288,6 +293,14 @@ pub(crate) mod sealed { fn get_compare_value(&self, channel: Channel) -> u16 { Self::regs_gp16().ccr(channel.index()).read().ccr() } + + /// Set output compare preload. + fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { + let channel_index = channel.index(); + Self::regs_gp16() + .ccmr_output(channel_index / 2) + .modify(|w| w.set_ocpe(channel_index % 2, preload)); + } } /// Capture/Compare 16-bit timer instance with complementary pin support. @@ -676,3 +689,6 @@ foreach_interrupt! { } }; } + +// Update Event trigger DMA for every timer +dma_trait!(UpDma, Basic16bitInstance); diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index e6072aa15..1819c7c55 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -55,11 +55,12 @@ channel_impl!(new_ch3, Ch3, Channel3Pin); channel_impl!(new_ch4, Ch4, Channel4Pin); /// Simple PWM driver. -pub struct SimplePwm<'d, T> { +pub struct SimplePwm<'d, T, Dma> { inner: PeripheralRef<'d, T>, + dma: PeripheralRef<'d, Dma>, } -impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { +impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> { /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, @@ -69,16 +70,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { _ch4: Option>, freq: Hertz, counting_mode: CountingMode, + dma: impl Peripheral

+ 'd, ) -> Self { - Self::new_inner(tim, freq, counting_mode) + Self::new_inner(tim, freq, counting_mode, dma) } - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { - into_ref!(tim); + fn new_inner( + tim: impl Peripheral

+ 'd, + freq: Hertz, + counting_mode: CountingMode, + dma: impl Peripheral

+ 'd, + ) -> Self { + into_ref!(tim, dma); T::enable_and_reset(); - let mut this = Self { inner: tim }; + let mut this = Self { inner: tim, dma }; this.inner.set_counting_mode(counting_mode); this.set_frequency(freq); @@ -86,14 +93,13 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { this.inner.enable_outputs(); - this.inner - .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); - this.inner - .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); - this.inner - .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); - this.inner - .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); + [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] + .iter() + .for_each(|&channel| { + this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); + this.inner.set_output_compare_preload(channel, true) + }); + this } @@ -141,7 +147,71 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { } } -impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { +impl<'d, T: CaptureCompare16bitInstance + Basic16bitInstance, Dma> SimplePwm<'d, T, Dma> +where + Dma: super::UpDma, +{ + /// Generate a sequence of PWM waveform + pub async fn gen_waveform(&mut self, channel: Channel, duty: &[u16]) { + duty.iter().all(|v| v.le(&self.get_max_duty())); + + self.inner.enable_update_dma(true); + + #[cfg_attr(any(stm32f334, stm32f378), allow(clippy::let_unit_value))] + let req = self.dma.request(); + + self.enable(channel); + + #[cfg(not(any(bdma, gpdma)))] + let dma_regs = self.dma.regs(); + #[cfg(not(any(bdma, gpdma)))] + let isr_num = self.dma.num() / 4; + #[cfg(not(any(bdma, gpdma)))] + let isr_bit = self.dma.num() % 4; + + #[cfg(not(any(bdma, gpdma)))] + // clean DMA FIFO error before a transfer + if dma_regs.isr(isr_num).read().feif(isr_bit) { + dma_regs.ifcr(isr_num).write(|v| v.set_feif(isr_bit, true)); + } + + unsafe { + #[cfg(not(any(bdma, gpdma)))] + use crate::dma::{Burst, FifoThreshold}; + use crate::dma::{Transfer, TransferOptions}; + + let dma_transfer_option = TransferOptions { + #[cfg(not(any(bdma, gpdma)))] + fifo_threshold: Some(FifoThreshold::Full), + #[cfg(not(any(bdma, gpdma)))] + mburst: Burst::Incr8, + ..Default::default() + }; + + Transfer::new_write( + &mut self.dma, + req, + duty, + T::regs_gp16().ccr(channel.index()).as_ptr() as *mut _, + dma_transfer_option, + ) + .await + }; + + self.disable(channel); + + self.inner.enable_update_dma(false); + + #[cfg(not(any(bdma, gpdma)))] + // Since DMA is closed before timer update event trigger DMA is turn off, it will almost always trigger a DMA FIFO error. + // Thus, we will always clean DMA FEIF after each transfer + if dma_regs.isr(isr_num).read().feif(isr_bit) { + dma_regs.ifcr(isr_num).write(|v| v.set_feif(isr_bit, true)); + } + } +} + +impl<'d, T: CaptureCompare16bitInstance, Dma> embedded_hal_02::Pwm for SimplePwm<'d, T, Dma> { type Channel = Channel; type Time = Hertz; type Duty = u16; diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs index 8844a9f0e..92bc42ec8 100644 --- a/examples/stm32f4/src/bin/pwm.rs +++ b/examples/stm32f4/src/bin/pwm.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::dma; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; @@ -16,7 +17,16 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull); - let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default()); + let mut pwm = SimplePwm::new( + p.TIM1, + Some(ch1), + None, + None, + None, + khz(10), + Default::default(), + dma::NoDma, + ); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs similarity index 50% rename from examples/stm32f4/src/bin/ws2812_pwm_dma.rs rename to examples/stm32f4/src/bin/ws2812_pwm.rs index 4458b643f..973743e49 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -2,15 +2,9 @@ // We assume the DIN pin of ws2812 connect to GPIO PB4, and ws2812 is properly powered. // // The idea is that the data rate of ws2812 is 800 kHz, and it use different duty ratio to represent bit 0 and bit 1. -// Thus we can set TIM overflow at 800 kHz, and let TIM Update Event trigger a DMA transfer, then let DMA change CCR value, -// such that pwm duty ratio meet the bit representation of ws2812. +// Thus we can set TIM overflow at 800 kHz, and change duty ratio of TIM to meet the bit representation of ws2812. // -// You may want to modify TIM CCR with Cortex core directly, -// but according to my test, Cortex core will need to run far more than 100 MHz to catch up with TIM. -// Thus we need to use a DMA. -// -// This demo is a combination of HAL, PAC, and manually invoke `dma::Transfer`. -// If you need a simpler way to control ws2812, you may want to take a look at `ws2812_spi.rs` file, which make use of SPI. +// you may also want to take a look at `ws2812_spi.rs` file, which make use of SPI instead. // // Warning: // DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. @@ -20,7 +14,6 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; -use embassy_stm32::pac; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::{Channel, CountingMode}; @@ -52,7 +45,7 @@ async fn main(_spawner: Spawner) { device_config.rcc.sys = Sysclk::PLL1_P; } - let mut dp = embassy_stm32::init(device_config); + let dp = embassy_stm32::init(device_config); let mut ws2812_pwm = SimplePwm::new( dp.TIM3, @@ -62,6 +55,7 @@ async fn main(_spawner: Spawner) { None, khz(800), // data rate of ws2812 CountingMode::EdgeAlignedUp, + dp.DMA1_CH2, ); // construct ws2812 non-return-to-zero (NRZ) code bit by bit @@ -89,62 +83,19 @@ async fn main(_spawner: Spawner) { let pwm_channel = Channel::Ch1; - // PAC level hacking, enable output compare preload - // keep output waveform integrity - pac::TIM3 - .ccmr_output(pwm_channel.index()) - .modify(|v| v.set_ocpe(0, true)); - // make sure PWM output keep low on first start ws2812_pwm.set_duty(pwm_channel, 0); - { - use embassy_stm32::dma::{Burst, FifoThreshold, Transfer, TransferOptions}; + // flip color at 2 Hz + let mut ticker = Ticker::every(Duration::from_millis(500)); - // configure FIFO and MBURST of DMA, to minimize DMA occupation on AHB/APB - let mut dma_transfer_option = TransferOptions::default(); - dma_transfer_option.fifo_threshold = Some(FifoThreshold::Full); - dma_transfer_option.mburst = Burst::Incr8; - - // flip color at 2 Hz - let mut ticker = Ticker::every(Duration::from_millis(500)); - - loop { - for &color in color_list { - // start PWM output - ws2812_pwm.enable(pwm_channel); - - // PAC level hacking, enable timer-update-event trigger DMA - pac::TIM3.dier().modify(|v| v.set_ude(true)); - - unsafe { - Transfer::new_write( - // with &mut, we can easily reuse same DMA channel multiple times - &mut dp.DMA1_CH2, - 5, - color, - pac::TIM3.ccr(pwm_channel.index()).as_ptr() as *mut _, - dma_transfer_option, - ) - .await; - - // Turn off timer-update-event trigger DMA as soon as possible. - // Then clean the FIFO Error Flag if set. - pac::TIM3.dier().modify(|v| v.set_ude(false)); - if pac::DMA1.isr(0).read().feif(2) { - pac::DMA1.ifcr(0).write(|v| v.set_feif(2, true)); - } - - // ws2812 need at least 50 us low level input to confirm the input data and change it's state - Timer::after_micros(50).await; - } - - // stop PWM output for saving some energy - ws2812_pwm.disable(pwm_channel); - - // wait until ticker tick - ticker.next().await; - } + loop { + for &color in color_list { + ws2812_pwm.gen_waveform(Channel::Ch1, color).await; + // ws2812 need at least 50 us low level input to confirm the input data and change it's state + Timer::after_micros(50).await; + // wait until ticker tick + ticker.next().await; } } } diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index d4809a481..9fa004c3e 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::dma; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; @@ -16,7 +17,16 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull); - let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default()); + let mut pwm = SimplePwm::new( + p.TIM1, + Some(ch1), + None, + None, + None, + khz(10), + Default::default(), + dma::NoDma, + ); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index 1e48ba67b..de155fc94 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -7,7 +7,7 @@ use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::Channel; -use embassy_stm32::Config; +use embassy_stm32::{dma, Config}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -38,7 +38,16 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull); - let mut pwm = SimplePwm::new(p.TIM3, Some(ch1), None, None, None, khz(10), Default::default()); + let mut pwm = SimplePwm::new( + p.TIM3, + Some(ch1), + None, + None, + None, + khz(10), + Default::default(), + dma::NoDma, + ); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); From 8d36fe388240b02ae5ef2f49b310e215fc9dffc3 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Dec 2023 18:14:55 +0100 Subject: [PATCH 123/760] ci: use stable 1.75. --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e1af0b647..a6fe52ee2 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "beta-2023-12-17" +channel = "1.75" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", From d32fe0ccdcfe7507accf28caaf2ce03b4b5713f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Damien?= Date: Thu, 28 Dec 2023 22:15:16 +0100 Subject: [PATCH 124/760] Add set_hop_limit to UDP sockets --- embassy-net/src/udp.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index d9df5b29d..a22cd8827 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -222,6 +222,11 @@ impl<'a> UdpSocket<'a> { pub fn payload_send_capacity(&self) -> usize { self.with(|s, _| s.payload_send_capacity()) } + + /// Set the hop limit field in the IP header of sent packets. + pub fn set_hop_limit(&mut self, hop_limit: Option) { + self.with_mut(|s, _| s.set_hop_limit(hop_limit)) + } } impl Drop for UdpSocket<'_> { From 989901c09268cecc5aca558eaecd6ca3fc8bbb76 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Dec 2023 23:55:19 +0100 Subject: [PATCH 125/760] ci: disable rpi-pico/i2c test --- ci.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci.sh b/ci.sh index 933e54a80..75640e384 100755 --- a/ci.sh +++ b/ci.sh @@ -207,6 +207,9 @@ cargo batch \ $BUILD_EXTRA +# failed, a wire must've come loose, will check asap. +rm out/tests/rpi-pico/i2c + rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble From a780339103239890e52fea26172071ec222ee81b Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 28 Dec 2023 23:57:10 +0100 Subject: [PATCH 126/760] stm32: Add breadcrumb to i2cv1 investigation Adds an in-code breadcrumb for https://github.com/embassy-rs/embassy/issues/2372 --- embassy-stm32/src/i2c/v1.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index df5b44c2d..134593276 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -1,3 +1,9 @@ +//! # I2Cv1 +//! +//! This implementation is used for STM32F1, STM32F2, STM32F4, and STM32L1 devices. +//! +//! All other devices (as of 2023-12-28) use [`v2`](super::v2) instead. + use core::future::poll_fn; use core::task::Poll; @@ -10,6 +16,17 @@ use crate::dma::Transfer; use crate::pac::i2c; use crate::time::Hertz; +// /!\ /!\ +// /!\ Implementation note! /!\ +// /!\ /!\ +// +// It's somewhat unclear whether using interrupts here in a *strictly* one-shot style is actually +// what we want! If you are looking in this file because you are doing async I2C and your code is +// just totally hanging (sometimes), maybe swing by this issue: +// . +// +// There's some more details there, and we might have a fix for you. But please let us know if you +// hit a case like this! pub unsafe fn on_interrupt() { let regs = T::regs(); // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of From 3916b26b258ae8216fedf0394257e39f23c53c19 Mon Sep 17 00:00:00 2001 From: ftilde Date: Fri, 29 Dec 2023 12:27:52 +0100 Subject: [PATCH 127/760] Reset rx_started state of nrf buffered_uarte on init This was likely forgotten as part of c46418f12. Without this, when creating a uarte instance, dropping it and then creating another instance, this instance would never receive any bytes. --- embassy-nrf/src/buffered_uarte.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 4ac622d34..2c620798d 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -342,6 +342,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { s.tx_count.store(0, Ordering::Relaxed); s.rx_started_count.store(0, Ordering::Relaxed); s.rx_ended_count.store(0, Ordering::Relaxed); + s.rx_started.store(false, Ordering::Relaxed); let len = tx_buffer.len(); unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; let len = rx_buffer.len(); From 24f569821c7812714070a1ea3692b87100fc53e1 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 29 Dec 2023 09:22:08 +0800 Subject: [PATCH 128/760] record&restore TIM OC to it's earlier state --- embassy-stm32/src/timer/mod.rs | 10 +++++ embassy-stm32/src/timer/simple_pwm.rs | 65 ++++++++++++++++++++------- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 05a0564a3..389666c40 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -99,6 +99,11 @@ pub(crate) mod sealed { Self::regs().dier().modify(|r| r.set_ude(enable)); } + /// Get the update dma enable/disable state. + fn get_update_dma_state(&self) -> bool { + Self::regs().dier().read().ude() + } + /// Enable/disable autoreload preload. fn set_autoreload_preload(&mut self, enable: bool) { Self::regs().cr1().modify(|r| r.set_arpe(enable)); @@ -274,6 +279,11 @@ pub(crate) mod sealed { Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); } + /// Get enable/disable state of a channel + fn get_channel_enable_state(&self, channel: Channel) -> bool { + Self::regs_gp16().ccer().read().cce(channel.index()) + } + /// Set compare value for a channel. fn set_compare_value(&mut self, channel: Channel, value: u16) { Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1819c7c55..acf0d12f9 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -62,6 +62,12 @@ pub struct SimplePwm<'d, T, Dma> { impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> { /// Create a new simple PWM driver. + /// + /// Note: + /// If you want to use [`Self::gen_waveform()`], you need to provide corresponding TIMx_UP DMA channel. + /// Otherwise you can just put a [`dma::NoDma`](crate::dma::NoDma) + /// Currently, you can only use one channel at a time to generate waveform with [`Self::gen_waveform()`]. + /// But you can always use multiple TIM to generate multiple waveform simultaneously. pub fn new( tim: impl Peripheral

+ 'd, _ch1: Option>, @@ -113,6 +119,11 @@ impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> { self.inner.enable_channel(channel, false); } + /// Check whether given channel is enabled + pub fn is_enabled(&self, channel: Channel) -> bool { + self.inner.get_channel_enable_state(channel) + } + /// Set PWM frequency. /// /// Note: when you call this, the max duty value changes, so you will have to @@ -141,6 +152,13 @@ impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> { self.inner.set_compare_value(channel, duty) } + /// Get the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn get_duty(&self, channel: Channel) -> u16 { + self.inner.get_compare_value(channel) + } + /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { self.inner.set_output_polarity(channel, polarity); @@ -153,26 +171,38 @@ where { /// Generate a sequence of PWM waveform pub async fn gen_waveform(&mut self, channel: Channel, duty: &[u16]) { - duty.iter().all(|v| v.le(&self.get_max_duty())); - - self.inner.enable_update_dma(true); + assert!(duty.iter().all(|v| *v <= self.get_max_duty())); #[cfg_attr(any(stm32f334, stm32f378), allow(clippy::let_unit_value))] let req = self.dma.request(); - self.enable(channel); - #[cfg(not(any(bdma, gpdma)))] let dma_regs = self.dma.regs(); #[cfg(not(any(bdma, gpdma)))] let isr_num = self.dma.num() / 4; #[cfg(not(any(bdma, gpdma)))] let isr_bit = self.dma.num() % 4; + #[cfg(not(any(bdma, gpdma)))] + let isr_reg = dma_regs.isr(isr_num); + #[cfg(not(any(bdma, gpdma)))] + let ifcr_reg = dma_regs.ifcr(isr_num); #[cfg(not(any(bdma, gpdma)))] // clean DMA FIFO error before a transfer - if dma_regs.isr(isr_num).read().feif(isr_bit) { - dma_regs.ifcr(isr_num).write(|v| v.set_feif(isr_bit, true)); + if isr_reg.read().feif(isr_bit) { + ifcr_reg.write(|v| v.set_feif(isr_bit, true)); + } + + let original_duty_state = self.get_duty(channel); + let original_enable_state = self.is_enabled(channel); + let original_update_dma_state = self.inner.get_update_dma_state(); + + if !original_update_dma_state { + self.inner.enable_update_dma(true); + } + + if !original_enable_state { + self.enable(channel); } unsafe { @@ -198,15 +228,20 @@ where .await }; - self.disable(channel); + // restore output compare state + if !original_enable_state { + self.disable(channel); + } + self.set_duty(channel, original_duty_state); + if !original_update_dma_state { + self.inner.enable_update_dma(false); - self.inner.enable_update_dma(false); - - #[cfg(not(any(bdma, gpdma)))] - // Since DMA is closed before timer update event trigger DMA is turn off, it will almost always trigger a DMA FIFO error. - // Thus, we will always clean DMA FEIF after each transfer - if dma_regs.isr(isr_num).read().feif(isr_bit) { - dma_regs.ifcr(isr_num).write(|v| v.set_feif(isr_bit, true)); + #[cfg(not(any(bdma, gpdma)))] + // Since DMA could be closed before timer update event trigger DMA is turn off, this can almost always trigger a DMA FIFO error. + // Thus, we will try clean DMA FEIF after each transfer + if isr_reg.read().feif(isr_bit) { + ifcr_reg.write(|v| v.set_feif(isr_bit, true)); + } } } } From 873ee0615147b4a4e0aacd069ce8ac8df611bbbf Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 30 Dec 2023 12:01:08 +0800 Subject: [PATCH 129/760] some trivial fix use less #[cfg] macro; reuse same variable --- embassy-stm32/src/timer/simple_pwm.rs | 17 ++++++++--------- examples/stm32f4/src/bin/ws2812_pwm.rs | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index acf0d12f9..7a5475c31 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -177,15 +177,14 @@ where let req = self.dma.request(); #[cfg(not(any(bdma, gpdma)))] - let dma_regs = self.dma.regs(); - #[cfg(not(any(bdma, gpdma)))] - let isr_num = self.dma.num() / 4; - #[cfg(not(any(bdma, gpdma)))] - let isr_bit = self.dma.num() % 4; - #[cfg(not(any(bdma, gpdma)))] - let isr_reg = dma_regs.isr(isr_num); - #[cfg(not(any(bdma, gpdma)))] - let ifcr_reg = dma_regs.ifcr(isr_num); + let (isr_bit, isr_reg, ifcr_reg) = { + let dma_regs = self.dma.regs(); + let isr_num = self.dma.num() / 4; + let isr_bit = self.dma.num() % 4; + let isr_reg = dma_regs.isr(isr_num); + let ifcr_reg = dma_regs.ifcr(isr_num); + (isr_bit, isr_reg, ifcr_reg) + }; #[cfg(not(any(bdma, gpdma)))] // clean DMA FIFO error before a transfer diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 973743e49..93a89f16a 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) { loop { for &color in color_list { - ws2812_pwm.gen_waveform(Channel::Ch1, color).await; + ws2812_pwm.gen_waveform(pwm_channel, color).await; // ws2812 need at least 50 us low level input to confirm the input data and change it's state Timer::after_micros(50).await; // wait until ticker tick From 1d2c09302b7c57fb7b4a6da20fa4da7af27ae9b8 Mon Sep 17 00:00:00 2001 From: Benjamin Ward Date: Sat, 30 Dec 2023 21:23:07 -0500 Subject: [PATCH 130/760] Fix lora-rs link in README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ae40fe59..714104331 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,7 @@ The embassy-net network stac The nrf-softdevice crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. The embassy-stm32-wpan crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers. -- **LoRa** - -The lora-rs project provides an async LoRa and LoRaWAN stack that works well on Embassy. +- **LoRa** - The lora-rs project provides an async LoRa and LoRaWAN stack that works well on Embassy. - **USB** - embassy-usb implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. From fa9cb99cb6daa898c0333cd02e0cd0b23ee6852b Mon Sep 17 00:00:00 2001 From: Benjamin Ward Date: Sat, 30 Dec 2023 21:28:41 -0500 Subject: [PATCH 131/760] Update docs to reflect current LoRa crate name/location --- docs/modules/ROOT/pages/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 6fba80eda..3cf032c45 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -41,7 +41,7 @@ The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implem The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. === LoRa -link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation. +link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation. === USB link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. From 93b64b90ce426e6d1aa91d473265ec5dfde97b71 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 31 Dec 2023 14:14:32 +0000 Subject: [PATCH 132/760] Extend the task macro to allow cfging arguments away --- embassy-executor-macros/src/macros/task.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 5161e1020..1efb2788b 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -49,7 +49,7 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result Result match t.pat.as_mut() { syn::Pat::Ident(id) => { - arg_names.push(id.ident.clone()); id.mutability = None; + args.push((id.clone(), t.attrs.clone())); } _ => { ctxt.error_spanned_by(arg, "pattern matching in task arguments is not yet supported"); @@ -79,13 +79,24 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result ::embassy_executor::SpawnToken { type Fut = impl ::core::future::Future + 'static; const POOL_SIZE: usize = #pool_size; static POOL: ::embassy_executor::raw::TaskPool = ::embassy_executor::raw::TaskPool::new(); - unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) } + unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } } }; #[cfg(not(feature = "nightly"))] @@ -93,7 +104,7 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result ::embassy_executor::SpawnToken { const POOL_SIZE: usize = #pool_size; static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new(); - unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) } + unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } } }; From 2efde24f333cdf1730f14c050460eb7e0c44f5b9 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 31 Dec 2023 16:55:46 +0000 Subject: [PATCH 133/760] Add test case --- embassy-executor/tests/test.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 0dbd391e8..2c2441dd5 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -135,3 +135,17 @@ fn executor_task_self_wake_twice() { ] ) } + +#[test] +fn executor_task_cfg_args() { + // simulate cfg'ing away argument c + #[task] + async fn task1(a: u32, b: u32, #[cfg(any())] c: u32) { + let (_, _) = (a, b); + } + + #[task] + async fn task2(a: u32, b: u32, #[cfg(all())] c: u32) { + let (_, _, _) = (a, b, c); + } +} From b7cd7952c890f585ff876c622482534e5d58d4a4 Mon Sep 17 00:00:00 2001 From: sodo Date: Mon, 1 Jan 2024 21:18:30 +0900 Subject: [PATCH 134/760] avr: support sleep --- ci.sh | 4 ++-- embassy-executor/Cargo.toml | 8 ++++++-- embassy-executor/src/arch/avr.rs | 13 +++++++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/ci.sh b/ci.sh index a5ddda3a1..a804647e1 100755 --- a/ci.sh +++ b/ci.sh @@ -208,8 +208,8 @@ cargo batch \ $BUILD_EXTRA # walkaround: "-Z" option not working on cargo batch -cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr -cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,integrated-timers +cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p +cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,integrated-timers,avr-device/atmega328p rm out/tests/stm32wb55rg/wpan_mac diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index ade37913b..c937194ce 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -36,10 +36,11 @@ embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macro embassy-time = { version = "0.2", path = "../embassy-time", optional = true} critical-section = "1.1" -# needed for riscv +# needed for riscv and avr # remove when https://github.com/rust-lang/rust/pull/114499 is merged portable-atomic = { version = "1.5", optional = true } + # arch-cortex-m dependencies cortex-m = { version = "0.7.6", optional = true } @@ -47,6 +48,9 @@ cortex-m = { version = "0.7.6", optional = true } wasm-bindgen = { version = "0.2.82", optional = true } js-sys = { version = "0.3", optional = true } +# arch-avr dependencies +avr-device = { version = "0.5.3", optional = true } + [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } @@ -55,7 +59,7 @@ critical-section = { version = "1.1", features = ["std"] } # Architecture _arch = [] # some arch was picked -arch-avr = ["_arch", "dep:portable-atomic"] +arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"] arch-std = ["_arch", "critical-section/std"] arch-cortex-m = ["_arch", "dep:cortex-m"] arch-riscv32 = ["_arch", "dep:portable-atomic"] diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index 2c715f297..fa6afe762 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -8,11 +8,16 @@ mod thread { use core::marker::PhantomData; pub use embassy_executor_macros::main_avr as main; + use portable_atomic::{AtomicBool, Ordering}; use crate::{raw, Spawner}; + static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); + #[export_name = "__pender"] - fn __pender(_context: *mut ()) {} + fn __pender(_context: *mut ()) { + SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); + } /// avr Executor pub struct Executor { @@ -52,7 +57,11 @@ mod thread { loop { unsafe { - self.inner.poll(); + if SIGNAL_WORK_THREAD_MODE.swap(false, Ordering::SeqCst) { + self.inner.poll(); + } else { + avr_device::asm::sleep(); + } } } } From 79cb62c9b4ba1d12b31072a9ecf7ce0b818cda8c Mon Sep 17 00:00:00 2001 From: Benjamin Ward Date: Mon, 1 Jan 2024 10:23:57 -0500 Subject: [PATCH 135/760] Expand LoRa crate notes per PR review --- docs/modules/ROOT/pages/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 3cf032c45..e17adbbd7 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -41,7 +41,7 @@ The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implem The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. === LoRa -link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation. +link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust LoRaWAN implementation. It provides four crates — lora-phy, lora-modulation, lorawan-encoding, and lorawan-device — and basic examples for various development boards. It has support for STM32WL wireless microcontrollers or Semtech SX127x transceivers, among others. === USB link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. From 26c0e5d4390a5d707669ed936c2a7f2f6e0f57e9 Mon Sep 17 00:00:00 2001 From: "Ben V. Brown" Date: Tue, 19 Dec 2023 11:00:01 +1100 Subject: [PATCH 136/760] Extend RTC low power mode for STM32G0 --- embassy-stm32/src/rtc/mod.rs | 10 +++++++--- embassy-stm32/src/rtc/v3.rs | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 1ffb567b3..169505501 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -43,7 +43,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))] +#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5, stm32g0))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -57,7 +57,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))] +#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5, stm32g0))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -423,7 +423,11 @@ impl Rtc { #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); - #[cfg(not(stm32l5))] + #[cfg(all(stm32g0))] + crate::pac::EXTI + .rpr(0) + .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + #[cfg(all(not(stm32g0), not(stm32l5)))] crate::pac::EXTI .pr(0) .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 114141b64..3d44a52ff 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -132,6 +132,12 @@ impl sealed::Instance for crate::peripherals::RTC { #[cfg(all(feature = "low-power", stm32g4))] const EXTI_WAKEUP_LINE: usize = 20; + #[cfg(all(feature = "low-power", stm32g0))] + const EXTI_WAKEUP_LINE: usize = 19; + + #[cfg(all(feature = "low-power", stm32g0))] + type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; + #[cfg(all(feature = "low-power", stm32g4))] type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; From b0071c5070f6b4c932e703f2539c2eef74f09338 Mon Sep 17 00:00:00 2001 From: sodo Date: Tue, 2 Jan 2024 14:48:27 +0900 Subject: [PATCH 137/760] avr: sleep fix --- embassy-executor/src/arch/avr.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index fa6afe762..11e81ed9a 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -57,10 +57,13 @@ mod thread { loop { unsafe { + avr_device::interrupt::disable(); if SIGNAL_WORK_THREAD_MODE.swap(false, Ordering::SeqCst) { - self.inner.poll(); - } else { + avr_device::interrupt::enable(); avr_device::asm::sleep(); + } else { + avr_device::interrupt::enable(); + self.inner.poll(); } } } From c276da5fcb93ce20da0c2f3bfccdeb7e0fee67a7 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 2 Jan 2024 13:30:13 +0800 Subject: [PATCH 138/760] ask a DMA Channel only when use .gen_waveform() --- embassy-stm32/src/timer/simple_pwm.rs | 78 +++++++++----------------- examples/stm32f4/src/bin/pwm.rs | 12 +--- examples/stm32f4/src/bin/ws2812_pwm.rs | 6 +- examples/stm32g4/src/bin/pwm.rs | 12 +--- examples/stm32h7/src/bin/pwm.rs | 13 +---- 5 files changed, 35 insertions(+), 86 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 7a5475c31..77d902e35 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -55,19 +55,12 @@ channel_impl!(new_ch3, Ch3, Channel3Pin); channel_impl!(new_ch4, Ch4, Channel4Pin); /// Simple PWM driver. -pub struct SimplePwm<'d, T, Dma> { +pub struct SimplePwm<'d, T> { inner: PeripheralRef<'d, T>, - dma: PeripheralRef<'d, Dma>, } -impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> { +impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Create a new simple PWM driver. - /// - /// Note: - /// If you want to use [`Self::gen_waveform()`], you need to provide corresponding TIMx_UP DMA channel. - /// Otherwise you can just put a [`dma::NoDma`](crate::dma::NoDma) - /// Currently, you can only use one channel at a time to generate waveform with [`Self::gen_waveform()`]. - /// But you can always use multiple TIM to generate multiple waveform simultaneously. pub fn new( tim: impl Peripheral

+ 'd, _ch1: Option>, @@ -76,22 +69,16 @@ impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> { _ch4: Option>, freq: Hertz, counting_mode: CountingMode, - dma: impl Peripheral

+ 'd, ) -> Self { - Self::new_inner(tim, freq, counting_mode, dma) + Self::new_inner(tim, freq, counting_mode) } - fn new_inner( - tim: impl Peripheral

+ 'd, - freq: Hertz, - counting_mode: CountingMode, - dma: impl Peripheral

+ 'd, - ) -> Self { - into_ref!(tim, dma); + fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { + into_ref!(tim); T::enable_and_reset(); - let mut this = Self { inner: tim, dma }; + let mut this = Self { inner: tim }; this.inner.set_counting_mode(counting_mode); this.set_frequency(freq); @@ -165,32 +152,23 @@ impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> { } } -impl<'d, T: CaptureCompare16bitInstance + Basic16bitInstance, Dma> SimplePwm<'d, T, Dma> -where - Dma: super::UpDma, -{ +impl<'d, T: CaptureCompare16bitInstance + Basic16bitInstance> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform - pub async fn gen_waveform(&mut self, channel: Channel, duty: &[u16]) { + /// + /// Note: + /// you will need to provide corresponding TIMx_UP DMA channel to use this method. + pub async fn gen_waveform( + &mut self, + dma: impl Peripheral

>, + channel: Channel, + duty: &[u16], + ) { assert!(duty.iter().all(|v| *v <= self.get_max_duty())); - #[cfg_attr(any(stm32f334, stm32f378), allow(clippy::let_unit_value))] - let req = self.dma.request(); + into_ref!(dma); - #[cfg(not(any(bdma, gpdma)))] - let (isr_bit, isr_reg, ifcr_reg) = { - let dma_regs = self.dma.regs(); - let isr_num = self.dma.num() / 4; - let isr_bit = self.dma.num() % 4; - let isr_reg = dma_regs.isr(isr_num); - let ifcr_reg = dma_regs.ifcr(isr_num); - (isr_bit, isr_reg, ifcr_reg) - }; - - #[cfg(not(any(bdma, gpdma)))] - // clean DMA FIFO error before a transfer - if isr_reg.read().feif(isr_bit) { - ifcr_reg.write(|v| v.set_feif(isr_bit, true)); - } + #[allow(clippy::let_unit_value)] // eg. stm32f334 + let req = dma.request(); let original_duty_state = self.get_duty(channel); let original_enable_state = self.is_enabled(channel); @@ -218,7 +196,7 @@ where }; Transfer::new_write( - &mut self.dma, + &mut dma, req, duty, T::regs_gp16().ccr(channel.index()).as_ptr() as *mut _, @@ -231,21 +209,21 @@ where if !original_enable_state { self.disable(channel); } + self.set_duty(channel, original_duty_state); + + // Since DMA is closed before timer update event trigger DMA is turn off, + // this can almost always trigger a DMA FIFO error. + // + // optional TODO: + // clean FEIF after disable UDE if !original_update_dma_state { self.inner.enable_update_dma(false); - - #[cfg(not(any(bdma, gpdma)))] - // Since DMA could be closed before timer update event trigger DMA is turn off, this can almost always trigger a DMA FIFO error. - // Thus, we will try clean DMA FEIF after each transfer - if isr_reg.read().feif(isr_bit) { - ifcr_reg.write(|v| v.set_feif(isr_bit, true)); - } } } } -impl<'d, T: CaptureCompare16bitInstance, Dma> embedded_hal_02::Pwm for SimplePwm<'d, T, Dma> { +impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs index 92bc42ec8..8844a9f0e 100644 --- a/examples/stm32f4/src/bin/pwm.rs +++ b/examples/stm32f4/src/bin/pwm.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; @@ -17,16 +16,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull); - let mut pwm = SimplePwm::new( - p.TIM1, - Some(ch1), - None, - None, - None, - khz(10), - Default::default(), - dma::NoDma, - ); + let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default()); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 93a89f16a..239709253 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) { device_config.rcc.sys = Sysclk::PLL1_P; } - let dp = embassy_stm32::init(device_config); + let mut dp = embassy_stm32::init(device_config); let mut ws2812_pwm = SimplePwm::new( dp.TIM3, @@ -55,7 +55,6 @@ async fn main(_spawner: Spawner) { None, khz(800), // data rate of ws2812 CountingMode::EdgeAlignedUp, - dp.DMA1_CH2, ); // construct ws2812 non-return-to-zero (NRZ) code bit by bit @@ -91,7 +90,8 @@ async fn main(_spawner: Spawner) { loop { for &color in color_list { - ws2812_pwm.gen_waveform(pwm_channel, color).await; + // with &mut, we can easily reuse same DMA channel multiple times + ws2812_pwm.gen_waveform(&mut dp.DMA1_CH2, pwm_channel, color).await; // ws2812 need at least 50 us low level input to confirm the input data and change it's state Timer::after_micros(50).await; // wait until ticker tick diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index 9fa004c3e..d4809a481 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; @@ -17,16 +16,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull); - let mut pwm = SimplePwm::new( - p.TIM1, - Some(ch1), - None, - None, - None, - khz(10), - Default::default(), - dma::NoDma, - ); + let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default()); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index de155fc94..1e48ba67b 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -7,7 +7,7 @@ use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::Channel; -use embassy_stm32::{dma, Config}; +use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -38,16 +38,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull); - let mut pwm = SimplePwm::new( - p.TIM3, - Some(ch1), - None, - None, - None, - khz(10), - Default::default(), - dma::NoDma, - ); + let mut pwm = SimplePwm::new(p.TIM3, Some(ch1), None, None, None, khz(10), Default::default()); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); From 162f356ece8533d326df4acf918b3c4462bf486c Mon Sep 17 00:00:00 2001 From: sodo Date: Tue, 2 Jan 2024 23:39:06 +0900 Subject: [PATCH 139/760] add avr to ci --- ci-nightly.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci-nightly.sh b/ci-nightly.sh index 1fc9692b5..46b19c5b7 100755 --- a/ci-nightly.sh +++ b/ci-nightly.sh @@ -28,3 +28,6 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \ +cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p +cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,integrated-timers,avr-device/atmega328p + From cad4efe57f9817b9368bb431dd12f18d05030c9f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 2 Jan 2024 17:28:08 +0100 Subject: [PATCH 140/760] stm32/timer: add missing supertrait bounds. --- embassy-stm32/src/timer/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 389666c40..d07fd2776 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -558,13 +558,16 @@ impl From for bool { pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} /// Gneral-purpose 16-bit timer instance. -pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} +pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + Basic16bitInstance + 'static {} /// Gneral-purpose 32-bit timer instance. -pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} +pub trait GeneralPurpose32bitInstance: + sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static +{ +} /// Advanced control timer instance. -pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} +pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose16bitInstance + 'static {} /// Capture/Compare 16-bit timer instance. pub trait CaptureCompare16bitInstance: @@ -574,7 +577,7 @@ pub trait CaptureCompare16bitInstance: /// Capture/Compare 16-bit timer instance with complementary pin support. pub trait ComplementaryCaptureCompare16bitInstance: - sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static + sealed::ComplementaryCaptureCompare16bitInstance + CaptureCompare16bitInstance + AdvancedControlInstance + 'static { } From 638aa313d4e5e80649f7f6201fef3154e5b2bbd5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 2 Jan 2024 17:28:23 +0100 Subject: [PATCH 141/760] stm32/pwm: simplify impl blocks. --- embassy-stm32/src/timer/simple_pwm.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 77d902e35..80f10424c 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -150,9 +150,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { self.inner.set_output_polarity(channel, polarity); } -} -impl<'d, T: CaptureCompare16bitInstance + Basic16bitInstance> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform /// /// Note: From eb7197c5b765cd58f0ad8f8663123c9837d7eff2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 2 Jan 2024 18:13:25 +0100 Subject: [PATCH 142/760] examples: configure executor task arena sizes. --- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 4 ++-- examples/stm32f7/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 4 ++-- examples/stm32h7/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 4 ++-- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- 24 files changed, 27 insertions(+), 27 deletions(-) diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index b52bac650..eba9a0579 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 08ce16877..38c9f8cff 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 248ec6dce..9c0aeb463 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index aa5f87615..e81ff618e 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 78e33de28..f75ffc8e6 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 240afe4c6..f58bd9557 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 97f1e277b..887126f9d 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 0c3830f97..d5fabac82 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index cdaee802e..394546b75 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index b5677e148..6c4dc7975 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index bc8a7f2d6..9ab731ce5 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index fc0346f90..730c44553 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 07de83203..e03fc6e8a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", 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"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index a4f306865..840a60303 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index a74e0f674..f0586a478 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index b76a848a8..acc30d959 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f767zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 8815b8e47..290bd791c 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h563zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 31feeda45..16c024bc9 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 8a5fb5749..cb50e3748 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 0d236ec90..329e7b98d 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 029b2cfe0..5a8a3eaac 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u585ai to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index bce53c440..a4a89889d 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 84eb6c831..923e0e8a1 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 62c34b792..20ffe6099 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } From 7dec3ccca4726ed42bf26dbd99d9f5d5dcf025b4 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 2 Jan 2024 18:44:41 +0100 Subject: [PATCH 143/760] [FAQ]: Link to Arena configuration docs --- docs/modules/ROOT/pages/faq.adoc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index 1fe9bde37..fd355827b 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -152,4 +152,10 @@ Note that the git revision should match any other embassy patches or git depende * When using `InterruptExecutor`: ** disable `executor-thread` ** make `main`` spawn everything, then enable link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.set_sleeponexit[SCB.SLEEPONEXIT] and `loop { cortex_m::asm::wfi() }` - ** *Note:* If you need 2 priority levels, using 2 interrupt executors is better than 1 thread executor + 1 interrupt executor. \ No newline at end of file + ** *Note:* If you need 2 priority levels, using 2 interrupt executors is better than 1 thread executor + 1 interrupt executor. + +== How do I set up the task arenas on stable? + +When you aren't using the `nightly` feature of `embassy-executor`, the executor uses a bump allocator, which may require configuration. + +Check out link:https://docs.embassy.dev/embassy-executor/git/cortex-m/index.html#task-arena[Task Arena Documentation] for more details. From 92995e8bb11f62f54d4ce2474b8d323a2e7ebb87 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Tue, 2 Jan 2024 22:13:06 +0100 Subject: [PATCH 144/760] update metapac to stm32-data PR 333 --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 16d1cca4c..60bb83859 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8caf2f0bda28baf4393899dc67ba57f058087f5a" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4d06d091219322837b7cef21748a180d09d7a34f" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8caf2f0bda28baf4393899dc67ba57f058087f5a", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4d06d091219322837b7cef21748a180d09d7a34f", default-features = false, features = ["metadata"]} [features] From cbdd570ad55c841ad80ab76b5d77c4ed930a6109 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Tue, 2 Jan 2024 22:21:59 +0100 Subject: [PATCH 145/760] dbgmcu: add stm32l5 support --- embassy-stm32/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index f10e9d50d..2508c4fca 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -209,7 +209,7 @@ pub fn init(config: Config) -> Peripherals { #[cfg(dbgmcu)] crate::pac::DBGMCU.cr().modify(|cr| { - #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] + #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))] { cr.set_dbg_stop(config.enable_debug_during_sleep); cr.set_dbg_standby(config.enable_debug_during_sleep); From f1c077ed2e420b1b4f8c1835fe05a1279a742267 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Tue, 2 Jan 2024 23:05:47 +0100 Subject: [PATCH 146/760] low-power: add stop support for stm32l5 --- embassy-stm32/src/lib.rs | 2 +- embassy-stm32/src/low_power.rs | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 2508c4fca..45a2ab63e 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -157,7 +157,7 @@ pub struct Config { /// RCC config. pub rcc: rcc::Config, - /// Enable debug during sleep. + /// Enable debug during sleep and stop. /// /// May incrase power consumption. Defaults to true. #[cfg(dbgmcu)] diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 4fab8dae4..c5c5dd96f 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -37,6 +37,8 @@ //! async fn async_main(spawner: Spawner) { //! // initialize the platform... //! let mut config = embassy_stm32::Config::default(); +//! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working +//! config.enable_debug_during_sleep = false; //! let p = embassy_stm32::init(config); //! //! // give the RTC to the executor... @@ -107,6 +109,19 @@ pub enum StopMode { Stop2, } +#[cfg(stm32l5)] +use stm32_metapac::pwr::vals::Lpms; + +#[cfg(stm32l5)] +impl Into for StopMode { + fn into(self) -> Lpms { + match self { + StopMode::Stop1 => Lpms::STOP1, + StopMode::Stop2 => Lpms::STOP2, + } + } +} + /// Thread mode executor, using WFE/SEV. /// /// This is the simplest and most common kind of executor. It runs on @@ -164,8 +179,9 @@ impl Executor { } } - fn configure_stop(&mut self, _stop_mode: StopMode) { - // TODO: configure chip-specific settings for stop + fn configure_stop(&mut self, stop_mode: StopMode) { + #[cfg(stm32l5)] + crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); } fn configure_pwr(&mut self) { From 38303009907fbf9ebd4919e85166c8bebb6e0ba4 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Tue, 2 Jan 2024 23:05:58 +0100 Subject: [PATCH 147/760] stm32l5: add low-power stop example --- examples/stm32l5/Cargo.toml | 6 +++- examples/stm32l5/src/bin/stop.rs | 61 ++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 examples/stm32l5/src/bin/stop.rs diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 329e7b98d..c50314587 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l552ze to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } @@ -30,3 +30,7 @@ static_cell = "2" [profile.release] debug = 2 + +[[bin]] +name = "stop" +default-features = ["embassy-stm32/low-power"] diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs new file mode 100644 index 000000000..21b30a266 --- /dev/null +++ b/examples/stm32l5/src/bin/stop.rs @@ -0,0 +1,61 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed, AnyPin}; +use embassy_stm32::low_power::Executor; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::Config; +use embassy_stm32::rcc::LsConfig; +use embassy_time::Timer; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[cortex_m_rt::entry] +fn main() -> ! { + Executor::take().run(|spawner| { + unwrap!(spawner.spawn(async_main(spawner))); + }) +} + +#[embassy_executor::task] +async fn async_main(spawner: Spawner) { + let mut config = Config::default(); + config.rcc.ls = LsConfig::default_lsi(); + // when enabled the power-consumption is much higher during stop, but debugging and RTT is working + // if you wan't to measure the power-consumption, or for production: uncomment this line + // config.enable_debug_during_sleep = false; + let p = embassy_stm32::init(config); + + // give the RTC to the executor... + let rtc = Rtc::new(p.RTC, RtcConfig::default()); + static RTC: StaticCell = StaticCell::new(); + let rtc = RTC.init(rtc); + embassy_stm32::low_power::stop_with_rtc(rtc); + + unwrap!(spawner.spawn(blinky(p.PC7.into()))); + unwrap!(spawner.spawn(timeout())); +} + +#[embassy_executor::task] +async fn blinky(led: AnyPin) -> ! { + let mut led = Output::new(led, Level::Low, Speed::Low); + loop { + info!("high"); + led.set_high(); + Timer::after_millis(300).await; + + info!("low"); + led.set_low(); + Timer::after_millis(300).await; + } +} + +// when enable_debug_during_sleep is false, it is more difficult to reprogram the MCU +// therefore we block the MCU after 30s to be able to reprogram it easily +#[embassy_executor::task] +async fn timeout() -> ! { + Timer::after_secs(30).await; + loop {} +} From 6da3db1190a0a10b7a65f9622bc3a4e1a7ef536c Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Tue, 2 Jan 2024 23:07:16 +0100 Subject: [PATCH 148/760] low-power: add feature for stm32l5 --- embassy-stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 60bb83859..571fb8ac0 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -24,7 +24,7 @@ flavors = [ { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi", features = ["low-power"] }, { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, - { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" }, + { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] }, { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" }, From 986eca1b1210d081d3e2f70702d8248c7ef5286b Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Tue, 2 Jan 2024 23:24:23 +0100 Subject: [PATCH 149/760] fix for rustfmt --- examples/stm32l5/src/bin/stop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs index 21b30a266..32a736de8 100644 --- a/examples/stm32l5/src/bin/stop.rs +++ b/examples/stm32l5/src/bin/stop.rs @@ -3,11 +3,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed, AnyPin}; +use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; use embassy_stm32::low_power::Executor; +use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; -use embassy_stm32::rcc::LsConfig; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; From 7f00d7aa0c0d9bd142209667bfdc224049cf6f90 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Tue, 2 Jan 2024 23:29:33 +0100 Subject: [PATCH 150/760] allow unused variable --- embassy-stm32/src/low_power.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index c5c5dd96f..4c3d288fd 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -179,6 +179,7 @@ impl Executor { } } + #[allow(unused_variables)] fn configure_stop(&mut self, stop_mode: StopMode) { #[cfg(stm32l5)] crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); From 34713b4910d2d94a632ff8e3a161ab982fdab2ba Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 2 Jan 2024 16:03:23 -0800 Subject: [PATCH 151/760] fix g0 being left out of some clock controls --- embassy-stm32/build.rs | 4 ++-- embassy-stm32/src/rcc/g0.rs | 27 +++++++++++++++++++++++---- embassy-stm32/src/rcc/mod.rs | 10 +++++----- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index de03827e9..ef152acd1 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -505,7 +505,7 @@ fn main() { (TokenStream::new(), TokenStream::new()) }; - let mux_supported = HashSet::from(["c0", "h5", "h50", "h7", "h7ab", "h7rm0433", "g4", "l4"]) + let mux_supported = HashSet::from(["c0", "h5", "h50", "h7", "h7ab", "h7rm0433", "g0", "g4", "l4"]) .contains(rcc_registers.version); let mux_for = |mux: Option<&'static PeripheralRccRegister>| { // restrict mux implementation to supported versions @@ -534,7 +534,7 @@ fn main() { let variant_name = format_ident!("{}", v.name); let clock_name = format_ident!("{}", v.name.to_ascii_lowercase()); - if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" { + if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" { quote! { #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name }, } diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index d3367b049..7f62031e5 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -95,7 +95,7 @@ impl Default for Config { } impl PllConfig { - pub(crate) fn init(self) -> Hertz { + pub(crate) fn init(self) -> (Hertz, Option, Option) { let (src, input_freq) = match self.source { PllSource::HSI => (vals::Pllsrc::HSI, HSI_FREQ), PllSource::HSE(freq, _) => (vals::Pllsrc::HSE, freq), @@ -118,6 +118,9 @@ impl PllConfig { // > Caution: The software must set this bitfield so as not to exceed 64 MHz on this clock. debug_assert!(r_freq.0 <= 64_000_000); + let q_freq = self.q.map(|q| n_freq / q); + let p_freq = self.p.map(|p| n_freq / p); + // RM0454 § 5.2.3: // > To modify the PLL configuration, proceed as follows: // > 1. Disable the PLL by setting PLLON to 0 in Clock control register (RCC_CR). @@ -172,11 +175,14 @@ impl PllConfig { w.set_pllpen(self.p.is_some()); }); - r_freq + (r_freq, q_freq, p_freq) } } pub(crate) unsafe fn init(config: Config) { + let mut pll1_q_freq = None; + let mut pll1_p_freq = None; + let (sys_clk, sw) = match config.mux { ClockSrc::HSI(div) => { // Enable HSI @@ -199,8 +205,12 @@ pub(crate) unsafe fn init(config: Config) { (freq, Sw::HSE) } ClockSrc::PLL(pll) => { - let freq = pll.init(); - (freq, Sw::PLL1_R) + let (r_freq, q_freq, p_freq) = pll.init(); + + pll1_q_freq = q_freq; + pll1_p_freq = p_freq; + + (r_freq, Sw::PLL1_R) } ClockSrc::LSI => { // Enable LSI @@ -286,12 +296,21 @@ pub(crate) unsafe fn init(config: Config) { } let rtc = config.ls.init(); + let lse_freq = config.ls.lse.map(|lse| lse.frequency); + + let hsi_freq = (sw == Sw::HSI).then_some(HSI_FREQ); + let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); set_freqs(Clocks { sys: sys_clk, hclk1: ahb_freq, pclk1: apb_freq, pclk1_tim: apb_tim_freq, + hsi: hsi_freq, + lse: lse_freq, + lsi: lsi_freq, + pll1_q: pll1_q_freq, + pll1_p: pll1_p_freq, rtc, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 04a51110c..c4bee4c95 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -121,9 +121,9 @@ pub struct Clocks { #[cfg(rcc_l4)] pub pllsai2_p: Option, - #[cfg(any(stm32g4, rcc_l4))] + #[cfg(any(stm32g0, stm32g4, rcc_l4))] pub pll1_p: Option, - #[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g4))] + #[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g0, stm32g4))] pub pll1_q: Option, #[cfg(any(stm32h5, stm32h7))] pub pll2_p: Option, @@ -160,16 +160,16 @@ pub struct Clocks { pub rtc: Option, - #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))] + #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))] pub hsi: Option, #[cfg(stm32h5)] pub hsi48: Option, - #[cfg(stm32h5)] + #[cfg(any(stm32g0, stm32h5))] pub lsi: Option, #[cfg(any(stm32h5, stm32h7))] pub csi: Option, - #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))] + #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))] pub lse: Option, #[cfg(any(stm32h5, stm32h7, stm32g4))] pub hse: Option, From d372cba266c7a110f314e74dfee589987b892383 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 2 Jan 2024 16:25:51 -0800 Subject: [PATCH 152/760] additional chip variants required more clocks --- embassy-stm32/src/rcc/g0.rs | 5 +++++ embassy-stm32/src/rcc/mod.rs | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 7f62031e5..aedc95bf3 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -299,7 +299,9 @@ pub(crate) unsafe fn init(config: Config) { let lse_freq = config.ls.lse.map(|lse| lse.frequency); let hsi_freq = (sw == Sw::HSI).then_some(HSI_FREQ); + let hsi_div_8_freq = hsi_freq.map(|f| f / 8u32); let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); + let hse_freq = (sw == Sw::HSE).then_some(sys_clk); set_freqs(Clocks { sys: sys_clk, @@ -307,6 +309,9 @@ pub(crate) unsafe fn init(config: Config) { pclk1: apb_freq, pclk1_tim: apb_tim_freq, hsi: hsi_freq, + hsi48: None, + hsi_div_8: hsi_div_8_freq, + hse: hse_freq, lse: lse_freq, lsi: lsi_freq, pll1_q: pll1_q_freq, diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c4bee4c95..240ffc6d2 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -162,8 +162,10 @@ pub struct Clocks { #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))] pub hsi: Option, - #[cfg(stm32h5)] + #[cfg(any(stm32h5, stm32g0))] pub hsi48: Option, + #[cfg(stm32g0)] + pub hsi_div_8: Option, #[cfg(any(stm32g0, stm32h5))] pub lsi: Option, #[cfg(any(stm32h5, stm32h7))] @@ -171,7 +173,7 @@ pub struct Clocks { #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))] pub lse: Option, - #[cfg(any(stm32h5, stm32h7, stm32g4))] + #[cfg(any(stm32h5, stm32h7, stm32g0, stm32g4))] pub hse: Option, #[cfg(stm32h5)] From 5fb6ad9a6a423e3b75f4ec2b1c3ccaf0030777c9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 3 Jan 2024 02:10:42 +0100 Subject: [PATCH 153/760] update stm32data, fixes missing interrupts. --- ci.sh | 1 + embassy-stm32/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index 75640e384..59bbf5d31 100755 --- a/ci.sh +++ b/ci.sh @@ -108,6 +108,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l041f6,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073cz,defmt,exti,time-driver-any,low-power,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f303c8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f398ve,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 571fb8ac0..938faa382 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4d06d091219322837b7cef21748a180d09d7a34f" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9ec9e0afb8fac2f5500a885e1cfd9c03f3a2ee30" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4d06d091219322837b7cef21748a180d09d7a34f", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9ec9e0afb8fac2f5500a885e1cfd9c03f3a2ee30", default-features = false, features = ["metadata"]} [features] From 01dbe9278357296fe9fb99f5e6923e80067c4a98 Mon Sep 17 00:00:00 2001 From: sodo Date: Wed, 3 Jan 2024 12:35:07 +0900 Subject: [PATCH 154/760] fix --- embassy-executor/src/arch/avr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index 11e81ed9a..70085d04d 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -58,7 +58,7 @@ mod thread { loop { unsafe { avr_device::interrupt::disable(); - if SIGNAL_WORK_THREAD_MODE.swap(false, Ordering::SeqCst) { + if !SIGNAL_WORK_THREAD_MODE.swap(false, Ordering::SeqCst) { avr_device::interrupt::enable(); avr_device::asm::sleep(); } else { From e31dd036febea5e8b4d469003328799f7d83f7dd Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 2 Jan 2024 20:03:14 -0800 Subject: [PATCH 155/760] add hf timer example for g0 --- examples/stm32g0/src/bin/hf_timer.rs | 69 ++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/stm32g0/src/bin/hf_timer.rs diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs new file mode 100644 index 000000000..475568a23 --- /dev/null +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +use defmt::info; +use {defmt_rtt as _, panic_probe as _}; + +use embassy_executor::Spawner; +use embassy_stm32::{ + gpio::OutputType, + pac, + pac::rcc::vals::Tim1sel, + rcc::{ClockSrc, Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr}, + time::khz, + timer::{ + complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}, + simple_pwm::PwmPin, + Channel, + }, + Config as PeripheralConfig, +}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut rcc_config = RccConfig::default(); + rcc_config.mux = ClockSrc::PLL(PllConfig { + source: PllSource::HSI, + m: Pllm::DIV1, + n: Plln::MUL16, + r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) + q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) + p: None, + }); + + let mut peripheral_config = PeripheralConfig::default(); + peripheral_config.rcc = rcc_config; + + let p = embassy_stm32::init(peripheral_config); + + // configure TIM1 mux to select PLLQ as clock source + // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + // RM0444 page 210 + // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 + pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q)); + + let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); + let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); + + let mut pwm = ComplementaryPwm::new( + p.TIM1, + Some(ch1), + Some(ch1n), + None, + None, + None, + None, + None, + None, + khz(512), + Default::default(), + ); + + let max = pwm.get_max_duty(); + info!("Max duty: {}", max); + + pwm.set_duty(Channel::Ch1, max / 2); + pwm.enable(Channel::Ch1); + + loop {} +} From 9b47fbeb47d30dc10e75b3c754f7e3f03ca495f5 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 2 Jan 2024 20:12:58 -0800 Subject: [PATCH 156/760] weird format rule --- examples/stm32g0/src/bin/hf_timer.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 475568a23..78a779e29 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -2,22 +2,16 @@ #![no_main] use defmt::info; -use {defmt_rtt as _, panic_probe as _}; - use embassy_executor::Spawner; -use embassy_stm32::{ - gpio::OutputType, - pac, - pac::rcc::vals::Tim1sel, - rcc::{ClockSrc, Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr}, - time::khz, - timer::{ - complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}, - simple_pwm::PwmPin, - Channel, - }, - Config as PeripheralConfig, -}; +use embassy_stm32::gpio::OutputType; +use embassy_stm32::pac::rcc::vals::Tim1sel; +use embassy_stm32::rcc::{ClockSrc, Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr}; +use embassy_stm32::time::khz; +use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; +use embassy_stm32::timer::simple_pwm::PwmPin; +use embassy_stm32::timer::Channel; +use embassy_stm32::{pac, Config as PeripheralConfig}; +use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { From c924f89ead457007c5304fcde0e2acf65b77c76d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 3 Jan 2024 13:08:53 +0100 Subject: [PATCH 157/760] fix: add missing impl block for async qspi multiwrite --- embassy-nrf/src/qspi.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index f35b83628..0171ceb0e 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -639,6 +639,9 @@ mod _eh1 { self.capacity as usize } } + + #[cfg(feature = "qspi-multiwrite-flash")] + impl<'d, T: Instance> embedded_storage_async::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {} } pub(crate) mod sealed { From 4a59fbdedc63999add80d6f9c2404dbfe2566e74 Mon Sep 17 00:00:00 2001 From: swanandx <73115739+swanandx@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:17:04 +0530 Subject: [PATCH 158/760] feat: impl ReadReady and WriteReady for tcp --- embassy-net/src/tcp.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index dcfb5c96e..72b0677b4 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -547,6 +547,12 @@ mod embedded_io_impls { } } + impl<'d> embedded_io_async::ReadReady for TcpSocket<'d> { + fn read_ready(&mut self) -> Result { + Ok(self.io.with(|s, _| s.may_recv())) + } + } + impl<'d> embedded_io_async::Write for TcpSocket<'d> { async fn write(&mut self, buf: &[u8]) -> Result { self.io.write(buf).await @@ -557,6 +563,12 @@ mod embedded_io_impls { } } + impl<'d> embedded_io_async::WriteReady for TcpSocket<'d> { + fn write_ready(&mut self) -> Result { + Ok(self.io.with(|s, _| s.may_send())) + } + } + impl<'d> embedded_io_async::ErrorType for TcpReader<'d> { type Error = Error; } @@ -567,6 +579,12 @@ mod embedded_io_impls { } } + impl<'d> embedded_io_async::ReadReady for TcpReader<'d> { + fn read_ready(&mut self) -> Result { + Ok(self.io.with(|s, _| s.may_recv())) + } + } + impl<'d> embedded_io_async::ErrorType for TcpWriter<'d> { type Error = Error; } @@ -580,6 +598,12 @@ mod embedded_io_impls { self.io.flush().await } } + + impl<'d> embedded_io_async::WriteReady for TcpWriter<'d> { + fn write_ready(&mut self) -> Result { + Ok(self.io.with(|s, _| s.may_send())) + } + } } /// TCP client compatible with `embedded-nal-async` traits. From face0312451fd56fb5475472dc793e7397dce563 Mon Sep 17 00:00:00 2001 From: swanandx <73115739+swanandx@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:22:01 +0530 Subject: [PATCH 159/760] feat: new_txonly_nosck in spis --- embassy-nrf/src/spis.rs | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index e202c6c27..16ac82e5f 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -105,7 +105,7 @@ impl<'d, T: Instance> Spis<'d, T> { Self::new_inner( spis, cs.map_into(), - sck.map_into(), + Some(sck.map_into()), Some(miso.map_into()), Some(mosi.map_into()), config, @@ -122,7 +122,14 @@ impl<'d, T: Instance> Spis<'d, T> { config: Config, ) -> Self { into_ref!(cs, sck, miso); - Self::new_inner(spis, cs.map_into(), sck.map_into(), Some(miso.map_into()), None, config) + Self::new_inner( + spis, + cs.map_into(), + Some(sck.map_into()), + Some(miso.map_into()), + None, + config, + ) } /// Create a new SPIS driver, capable of RX only (MOSI only). @@ -135,13 +142,32 @@ impl<'d, T: Instance> Spis<'d, T> { config: Config, ) -> Self { into_ref!(cs, sck, mosi); - Self::new_inner(spis, cs.map_into(), sck.map_into(), None, Some(mosi.map_into()), config) + Self::new_inner( + spis, + cs.map_into(), + Some(sck.map_into()), + None, + Some(mosi.map_into()), + config, + ) + } + + /// Create a new SPIS driver, capable of TX only (MISO only) without SCK pin. + pub fn new_txonly_nosck( + spis: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + cs: impl Peripheral

+ 'd, + miso: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(cs, miso); + Self::new_inner(spis, cs.map_into(), None, Some(miso.map_into()), None, config) } fn new_inner( spis: impl Peripheral

+ 'd, cs: PeripheralRef<'d, AnyPin>, - sck: PeripheralRef<'d, AnyPin>, + sck: Option>, miso: Option>, mosi: Option>, config: Config, @@ -153,10 +179,12 @@ impl<'d, T: Instance> Spis<'d, T> { let r = T::regs(); // Configure pins. - sck.conf().write(|w| w.input().connect().drive().h0h1()); - r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); cs.conf().write(|w| w.input().connect().drive().h0h1()); r.psel.csn.write(|w| unsafe { w.bits(cs.psel_bits()) }); + if let Some(sck) = &sck { + sck.conf().write(|w| w.input().connect().drive().h0h1()); + r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); + } if let Some(mosi) = &mosi { mosi.conf().write(|w| w.input().connect().drive().h0h1()); r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) }); From 8352d13cfd7ea46abf8bd2bb460ff1ce32e7da8d Mon Sep 17 00:00:00 2001 From: swanandx <73115739+swanandx@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:25:09 +0530 Subject: [PATCH 160/760] feat: new_txonly_nosck in spim --- embassy-nrf/src/spim.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 5d3c3268c..ab16491a5 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -99,7 +99,7 @@ impl<'d, T: Instance> Spim<'d, T> { into_ref!(sck, miso, mosi); Self::new_inner( spim, - sck.map_into(), + Some(sck.map_into()), Some(miso.map_into()), Some(mosi.map_into()), config, @@ -115,7 +115,7 @@ impl<'d, T: Instance> Spim<'d, T> { config: Config, ) -> Self { into_ref!(sck, mosi); - Self::new_inner(spim, sck.map_into(), None, Some(mosi.map_into()), config) + Self::new_inner(spim, Some(sck.map_into()), None, Some(mosi.map_into()), config) } /// Create a new SPIM driver, capable of RX only (MISO only). @@ -127,12 +127,23 @@ impl<'d, T: Instance> Spim<'d, T> { config: Config, ) -> Self { into_ref!(sck, miso); - Self::new_inner(spim, sck.map_into(), Some(miso.map_into()), None, config) + Self::new_inner(spim, Some(sck.map_into()), Some(miso.map_into()), None, config) + } + + /// Create a new SPIM driver, capable of TX only (MOSI only), without SCK pin. + pub fn new_txonly_nosck( + spim: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + mosi: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(mosi); + Self::new_inner(spim, None, None, Some(mosi.map_into()), config) } fn new_inner( spim: impl Peripheral

+ 'd, - sck: PeripheralRef<'d, AnyPin>, + sck: Option>, miso: Option>, mosi: Option>, config: Config, @@ -142,7 +153,9 @@ impl<'d, T: Instance> Spim<'d, T> { let r = T::regs(); // Configure pins - sck.conf().write(|w| w.dir().output().drive().h0h1()); + if let Some(sck) = &sck { + sck.conf().write(|w| w.dir().output().drive().h0h1()); + } if let Some(mosi) = &mosi { mosi.conf().write(|w| w.dir().output().drive().h0h1()); } From 046af81a10a0e979d207706a59290151089f49ee Mon Sep 17 00:00:00 2001 From: swanandx <73115739+swanandx@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:33:43 +0530 Subject: [PATCH 161/760] fix: info_ref! can't be called on Option --- embassy-nrf/src/spis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 16ac82e5f..3aad25298 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -174,7 +174,7 @@ impl<'d, T: Instance> Spis<'d, T> { ) -> Self { compiler_fence(Ordering::SeqCst); - into_ref!(spis, cs, sck); + into_ref!(spis, cs); let r = T::regs(); From bdaf722cb899504032816d09de63c0f44b2776e8 Mon Sep 17 00:00:00 2001 From: swanandx <73115739+swanandx@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:35:30 +0530 Subject: [PATCH 162/760] fix: check if sck is some before setting high or low --- embassy-nrf/src/spim.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index ab16491a5..b0723d495 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -165,13 +165,17 @@ impl<'d, T: Instance> Spim<'d, T> { match config.mode.polarity { Polarity::IdleHigh => { - sck.set_high(); + if let Some(sck) = &sck { + sck.set_high(); + } if let Some(mosi) = &mosi { mosi.set_high(); } } Polarity::IdleLow => { - sck.set_low(); + if let Some(sck) = &sck { + sck.set_low(); + } if let Some(mosi) = &mosi { mosi.set_low(); } From 31bf1278072bdb865aa7d8d361152fe47957ce08 Mon Sep 17 00:00:00 2001 From: Tyler Gilbert Date: Wed, 3 Jan 2024 10:46:45 -0600 Subject: [PATCH 163/760] Update STM32 RCC U5 to support P and Q dividers --- embassy-stm32/src/rcc/u5.rs | 18 ++++++++++++++++++ examples/stm32u5/src/bin/usb_serial.rs | 2 ++ 2 files changed, 20 insertions(+) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 81bdec881..0321d51f7 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -45,6 +45,18 @@ pub struct PllConfig { /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. pub n: Plln, + /// The divider for the P output. + /// + /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` + /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default + /// `Config { voltage_range }`. + pub p: Plldiv, + /// The divider for the Q output. + /// + /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` + /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default + /// `Config { voltage_range }`. + pub q: Plldiv, /// The divider for the R output. /// /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` @@ -60,6 +72,8 @@ impl PllConfig { source: PllSource::HSI, m: Pllm::DIV1, n: Plln::MUL10, + p: Plldiv::DIV3, + q: Plldiv::DIV2, r: Plldiv::DIV1, } } @@ -70,6 +84,8 @@ impl PllConfig { source: PllSource::MSIS(Msirange::RANGE_48MHZ), m: Pllm::DIV3, n: Plln::MUL10, + p: Plldiv::DIV3, + q: Plldiv::DIV2, r: Plldiv::DIV1, } } @@ -301,6 +317,8 @@ pub(crate) unsafe fn init(config: Config) { RCC.pll1divr().modify(|w| { // Set the VCO multiplier w.set_plln(pll.n); + w.set_pllp(pll.p); + w.set_pllq(pll.q); // Set the R output divisor w.set_pllr(pll.r); }); diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 44d1df4f1..dca34fd0e 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -26,6 +26,8 @@ async fn main(_spawner: Spawner) { source: PllSource::HSI, m: Pllm::DIV2, n: Plln::MUL10, + p: Plldiv::DIV1, + q: Plldiv::DIV1, r: Plldiv::DIV1, }); config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB From 727906fa04f52b27aa8dd3f1fea51b15fe1e7391 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 3 Jan 2024 11:04:48 -0600 Subject: [PATCH 164/760] Update u5.rs Update comments on p and q divider values to correctly describe what the clock outputs are used for. --- embassy-stm32/src/rcc/u5.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 0321d51f7..ceed46176 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -45,17 +45,15 @@ pub struct PllConfig { /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. pub n: Plln, - /// The divider for the P output. - /// - /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` - /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default - /// `Config { voltage_range }`. + /// The divider for the P output. + /// + /// The P output is one of several options + /// that can be used to feed the SAI/MDF/ADF Clock mux's. pub p: Plldiv, - /// The divider for the Q output. - /// - /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` - /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default - /// `Config { voltage_range }`. + /// The divider for the Q output. + /// + /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks + /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. pub q: Plldiv, /// The divider for the R output. /// From 994b77e6843d70db34c59c0723b7718d52f3fd52 Mon Sep 17 00:00:00 2001 From: Tyler Gilbert Date: Wed, 3 Jan 2024 11:06:03 -0600 Subject: [PATCH 165/760] Add write_immediate() function to STM32 DMA ringbuffer API to pre-fill the buffer before starting the DMA --- embassy-stm32/src/dma/bdma.rs | 7 +++++++ embassy-stm32/src/dma/dma.rs | 7 +++++++ embassy-stm32/src/dma/ringbuffer.rs | 11 +++++++++++ 3 files changed, 25 insertions(+) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index a2b83716d..077cfdcd9 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -664,6 +664,13 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } + /// Write elements directly to the raw buffer. + /// This can be used to fill the buffer before starting the DMA transfer. + #[allow(dead_code)] + pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + self.ringbuf.write_immediate(buf) + } + /// Write elements to the ring buffer /// Return a tuple of the length written and the length remaining in the buffer pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 16d02f273..ef9bb3d78 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -934,6 +934,13 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } + /// Write elements directly to the raw buffer. + /// This can be used to fill the buffer before starting the DMA transfer. + #[allow(dead_code)] + pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + self.ringbuf.write_immediate(buf) + } + /// Write elements from the ring buffer /// Return a tuple of the length written and the length remaining in the buffer pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs index c9f7a3026..c5b42060a 100644 --- a/embassy-stm32/src/dma/ringbuffer.rs +++ b/embassy-stm32/src/dma/ringbuffer.rs @@ -263,6 +263,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { self.cap() - dma.get_remaining_transfers() } + /// Write elements directly to the buffer. This must be done before the DMA is started + /// or after the buffer has been cleared using `clear()`. + pub fn write_immediate(&mut self, buffer: &[W]) -> Result<(usize, usize), OverrunError> { + if self.end != 0 { + return Err(OverrunError); + } + let written = self.copy_from(buffer, 0..self.cap()); + self.end = written % self.cap(); + Ok((written, self.cap() - written)) + } + /// Write an exact number of elements to the ringbuffer. pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result { let mut written_data = 0; From 7944e854dda297193328e00b4f9b08ce4d843915 Mon Sep 17 00:00:00 2001 From: Tyler Gilbert Date: Wed, 3 Jan 2024 11:07:57 -0600 Subject: [PATCH 166/760] Fix formatting of comments --- embassy-stm32/src/rcc/u5.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index ceed46176..dff08dc9b 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -45,13 +45,13 @@ pub struct PllConfig { /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. pub n: Plln, - /// The divider for the P output. - /// + /// The divider for the P output. + /// /// The P output is one of several options /// that can be used to feed the SAI/MDF/ADF Clock mux's. pub p: Plldiv, - /// The divider for the Q output. - /// + /// The divider for the Q output. + /// /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. pub q: Plldiv, From 03ba4ae3864d3cc38545dcf469944bafae5ca8a7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 3 Jan 2024 18:31:18 +0100 Subject: [PATCH 167/760] stm32: update metapac. --- ci.sh | 1 + embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/v2.rs | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ci.sh b/ci.sh index 59bbf5d31..84a724ede 100755 --- a/ci.sh +++ b/ci.sh @@ -106,6 +106,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb15cc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l041f6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l051k8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073cz,defmt,exti,time-driver-any,low-power,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f303c8,defmt,exti,time-driver-any,time \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 938faa382..844a55cf8 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9ec9e0afb8fac2f5500a885e1cfd9c03f3a2ee30" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f9f48b067be92fa9ea9dbdce0e85b5d0eb989790" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9ec9e0afb8fac2f5500a885e1cfd9c03f3a2ee30", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f9f48b067be92fa9ea9dbdce0e85b5d0eb989790", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index eda1324de..4622b40a9 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -156,7 +156,7 @@ where fn convert(&mut self) -> u16 { // clear end of conversion flag T::regs().sr().modify(|reg| { - reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE); + reg.set_eoc(false); }); // Start conversion @@ -164,10 +164,10 @@ where reg.set_swstart(true); }); - while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED { + while T::regs().sr().read().strt() == false { // spin //wait for actual start } - while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE { + while T::regs().sr().read().eoc() == false { // spin //wait for finish } From f85898771bc1cda13131de785647732580d1a179 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 4 Jan 2024 15:45:42 +0000 Subject: [PATCH 168/760] New embassy-net release --- embassy-net/CHANGELOG.md | 6 +++++- embassy-net/Cargo.toml | 2 +- embassy-net/src/lib.rs | 2 -- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/perf-client/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 19 files changed, 22 insertions(+), 20 deletions(-) diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md index 0319a5ed4..cc763b74c 100644 --- a/embassy-net/CHANGELOG.md +++ b/embassy-net/CHANGELOG.md @@ -7,9 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3 - 2024-01-04 + +- Added `ReadReady` and `WriteReady` impls on `TcpSocket`. - Avoid never resolving `TcpIo::read` when the output buffer is empty. -- Update to `smoltcp` git. +- Update to `smoltcp` v0.11. - Forward constants from `smoltcp` in DNS query results so changing DNS result size in `smoltcp` properly propagates. +- Removed the nightly feature. ## 0.2.1 - 2023-10-31 diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 612a3d689..67f0bd028 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net" -version = "0.2.1" +version = "0.3.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Async TCP/IP network stack for embedded systems" diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 2cef2232c..1c0cf1a12 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -1,6 +1,4 @@ #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(nightly, feature(async_fn_in_trait, impl_trait_projections))] -#![cfg_attr(nightly, allow(stable_features, unknown_lints))] #![allow(async_fn_in_trait)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 9ab731ce5..02e5cddec 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 730c44553..fc225eee6 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index e03fc6e8a..4f45e9cc1 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.4.0", path = "../../embassy-executor", feature embassy-time = { version = "0.2", 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.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "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" } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 840a60303..969c3d36a 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "std", ] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index f0586a478..838bb5291 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index acc30d959..4b22069a0 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 290bd791c..02e11731a 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 16c024bc9..f4dca0e44 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index cb50e3748..97a27efd2 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -13,7 +13,7 @@ embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defm embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index c50314587..ce71cc310 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.6.0" diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index a4a89889d..8dce89abf 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -11,7 +11,7 @@ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", fea embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 923e0e8a1..48455b760 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -9,7 +9,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index ccdca0844..c25388699 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -13,7 +13,7 @@ embassy-executor = { version = "0.4.0", path = "../../embassy-executor", feature embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } embedded-hal-async = { version = "1.0.0-rc.3" } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 52aa74df3..9eecd535c 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3.0" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index c38aa8004..50a85e116 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.4.0", path = "../../embassy-executor", feature embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index c60b28a7a..2f5340a6a 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -54,7 +54,7 @@ embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defm embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } -embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } perf-client = { path = "../perf-client" } defmt = "0.3.0" From c80781078c58b76f82df508f5d65e22aab72ce05 Mon Sep 17 00:00:00 2001 From: Pawel Rawski Date: Thu, 4 Jan 2024 21:25:55 +0100 Subject: [PATCH 169/760] Fix an error in compiling examples for rp2040 --- embassy-rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 669d79f40..4942ca507 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -82,7 +82,7 @@ cortex-m = "0.7.6" critical-section = "1.1" futures = { version = "0.3.17", default-features = false, features = ["async-await"] } chrono = { version = "0.4", default-features = false, optional = true } -embedded-io = { version = "0.6.0" } +embedded-io = { version = "0.6.1" } embedded-io-async = { version = "0.6.1" } embedded-storage = { version = "0.3" } embedded-storage-async = { version = "0.4.1" } From 17346fdfc22a34d651d9d30bcc35125916ee44b5 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 5 Jan 2024 14:47:56 +0200 Subject: [PATCH 170/760] tests: nrf: Sync link_ram.x from upstream Upstream has added bunch of improvements and fixes to linker script, so sync these while keeping the FLASH -> RAM changes. --- tests/nrf/link_ram.x | 46 ++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/tests/nrf/link_ram.x b/tests/nrf/link_ram.x index 26da86baa..5cb23a642 100644 --- a/tests/nrf/link_ram.x +++ b/tests/nrf/link_ram.x @@ -1,5 +1,5 @@ /* ##### EMBASSY NOTE - Originally from https://github.com/rust-embedded/cortex-m-rt/blob/master/link.x.in + Originally from https://github.com/rust-embedded/cortex-m/blob/master/cortex-m-rt/link.x.in Adjusted to put everything in RAM */ @@ -65,22 +65,30 @@ PROVIDE(__pre_init = DefaultPreInit); /* # Sections */ SECTIONS { - PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); + PROVIDE(_ram_start = ORIGIN(RAM)); + PROVIDE(_ram_end = ORIGIN(RAM) + LENGTH(RAM)); + PROVIDE(_stack_start = _ram_end); /* ## Sections in RAM */ /* ### Vector table */ .vector_table ORIGIN(RAM) : { - /* Initial Stack Pointer (SP) value */ - LONG(_stack_start); + __vector_table = .; + + /* Initial Stack Pointer (SP) value. + * We mask the bottom three bits to force 8-byte alignment. + * Despite having an assert for this later, it's possible that a separate + * linker script could override _stack_start after the assert is checked. + */ + LONG(_stack_start & 0xFFFFFFF8); /* Reset vector */ KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ - __reset_vector = .; /* Exceptions */ + __exceptions = .; /* start of exceptions */ KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ - __eexceptions = .; + __eexceptions = .; /* end of exceptions */ /* Device specific interrupts */ KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ @@ -125,7 +133,6 @@ SECTIONS { . = ALIGN(4); __sdata = .; - __edata = .; *(.data .data.*); . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ } > RAM @@ -133,6 +140,7 @@ SECTIONS * use the .data loading mechanism by pushing __edata. Note: do not change * output region or load region in those user sections! */ . = ALIGN(4); + __edata = .; /* LMA of .data */ __sidata = LOADADDR(.data); @@ -147,8 +155,12 @@ SECTIONS __veneer_base = .; *(.gnu.sgstubs*) . = ALIGN(32); - __veneer_limit = .; } > RAM + /* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are + * always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol. + */ + . = ALIGN(32); + __veneer_limit = .; /* ### .bss */ .bss (NOLOAD) : ALIGN(4) @@ -213,10 +225,21 @@ BUG(cortex-m-rt): .bss is not 4-byte aligned"); ASSERT(__sheap % 4 == 0, " BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); +ASSERT(_stack_start % 8 == 0, " +ERROR(cortex-m-rt): stack start address is not 8-byte aligned. +If you have set _stack_start, check it's set to an address which is a multiple of 8 bytes. +If you haven't, stack starts at the end of RAM by default. Check that both RAM +origin and length are set to multiples of 8 in the `memory.x` file."); + /* # Position checks */ -/* ## .vector_table */ -ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " +/* ## .vector_table + * + * If the *start* of exception vectors is not 8 bytes past the start of the + * vector table, then we somehow did not place the reset vector, which should + * live 4 bytes past the start of the vector table. + */ +ASSERT(__exceptions == ADDR(.vector_table) + 0x8, " BUG(cortex-m-rt): the reset vector is missing"); ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " @@ -248,7 +271,6 @@ the 'cc' crate then modify your build script to compile the C code _without_ the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); /* Do not exceed this mark in the error messages above | */ - /* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ /* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */ -INCLUDE device.x \ No newline at end of file +INCLUDE device.x From 890ceae4e5b353ac85d7030ea7b344c18a1d663e Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 5 Jan 2024 14:58:57 +0200 Subject: [PATCH 171/760] tests: Use unified link_ram_cortex_m.x file for all Cortex M targets --- tests/{nrf/link_ram.x => link_ram_cortex_m.x} | 0 tests/nrf/build.rs | 2 +- tests/rp/build.rs | 2 +- tests/rp/link_ram.x | 255 ------------------ tests/rp/memory.x | 4 + tests/stm32/build.rs | 2 +- tests/stm32/link_ram.x | 254 ----------------- 7 files changed, 7 insertions(+), 512 deletions(-) rename tests/{nrf/link_ram.x => link_ram_cortex_m.x} (100%) delete mode 100644 tests/rp/link_ram.x create mode 100644 tests/rp/memory.x delete mode 100644 tests/stm32/link_ram.x diff --git a/tests/nrf/link_ram.x b/tests/link_ram_cortex_m.x similarity index 100% rename from tests/nrf/link_ram.x rename to tests/link_ram_cortex_m.x diff --git a/tests/nrf/build.rs b/tests/nrf/build.rs index 93e2a28cf..71c82a70f 100644 --- a/tests/nrf/build.rs +++ b/tests/nrf/build.rs @@ -4,7 +4,7 @@ use std::{env, fs}; fn main() -> Result<(), Box> { let out = PathBuf::from(env::var("OUT_DIR").unwrap()); - fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap(); + fs::write(out.join("link_ram.x"), include_bytes!("../link_ram_cortex_m.x")).unwrap(); println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rerun-if-changed=link_ram.x"); diff --git a/tests/rp/build.rs b/tests/rp/build.rs index 93e2a28cf..71c82a70f 100644 --- a/tests/rp/build.rs +++ b/tests/rp/build.rs @@ -4,7 +4,7 @@ use std::{env, fs}; fn main() -> Result<(), Box> { let out = PathBuf::from(env::var("OUT_DIR").unwrap()); - fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap(); + fs::write(out.join("link_ram.x"), include_bytes!("../link_ram_cortex_m.x")).unwrap(); println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rerun-if-changed=link_ram.x"); diff --git a/tests/rp/link_ram.x b/tests/rp/link_ram.x deleted file mode 100644 index 86a11e875..000000000 --- a/tests/rp/link_ram.x +++ /dev/null @@ -1,255 +0,0 @@ -/* ##### EMBASSY NOTE - Originally from https://github.com/rust-embedded/cortex-m-rt/blob/master/link.x.in - Adjusted to put everything in RAM -*/ - -/* # Developer notes - -- Symbols that start with a double underscore (__) are considered "private" - -- Symbols that start with a single underscore (_) are considered "semi-public"; they can be - overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { - static mut __sbss }`). - -- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a - symbol if not dropped if it appears in or near the front of the linker arguments and "it's not - needed" by any of the preceding objects (linker arguments) - -- `PROVIDE` is used to provide default values that can be overridden by a user linker script - -- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* - the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization - routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see - "Address (..) is out of bounds" in the disassembly produced by `objdump`. -*/ - -/* Provides information about the memory layout of the device */ -MEMORY { - RAM : ORIGIN = 0x20000000, LENGTH = 256K -} - -/* # Entry point = reset vector */ -EXTERN(__RESET_VECTOR); -EXTERN(Reset); -ENTRY(Reset); - -/* # Exception vectors */ -/* This is effectively weak aliasing at the linker level */ -/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. - the `exception!` macro) */ -EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ - -EXTERN(DefaultHandler); - -PROVIDE(NonMaskableInt = DefaultHandler); -EXTERN(HardFaultTrampoline); -PROVIDE(MemoryManagement = DefaultHandler); -PROVIDE(BusFault = DefaultHandler); -PROVIDE(UsageFault = DefaultHandler); -PROVIDE(SecureFault = DefaultHandler); -PROVIDE(SVCall = DefaultHandler); -PROVIDE(DebugMonitor = DefaultHandler); -PROVIDE(PendSV = DefaultHandler); -PROVIDE(SysTick = DefaultHandler); - -PROVIDE(DefaultHandler = DefaultHandler_); -PROVIDE(HardFault = HardFault_); - -/* # Interrupt vectors */ -EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ - -/* # Pre-initialization function */ -/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, - then the function this points to will be called before the RAM is initialized. */ -PROVIDE(__pre_init = DefaultPreInit); - -/* # Sections */ -SECTIONS -{ - PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); - - /* ## Sections in RAM */ - /* ### Vector table */ - .vector_table ORIGIN(RAM) : - { - /* Initial Stack Pointer (SP) value */ - LONG(_stack_start); - - /* Reset vector */ - KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ - __reset_vector = .; - - /* Exceptions */ - KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ - __eexceptions = .; - - /* Device specific interrupts */ - KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ - } > RAM - - PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); - - /* ### .text */ - .text _stext : - { - __stext = .; - *(.Reset); - - *(.text .text.*); - - /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, - so must be placed close to it. */ - *(.HardFaultTrampoline); - *(.HardFault.*); - - . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ - __etext = .; - } > RAM - - /* ### .rodata */ - .rodata : ALIGN(4) - { - . = ALIGN(4); - __srodata = .; - *(.rodata .rodata.*); - - /* 4-byte align the end (VMA) of this section. - This is required by LLD to ensure the LMA of the following .data - section will have the correct alignment. */ - . = ALIGN(4); - __erodata = .; - } > RAM - - /* ## Sections in RAM */ - /* ### .data */ - .data : ALIGN(4) - { - . = ALIGN(4); - __sdata = .; - __edata = .; - *(.data .data.*); - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - } > RAM - /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to - * use the .data loading mechanism by pushing __edata. Note: do not change - * output region or load region in those user sections! */ - . = ALIGN(4); - - /* LMA of .data */ - __sidata = LOADADDR(.data); - - /* ### .gnu.sgstubs - This section contains the TrustZone-M veneers put there by the Arm GNU linker. */ - /* Security Attribution Unit blocks must be 32 bytes aligned. */ - /* Note that this pads the RAM usage to 32 byte alignment. */ - .gnu.sgstubs : ALIGN(32) - { - . = ALIGN(32); - __veneer_base = .; - *(.gnu.sgstubs*) - . = ALIGN(32); - __veneer_limit = .; - } > RAM - - /* ### .bss */ - .bss (NOLOAD) : ALIGN(4) - { - . = ALIGN(4); - __sbss = .; - *(.bss .bss.*); - *(COMMON); /* Uninitialized C statics */ - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - } > RAM - /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to - * use the .bss zeroing mechanism by pushing __ebss. Note: do not change - * output region or load region in those user sections! */ - . = ALIGN(4); - __ebss = .; - - /* ### .uninit */ - .uninit (NOLOAD) : ALIGN(4) - { - . = ALIGN(4); - __suninit = .; - *(.uninit .uninit.*); - . = ALIGN(4); - __euninit = .; - } > RAM - - /* Place the heap right after `.uninit` in RAM */ - PROVIDE(__sheap = __euninit); - - /* ## .got */ - /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in - the input files and raise an error if relocatable code is found */ - .got (NOLOAD) : - { - KEEP(*(.got .got.*)); - } - - /* ## Discarded sections */ - /DISCARD/ : - { - /* Unused exception related info that only wastes space */ - *(.ARM.exidx); - *(.ARM.exidx.*); - *(.ARM.extab.*); - } -} - -/* Do not exceed this mark in the error messages below | */ -/* # Alignment checks */ -ASSERT(ORIGIN(RAM) % 4 == 0, " -ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); - -ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " -BUG(cortex-m-rt): .data is not 4-byte aligned"); - -ASSERT(__sidata % 4 == 0, " -BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); - -ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " -BUG(cortex-m-rt): .bss is not 4-byte aligned"); - -ASSERT(__sheap % 4 == 0, " -BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); - -/* # Position checks */ - -/* ## .vector_table */ -ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " -BUG(cortex-m-rt): the reset vector is missing"); - -ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " -BUG(cortex-m-rt): the exception vectors are missing"); - -ASSERT(SIZEOF(.vector_table) > 0x40, " -ERROR(cortex-m-rt): The interrupt vectors are missing. -Possible solutions, from most likely to less likely: -- Link to a svd2rust generated device crate -- Check that you actually use the device/hal/bsp crate in your code -- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency -may be enabling it) -- Supply the interrupt handlers yourself. Check the documentation for details."); - -/* ## .text */ -ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " -ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section -Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); - -ASSERT(_stext + SIZEOF(.text) < ORIGIN(RAM) + LENGTH(RAM), " -ERROR(cortex-m-rt): The .text section must be placed inside the RAM memory. -Set _stext to an address smaller than 'ORIGIN(RAM) + LENGTH(RAM)'"); - -/* # Other checks */ -ASSERT(SIZEOF(.got) == 0, " -ERROR(cortex-m-rt): .got section detected in the input object files -Dynamic relocations are not supported. If you are linking to C code compiled using -the 'cc' crate then modify your build script to compile the C code _without_ -the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); -/* Do not exceed this mark in the error messages above | */ - - -/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ -/* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */ -INCLUDE device.x \ No newline at end of file diff --git a/tests/rp/memory.x b/tests/rp/memory.x new file mode 100644 index 000000000..bf0041d7d --- /dev/null +++ b/tests/rp/memory.x @@ -0,0 +1,4 @@ +/* Provides information about the memory layout of the device */ +MEMORY { + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index c5d0e40d6..f32a7b2f8 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs @@ -4,7 +4,7 @@ use std::{env, fs}; fn main() -> Result<(), Box> { let out = PathBuf::from(env::var("OUT_DIR").unwrap()); - fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap(); + fs::write(out.join("link_ram.x"), include_bytes!("../link_ram_cortex_m.x")).unwrap(); println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rustc-link-arg-bins=--nmagic"); diff --git a/tests/stm32/link_ram.x b/tests/stm32/link_ram.x deleted file mode 100644 index 26da86baa..000000000 --- a/tests/stm32/link_ram.x +++ /dev/null @@ -1,254 +0,0 @@ -/* ##### EMBASSY NOTE - Originally from https://github.com/rust-embedded/cortex-m-rt/blob/master/link.x.in - Adjusted to put everything in RAM -*/ - -/* # Developer notes - -- Symbols that start with a double underscore (__) are considered "private" - -- Symbols that start with a single underscore (_) are considered "semi-public"; they can be - overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { - static mut __sbss }`). - -- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a - symbol if not dropped if it appears in or near the front of the linker arguments and "it's not - needed" by any of the preceding objects (linker arguments) - -- `PROVIDE` is used to provide default values that can be overridden by a user linker script - -- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* - the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization - routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see - "Address (..) is out of bounds" in the disassembly produced by `objdump`. -*/ - -/* Provides information about the memory layout of the device */ -/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ -INCLUDE memory.x - -/* # Entry point = reset vector */ -EXTERN(__RESET_VECTOR); -EXTERN(Reset); -ENTRY(Reset); - -/* # Exception vectors */ -/* This is effectively weak aliasing at the linker level */ -/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. - the `exception!` macro) */ -EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ - -EXTERN(DefaultHandler); - -PROVIDE(NonMaskableInt = DefaultHandler); -EXTERN(HardFaultTrampoline); -PROVIDE(MemoryManagement = DefaultHandler); -PROVIDE(BusFault = DefaultHandler); -PROVIDE(UsageFault = DefaultHandler); -PROVIDE(SecureFault = DefaultHandler); -PROVIDE(SVCall = DefaultHandler); -PROVIDE(DebugMonitor = DefaultHandler); -PROVIDE(PendSV = DefaultHandler); -PROVIDE(SysTick = DefaultHandler); - -PROVIDE(DefaultHandler = DefaultHandler_); -PROVIDE(HardFault = HardFault_); - -/* # Interrupt vectors */ -EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ - -/* # Pre-initialization function */ -/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, - then the function this points to will be called before the RAM is initialized. */ -PROVIDE(__pre_init = DefaultPreInit); - -/* # Sections */ -SECTIONS -{ - PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); - - /* ## Sections in RAM */ - /* ### Vector table */ - .vector_table ORIGIN(RAM) : - { - /* Initial Stack Pointer (SP) value */ - LONG(_stack_start); - - /* Reset vector */ - KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ - __reset_vector = .; - - /* Exceptions */ - KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ - __eexceptions = .; - - /* Device specific interrupts */ - KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ - } > RAM - - PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); - - /* ### .text */ - .text _stext : - { - __stext = .; - *(.Reset); - - *(.text .text.*); - - /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, - so must be placed close to it. */ - *(.HardFaultTrampoline); - *(.HardFault.*); - - . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ - __etext = .; - } > RAM - - /* ### .rodata */ - .rodata : ALIGN(4) - { - . = ALIGN(4); - __srodata = .; - *(.rodata .rodata.*); - - /* 4-byte align the end (VMA) of this section. - This is required by LLD to ensure the LMA of the following .data - section will have the correct alignment. */ - . = ALIGN(4); - __erodata = .; - } > RAM - - /* ## Sections in RAM */ - /* ### .data */ - .data : ALIGN(4) - { - . = ALIGN(4); - __sdata = .; - __edata = .; - *(.data .data.*); - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - } > RAM - /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to - * use the .data loading mechanism by pushing __edata. Note: do not change - * output region or load region in those user sections! */ - . = ALIGN(4); - - /* LMA of .data */ - __sidata = LOADADDR(.data); - - /* ### .gnu.sgstubs - This section contains the TrustZone-M veneers put there by the Arm GNU linker. */ - /* Security Attribution Unit blocks must be 32 bytes aligned. */ - /* Note that this pads the RAM usage to 32 byte alignment. */ - .gnu.sgstubs : ALIGN(32) - { - . = ALIGN(32); - __veneer_base = .; - *(.gnu.sgstubs*) - . = ALIGN(32); - __veneer_limit = .; - } > RAM - - /* ### .bss */ - .bss (NOLOAD) : ALIGN(4) - { - . = ALIGN(4); - __sbss = .; - *(.bss .bss.*); - *(COMMON); /* Uninitialized C statics */ - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - } > RAM - /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to - * use the .bss zeroing mechanism by pushing __ebss. Note: do not change - * output region or load region in those user sections! */ - . = ALIGN(4); - __ebss = .; - - /* ### .uninit */ - .uninit (NOLOAD) : ALIGN(4) - { - . = ALIGN(4); - __suninit = .; - *(.uninit .uninit.*); - . = ALIGN(4); - __euninit = .; - } > RAM - - /* Place the heap right after `.uninit` in RAM */ - PROVIDE(__sheap = __euninit); - - /* ## .got */ - /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in - the input files and raise an error if relocatable code is found */ - .got (NOLOAD) : - { - KEEP(*(.got .got.*)); - } - - /* ## Discarded sections */ - /DISCARD/ : - { - /* Unused exception related info that only wastes space */ - *(.ARM.exidx); - *(.ARM.exidx.*); - *(.ARM.extab.*); - } -} - -/* Do not exceed this mark in the error messages below | */ -/* # Alignment checks */ -ASSERT(ORIGIN(RAM) % 4 == 0, " -ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); - -ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " -BUG(cortex-m-rt): .data is not 4-byte aligned"); - -ASSERT(__sidata % 4 == 0, " -BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); - -ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " -BUG(cortex-m-rt): .bss is not 4-byte aligned"); - -ASSERT(__sheap % 4 == 0, " -BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); - -/* # Position checks */ - -/* ## .vector_table */ -ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " -BUG(cortex-m-rt): the reset vector is missing"); - -ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " -BUG(cortex-m-rt): the exception vectors are missing"); - -ASSERT(SIZEOF(.vector_table) > 0x40, " -ERROR(cortex-m-rt): The interrupt vectors are missing. -Possible solutions, from most likely to less likely: -- Link to a svd2rust generated device crate -- Check that you actually use the device/hal/bsp crate in your code -- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency -may be enabling it) -- Supply the interrupt handlers yourself. Check the documentation for details."); - -/* ## .text */ -ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " -ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section -Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); - -ASSERT(_stext + SIZEOF(.text) < ORIGIN(RAM) + LENGTH(RAM), " -ERROR(cortex-m-rt): The .text section must be placed inside the RAM memory. -Set _stext to an address smaller than 'ORIGIN(RAM) + LENGTH(RAM)'"); - -/* # Other checks */ -ASSERT(SIZEOF(.got) == 0, " -ERROR(cortex-m-rt): .got section detected in the input object files -Dynamic relocations are not supported. If you are linking to C code compiled using -the 'cc' crate then modify your build script to compile the C code _without_ -the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); -/* Do not exceed this mark in the error messages above | */ - - -/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ -/* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */ -INCLUDE device.x \ No newline at end of file From 9b44cca4ce1c8426ecec77136c2b1f520c1f31d4 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 5 Jan 2024 15:34:04 +0200 Subject: [PATCH 172/760] tests: Fix location of __edata section and comment original --- tests/link_ram_cortex_m.x | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/link_ram_cortex_m.x b/tests/link_ram_cortex_m.x index 5cb23a642..39a31b52a 100644 --- a/tests/link_ram_cortex_m.x +++ b/tests/link_ram_cortex_m.x @@ -133,14 +133,18 @@ SECTIONS { . = ALIGN(4); __sdata = .; + __edata = .; /* RAM: By setting __sdata=__edata cortex-m-rt has to copy 0 bytes as .data is already in RAM */ + *(.data .data.*); . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ } > RAM /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to * use the .data loading mechanism by pushing __edata. Note: do not change * output region or load region in those user sections! */ + /* Link from RAM: Disabled, now __sdata == __edata . = ALIGN(4); __edata = .; + */ /* LMA of .data */ __sidata = LOADADDR(.data); From 801a36c7b4e476388e55c842dec09d7ef2607a5a Mon Sep 17 00:00:00 2001 From: Derek Hageman Date: Thu, 4 Jan 2024 07:52:53 -0700 Subject: [PATCH 173/760] stm32: Add G0 USB RCC Add configuration for STM32G0 USB clock. --- embassy-stm32/src/rcc/g0.rs | 51 ++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index aedc95bf3..b38fe1dcc 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -72,6 +72,22 @@ pub enum PllSource { HSE(Hertz, HseMode), } +/// Sets the source for the 48MHz clock to the USB peripheral. +#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] +pub enum UsbSrc { + /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the + /// oscillator to comply with the USB specification for oscillator tolerance. + #[cfg(any(stm32g0b1, stm32g0c1))] + Hsi48(super::Hsi48Config), + /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The + /// PLL needs to be using the HSE source to comply with the USB specification for oscillator + /// tolerance. + PllQ, + /// Use the HSE source directly. The HSE must be a 48MHz source. The HSE source must comply + /// with the USB specification for oscillator tolerance. + HSE, +} + /// Clocks configutation pub struct Config { pub mux: ClockSrc, @@ -79,6 +95,8 @@ pub struct Config { pub apb_pre: APBPrescaler, pub low_power_run: bool, pub ls: super::LsConfig, + #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] + pub usb_src: Option, } impl Default for Config { @@ -90,6 +108,8 @@ impl Default for Config { apb_pre: APBPrescaler::DIV1, low_power_run: false, ls: Default::default(), + #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] + usb_src: None, } } } @@ -303,13 +323,42 @@ pub(crate) unsafe fn init(config: Config) { let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); let hse_freq = (sw == Sw::HSE).then_some(sys_clk); + #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] + let hsi48_freq = config.usb_src.and_then(|config| { + match config { + UsbSrc::PllQ => { + // Make sure the PLLQ is enabled and running at 48Mhz + assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000); + RCC.ccipr2() + .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q)); + None + } + UsbSrc::HSE => { + // Make sure the HSE is enabled and running at 48Mhz + assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000); + RCC.ccipr2() + .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE)); + None + } + #[cfg(any(stm32g0b1, stm32g0c1))] + UsbSrc::Hsi48(config) => { + let freq = super::init_hsi48(config); + RCC.ccipr2() + .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)); + Some(freq) + } + } + }); + #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))] + let hsi48_freq: Option = None; + set_freqs(Clocks { sys: sys_clk, hclk1: ahb_freq, pclk1: apb_freq, pclk1_tim: apb_tim_freq, hsi: hsi_freq, - hsi48: None, + hsi48: hsi48_freq, hsi_div_8: hsi_div_8_freq, hse: hse_freq, lse: lse_freq, From d34910dbc88d4d4b7cf907b17dd6ed4fd7e2f39c Mon Sep 17 00:00:00 2001 From: Derek Hageman Date: Thu, 4 Jan 2024 07:53:31 -0700 Subject: [PATCH 174/760] stm32: Add G0 USB example Add a USB CDC ACM example using STM32G0 USB and CRS. --- examples/stm32g0/.cargo/config.toml | 4 +- examples/stm32g0/Cargo.toml | 6 +- examples/stm32g0/src/bin/usb_serial.rs | 99 ++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 examples/stm32g0/src/bin/usb_serial.rs diff --git a/examples/stm32g0/.cargo/config.toml b/examples/stm32g0/.cargo/config.toml index 35cca5412..f395d8920 100644 --- a/examples/stm32g0/.cargo/config.toml +++ b/examples/stm32g0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip STM32G071RBTx" +# replace STM32G0B1RETx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32G0B1RETx" [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 0abc0a638..7ad36952f 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -5,11 +5,13 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -# Change stm32g071rb to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } +# Change stm32g0b1re to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs new file mode 100644 index 000000000..f5aaa5624 --- /dev/null +++ b/examples/stm32g0/src/bin/usb_serial.rs @@ -0,0 +1,99 @@ +#![no_std] +#![no_main] + +use defmt::{panic, *}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_stm32::rcc::{Hsi48Config, UsbSrc}; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::Builder; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USB_UCPD1_2 => usb::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config { + sync_from_usb: true, + ..Default::default() + })); + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + // Create the driver, from the HAL. + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); + + // Create embassy-usb Config + let config = embassy_usb::Config::new(0xc0de, 0xcafe); + //config.max_packet_size_0 = 64; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 7]; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder. + let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do stuff with the class! + let echo_fut = async { + loop { + class.wait_connection().await; + info!("Connected"); + let _ = echo(&mut class).await; + info!("Disconnected"); + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, echo_fut).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + info!("data: {:x}", data); + class.write_packet(data).await?; + } +} From eb70d744a9ad6c1a9747777eb32b7b22481e77ec Mon Sep 17 00:00:00 2001 From: ftilde Date: Thu, 4 Jan 2024 21:24:09 +0100 Subject: [PATCH 175/760] Expose rx_delay in nrf qspi config --- embassy-nrf/src/qspi.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 0171ceb0e..8eec09c96 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -80,6 +80,8 @@ pub struct Config { pub frequency: Frequency, /// Value is specified in number of 16 MHz periods (62.5 ns) pub sck_delay: u8, + /// Value is specified in number of 64 MHz periods (15.625 ns), valid values between 0 and 7 (inclusive) + pub rx_delay: u8, /// Whether data is captured on the clock rising edge and data is output on a falling edge (MODE0) or vice-versa (MODE3) pub spi_mode: SpiMode, /// Addressing mode (24-bit or 32-bit) @@ -98,6 +100,7 @@ impl Default for Config { deep_power_down: None, frequency: Frequency::M8, sck_delay: 80, + rx_delay: 2, spi_mode: SpiMode::MODE0, address_mode: AddressMode::_24BIT, capacity: 0, @@ -202,6 +205,11 @@ impl<'d, T: Instance> Qspi<'d, T> { w }); + r.iftiming.write(|w| unsafe { + w.rxdelay().bits(config.rx_delay & 0b111); + w + }); + r.xipoffset.write(|w| unsafe { w.xipoffset().bits(config.xip_offset); w From 208ad8fbfcf639ca8876b50686665a3c8817dabe Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 5 Jan 2024 23:49:10 +0100 Subject: [PATCH 176/760] stm32/flash: add support for f1. --- .vscode/settings.json | 8 +++++++- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/flash/f0.rs | 4 ++-- embassy-stm32/src/flash/{f3.rs => f1f3.rs} | 12 ++++++++++-- embassy-stm32/src/flash/f4.rs | 4 ++-- embassy-stm32/src/flash/f7.rs | 4 ++-- embassy-stm32/src/flash/g.rs | 4 ++-- embassy-stm32/src/flash/h7.rs | 8 ++++---- embassy-stm32/src/flash/l.rs | 12 ++++++------ embassy-stm32/src/flash/mod.rs | 6 +++--- 10 files changed, 40 insertions(+), 26 deletions(-) rename embassy-stm32/src/flash/{f3.rs => f1f3.rs} (84%) diff --git a/.vscode/settings.json b/.vscode/settings.json index a5b23175a..46d26562c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,10 +15,16 @@ //"rust-analyzer.cargo.target": "thumbv7m-none-eabi", "rust-analyzer.cargo.target": "thumbv7em-none-eabi", //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", + "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. - "examples/stm32l4/Cargo.toml", + "embassy-stm32/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 844a55cf8..88faf569a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f9f48b067be92fa9ea9dbdce0e85b5d0eb989790" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d5096244fa0b7992454a894a2aeaa369ae674222" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f9f48b067be92fa9ea9dbdce0e85b5d0eb989790", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d5096244fa0b7992454a894a2aeaa369ae674222", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index c0a8d7022..e0c76e6b2 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -20,8 +20,8 @@ pub(crate) unsafe fn lock() { pub(crate) unsafe fn unlock() { if pac::FLASH.cr().read().lock() { - pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); } } diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f1f3.rs similarity index 84% rename from embassy-stm32/src/flash/f3.rs rename to embassy-stm32/src/flash/f1f3.rs index 817ccef4d..e7790369a 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f1f3.rs @@ -20,8 +20,8 @@ pub(crate) unsafe fn lock() { pub(crate) unsafe fn unlock() { if pac::FLASH.cr().read().lock() { - pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); } } @@ -59,6 +59,14 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_strt(true); }); + // Wait for at least one clock cycle before reading the + // BSY bit, because there is a one-cycle delay between + // setting the STRT bit and the BSY bit being asserted + // by hardware. See STM32F105xx, STM32F107xx device errata, + // section 2.2.8 + #[cfg(stm32f1)] + pac::FLASH.cr().read(); + let mut ret: Result<(), Error> = wait_ready_blocking(); if !pac::FLASH.sr().read().eop() { diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 2671dfb04..57447bea5 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -227,8 +227,8 @@ pub(crate) unsafe fn lock() { pub(crate) unsafe fn unlock() { if pac::FLASH.cr().read().lock() { - pac::FLASH.keyr().write(|w| w.set_key(0x45670123)); - pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB)); + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); } } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 6b3e66ac6..0f512bbc4 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -20,8 +20,8 @@ pub(crate) unsafe fn lock() { pub(crate) unsafe fn unlock() { if pac::FLASH.cr().read().lock() { - pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); } } diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index d97b4a932..b69c4343b 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -25,8 +25,8 @@ pub(crate) unsafe fn unlock() { // Unlock flash if pac::FLASH.cr().read().lock() { - pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); } } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 65d163d29..ae395d568 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -27,13 +27,13 @@ pub(crate) unsafe fn lock() { pub(crate) unsafe fn unlock() { if pac::FLASH.bank(0).cr().read().lock() { - pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123)); - pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + pac::FLASH.bank(0).keyr().write_value(0x4567_0123); + pac::FLASH.bank(0).keyr().write_value(0xCDEF_89AB); } if is_dual_bank() { if pac::FLASH.bank(1).cr().read().lock() { - pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123)); - pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + pac::FLASH.bank(1).keyr().write_value(0x4567_0123); + pac::FLASH.bank(1).keyr().write_value(0xCDEF_89AB); } } } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 0b332dc61..b14224bff 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -29,21 +29,21 @@ pub(crate) unsafe fn unlock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] { if pac::FLASH.cr().read().lock() { - pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); } } #[cfg(any(flash_l0, flash_l1))] { if pac::FLASH.pecr().read().pelock() { - pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF)); - pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405)); + pac::FLASH.pekeyr().write_value(0x89AB_CDEF); + pac::FLASH.pekeyr().write_value(0x0203_0405); } if pac::FLASH.pecr().read().prglock() { - pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF)); - pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516)); + pac::FLASH.prgkeyr().write_value(0x8C9D_AEBF); + pac::FLASH.prgkeyr().write_value(0x1314_1516); } } } diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index cbf5c25b2..47232f4a4 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -95,7 +95,7 @@ pub enum FlashBank { #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f0, path = "f0.rs")] -#[cfg_attr(flash_f3, path = "f3.rs")] +#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] #[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")] @@ -103,8 +103,8 @@ pub enum FlashBank { #[cfg_attr(flash_h7ab, path = "h7.rs")] #[cfg_attr( not(any( - flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_g4, - flash_h7, flash_h7ab + flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, + flash_g4, flash_h7, flash_h7ab )), path = "other.rs" )] From fe3973c513a71d20ec2bc2f7d3cefd414f405980 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 6 Jan 2024 11:59:55 +0800 Subject: [PATCH 177/760] mark json file inside .vscode folder as jsonc --- .gitattributes | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 4db9edae7..a51376f0d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,6 +15,8 @@ *.x text *.yml text +.vscode/*.json linguist-language=JSON-with-Comments + *.raw binary *.bin binary *.png binary @@ -38,4 +40,4 @@ *.pdf binary *.ez binary *.bz2 binary -*.swp binary \ No newline at end of file +*.swp binary From 424ddaf3d95417bcfe8b46475c8135aead3792d2 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 6 Jan 2024 22:22:38 +0800 Subject: [PATCH 178/760] impl waveform with TIM Channel --- embassy-stm32/build.rs | 14 ++-- embassy-stm32/src/timer/mod.rs | 25 +++++++ embassy-stm32/src/timer/simple_pwm.rs | 90 +++++++++++++++++++++++++- examples/stm32f4/src/bin/ws2812_pwm.rs | 2 +- 4 files changed, 119 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ef152acd1..7860ee2ff 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1009,6 +1009,10 @@ fn main() { (("dac", "CH1"), quote!(crate::dac::DacDma1)), (("dac", "CH2"), quote!(crate::dac::DacDma2)), (("timer", "UP"), quote!(crate::timer::UpDma)), + (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), + (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), + (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), + (("timer", "CH4"), quote!(crate::timer::Ch4Dma)), ] .into(); @@ -1024,16 +1028,6 @@ fn main() { } if let Some(tr) = signals.get(&(regs.kind, ch.signal)) { - // TIM6 of stm32f334 is special, DMA channel for TIM6 depending on SYSCFG state - if chip_name.starts_with("stm32f334") && p.name == "TIM6" { - continue; - } - - // TIM6 of stm32f378 is special, DMA channel for TIM6 depending on SYSCFG state - if chip_name.starts_with("stm32f378") && p.name == "TIM6" { - continue; - } - let peri = format_ident!("{}", p.name); let channel = if let Some(channel) = &ch.channel { diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index d07fd2776..957098cde 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -311,6 +311,26 @@ pub(crate) mod sealed { .ccmr_output(channel_index / 2) .modify(|w| w.set_ocpe(channel_index % 2, preload)); } + + /// Get capture compare DMA selection + fn get_cc_dma_selection(&self) -> super::vals::Ccds { + Self::regs_gp16().cr2().read().ccds() + } + + /// Set capture compare DMA selection + fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { + Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) + } + + /// Get capture compare DMA enable state + fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { + Self::regs_gp16().dier().read().ccde(channel.index()) + } + + /// Set capture compare DMA enable state + fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { + Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) + } } /// Capture/Compare 16-bit timer instance with complementary pin support. @@ -705,3 +725,8 @@ foreach_interrupt! { // Update Event trigger DMA for every timer dma_trait!(UpDma, Basic16bitInstance); + +dma_trait!(Ch1Dma, CaptureCompare16bitInstance); +dma_trait!(Ch2Dma, CaptureCompare16bitInstance); +dma_trait!(Ch3Dma, CaptureCompare16bitInstance); +dma_trait!(Ch4Dma, CaptureCompare16bitInstance); diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 80f10424c..665557354 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -155,7 +155,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { /// /// Note: /// you will need to provide corresponding TIMx_UP DMA channel to use this method. - pub async fn gen_waveform( + pub async fn waveform_up( &mut self, dma: impl Peripheral

>, channel: Channel, @@ -221,6 +221,94 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { } } +macro_rules! impl_waveform_chx { + ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { + impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { + /// Generate a sequence of PWM waveform + /// + /// Note: + /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. + pub async fn $fn_name(&mut self, dma: impl Peripheral

>, duty: &[u16]) { + use super::vals::Ccds; + + assert!(duty.iter().all(|v| *v <= self.get_max_duty())); + + into_ref!(dma); + + #[allow(clippy::let_unit_value)] // eg. stm32f334 + let req = dma.request(); + + let cc_channel = super::Channel::$cc_ch; + + let original_duty_state = self.get_duty(cc_channel); + let original_enable_state = self.is_enabled(cc_channel); + let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE; + let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); + + if original_cc_dma_on_update { + self.inner.set_cc_dma_selection(Ccds::ONUPDATE) + } + + if !original_cc_dma_enabled { + self.inner.set_cc_dma_enable_state(cc_channel, true); + } + + if !original_enable_state { + self.enable(cc_channel); + } + + unsafe { + #[cfg(not(any(bdma, gpdma)))] + use crate::dma::{Burst, FifoThreshold}; + use crate::dma::{Transfer, TransferOptions}; + + let dma_transfer_option = TransferOptions { + #[cfg(not(any(bdma, gpdma)))] + fifo_threshold: Some(FifoThreshold::Full), + #[cfg(not(any(bdma, gpdma)))] + mburst: Burst::Incr8, + ..Default::default() + }; + + Transfer::new_write( + &mut dma, + req, + duty, + T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, + dma_transfer_option, + ) + .await + }; + + // restore output compare state + if !original_enable_state { + self.disable(cc_channel); + } + + self.set_duty(cc_channel, original_duty_state); + + // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, + // this can almost always trigger a DMA FIFO error. + // + // optional TODO: + // clean FEIF after disable UDE + if !original_cc_dma_enabled { + self.inner.set_cc_dma_enable_state(cc_channel, false); + } + + if !original_cc_dma_on_update { + self.inner.set_cc_dma_selection(Ccds::ONCOMPARE) + } + } + } + }; +} + +impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1); +impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); +impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); +impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); + impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { type Channel = Channel; type Time = Hertz; diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 239709253..6122cea2d 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) { loop { for &color in color_list { // with &mut, we can easily reuse same DMA channel multiple times - ws2812_pwm.gen_waveform(&mut dp.DMA1_CH2, pwm_channel, color).await; + ws2812_pwm.waveform_up(&mut dp.DMA1_CH2, pwm_channel, color).await; // ws2812 need at least 50 us low level input to confirm the input data and change it's state Timer::after_micros(50).await; // wait until ticker tick From 890a1269d05297993ffa7b537739926eb30d5436 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 6 Jan 2024 22:48:21 +0800 Subject: [PATCH 179/760] refactor with clippy --- embassy-stm32/build.rs | 7 ++++--- embassy-stm32/src/timer/complementary_pwm.rs | 3 ++- embassy-stm32/src/timer/mod.rs | 15 ++++++--------- embassy-stm32/src/timer/simple_pwm.rs | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 7860ee2ff..fc876afcc 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -936,9 +936,9 @@ fn main() { } else if pin.signal.starts_with("INN") { // TODO handle in the future when embassy supports differential measurements None - } else if pin.signal.starts_with("IN") && pin.signal.ends_with("b") { + } else if pin.signal.starts_with("IN") && pin.signal.ends_with('b') { // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63 - let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix("b").unwrap(); + let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix('b').unwrap(); Some(32u8 + signal.parse::().unwrap()) } else if pin.signal.starts_with("IN") { Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap()) @@ -1186,7 +1186,7 @@ fn main() { ADC3 and higher are assigned to the adc34 clock in the table The adc3_common cfg directive is added if ADC3_COMMON exists */ - let has_adc3 = METADATA.peripherals.iter().find(|p| p.name == "ADC3_COMMON").is_some(); + let has_adc3 = METADATA.peripherals.iter().any(|p| p.name == "ADC3_COMMON"); let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]); for m in METADATA @@ -1370,6 +1370,7 @@ fn main() { // ======= // ADC3_COMMON is present + #[allow(clippy::print_literal)] if has_adc3 { println!("cargo:rustc-cfg={}", "adc3_common"); } diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 71d7110b5..eddce0404 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -54,6 +54,7 @@ pub struct ComplementaryPwm<'d, T> { impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. + #[allow(clippy::too_many_arguments)] pub fn new( tim: impl Peripheral

+ 'd, _ch1: Option>, @@ -165,7 +166,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C } fn get_period(&self) -> Self::Time { - self.inner.get_frequency().into() + self.inner.get_frequency() } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 957098cde..210bf7153 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -470,20 +470,17 @@ pub enum CountingMode { impl CountingMode { /// Return whether this mode is edge-aligned (up or down). pub fn is_edge_aligned(&self) -> bool { - match self { - CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, - _ => false, - } + matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown) } /// Return whether this mode is center-aligned. pub fn is_center_aligned(&self) -> bool { - match self { + matches!( + self, CountingMode::CenterAlignedDownInterrupts - | CountingMode::CenterAlignedUpInterrupts - | CountingMode::CenterAlignedBothInterrupts => true, - _ => false, - } + | CountingMode::CenterAlignedUpInterrupts + | CountingMode::CenterAlignedBothInterrupts + ) } } diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 665557354..709278c0c 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -323,7 +323,7 @@ impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, } fn get_period(&self) -> Self::Time { - self.inner.get_frequency().into() + self.inner.get_frequency() } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { From b28629822b001a76d2d2dd3747774dad394a6590 Mon Sep 17 00:00:00 2001 From: Maja Piechotka Date: Sat, 6 Jan 2024 15:21:24 -0800 Subject: [PATCH 180/760] boot: Take maximum of READ_SIZE and WRITE_SIZE when checking sizes, fixes #2382 --- embassy-boot/boot/src/firmware_updater/asynch.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs index 64a4b32ec..2e43e1cc1 100644 --- a/embassy-boot/boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/boot/src/firmware_updater/asynch.rs @@ -224,10 +224,10 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { /// /// # Safety /// - /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from - /// and written to. + /// The `aligned` buffer must have a size of maximum of STATE::WRITE_SIZE and STATE::READ_SIZE, + /// and follow the alignment rules for the flash being read from and written to. pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { - assert_eq!(aligned.len(), STATE::WRITE_SIZE); + assert_eq!(aligned.len(), STATE::WRITE_SIZE.max(STATE::READ_SIZE)); Self { state, aligned } } From 3729608e82d1a08926760a180b52bf114ad5b73d Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Mon, 8 Jan 2024 00:03:44 +0100 Subject: [PATCH 181/760] Add buffer size info to read_packet --- embassy-usb/src/class/cdc_acm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index f1066d2f2..2823e522e 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -439,6 +439,7 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> { } /// Reads a single packet from the OUT endpoint. + /// Must be called with a buffer large enough to hold max_packet_size bytes. pub async fn read_packet(&mut self, data: &mut [u8]) -> Result { self.read_ep.read(data).await } From 1f57692d042de781f884d50f0cbd9eea0c71626d Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Mon, 8 Jan 2024 00:20:40 +0100 Subject: [PATCH 182/760] Add function to create logger from class --- embassy-usb-logger/src/lib.rs | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 45d780bf8..422cefb59 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -105,6 +105,34 @@ impl UsbLogger { join(run_fut, join(log_fut, discard_fut)).await; } } + + // Creates the futures needed for the logger from a given class + pub async fn create_future_from_class<'d, D>(&'d self, class: CdcAcmClass<'d, D> ) + where + D: Driver<'d>, + { + const MAX_PACKET_SIZE: u8 = 64; + let (mut sender, mut receiver) = class.split(); + + loop { + let log_fut = async { + let mut rx: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; + sender.wait_connection().await; + loop { + let len = self.buffer.read(&mut rx[..]).await; + let _ = sender.write_packet(&rx[..len]).await; + } + }; + let discard_fut = async { + let mut discard_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; + receiver.wait_connection().await; + loop { + let _ = receiver.read_packet(&mut discard_buf).await; + } + }; + join(log_fut, discard_fut).await; + } + } } impl log::Log for UsbLogger { @@ -153,3 +181,29 @@ macro_rules! run { let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; }; } + +/// Initialize the USB serial logger from a serial class and return the future to run it. +/// +/// Arguments specify the buffer size, log level and the serial class, respectively. +/// +/// # Usage +/// +/// ``` +/// embassy_usb_logger::with_class!(1024, log::LevelFilter::Info, class); +/// ``` +/// +/// # Safety +/// +/// This macro should only be invoked only once since it is setting the global logging state of the application. +#[macro_export] +macro_rules! with_class { + ( $x:expr, $l:expr, $p:ident ) => { + { + static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); + unsafe { + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + } + LOGGER.create_future_from_class($p) + } + }; +} From 6f505feeb1640c3d76c47aa21160a5a802fb6b93 Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Mon, 8 Jan 2024 00:21:02 +0100 Subject: [PATCH 183/760] Add example --- examples/rp/src/bin/usb_serial_with_logger.rs | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 examples/rp/src/bin/usb_serial_with_logger.rs diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs new file mode 100644 index 000000000..4ba4fc25c --- /dev/null +++ b/examples/rp/src/bin/usb_serial_with_logger.rs @@ -0,0 +1,117 @@ +//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip as well as how to create multiple usb classes for one device +//! +//! This creates a USB serial port that echos. It will also print out logging information on a separate serial device + +#![no_std] +#![no_main] + +use defmt::{info, panic}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::USB; +use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::{Builder, Config}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello there!"); + + let p = embassy_rp::init(Default::default()); + + // Create the driver, from the HAL. + let driver = Driver::new(p.USB, Irqs); + + // Create embassy-usb Config + let mut config = Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-serial example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let mut state = State::new(); + let mut logger_state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder. + let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + + // Create a class for the logger + let logger_class = CdcAcmClass::new(&mut builder, &mut logger_state, 64); + + // Creates the logger and returns the logger future + // Note: You'll need to use log::info! afterwards instead of info! for this to work (this also applies to all the other log::* macros) + let log_fut = embassy_usb_logger::with_class!(1024, log::LevelFilter::Info, logger_class); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do stuff with the class! + let echo_fut = async { + loop { + class.wait_connection().await; + log::info!("Connected"); + let _ = echo(&mut class).await; + log::info!("Disconnected"); + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, join(echo_fut, log_fut)).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + info!("data: {:x}", data); + class.write_packet(data).await?; + } +} From f0c750422970db71304101fca821a0c254571604 Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Mon, 8 Jan 2024 00:21:22 +0100 Subject: [PATCH 184/760] Fix log messages not always showing up straight away --- embassy-usb-logger/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 422cefb59..5142d9073 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -93,6 +93,9 @@ impl UsbLogger { loop { let len = self.buffer.read(&mut rx[..]).await; let _ = sender.write_packet(&rx[..len]).await; + if len as u8 == MAX_PACKET_SIZE { + let _ = sender.write_packet(&[]).await; + } } }; let discard_fut = async { @@ -121,6 +124,9 @@ impl UsbLogger { loop { let len = self.buffer.read(&mut rx[..]).await; let _ = sender.write_packet(&rx[..len]).await; + if len as u8 == MAX_PACKET_SIZE { + let _ = sender.write_packet(&[]).await; + } } }; let discard_fut = async { From 03bf72f690f341b9ca7dbcd329df7571fe47d014 Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Mon, 8 Jan 2024 00:24:15 +0100 Subject: [PATCH 185/760] Better explanation --- embassy-usb-logger/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 5142d9073..f197c6874 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -109,7 +109,8 @@ impl UsbLogger { } } - // Creates the futures needed for the logger from a given class + /// Creates the futures needed for the logger from a given class + /// This can be used in cases where the usb device is already in use for another connection pub async fn create_future_from_class<'d, D>(&'d self, class: CdcAcmClass<'d, D> ) where D: Driver<'d>, From 2c6b475f4e663402fd87977d77dcfc4ccb70babb Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Mon, 8 Jan 2024 00:39:32 +0100 Subject: [PATCH 186/760] Fix formatting --- embassy-usb-logger/src/lib.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index f197c6874..a057fcf32 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -111,7 +111,7 @@ impl UsbLogger { /// Creates the futures needed for the logger from a given class /// This can be used in cases where the usb device is already in use for another connection - pub async fn create_future_from_class<'d, D>(&'d self, class: CdcAcmClass<'d, D> ) + pub async fn create_future_from_class<'d, D>(&'d self, class: CdcAcmClass<'d, D>) where D: Driver<'d>, { @@ -121,7 +121,7 @@ impl UsbLogger { loop { let log_fut = async { let mut rx: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; - sender.wait_connection().await; + sender.wait_connection().await; loop { let len = self.buffer.read(&mut rx[..]).await; let _ = sender.write_packet(&rx[..len]).await; @@ -204,13 +204,11 @@ macro_rules! run { /// This macro should only be invoked only once since it is setting the global logging state of the application. #[macro_export] macro_rules! with_class { - ( $x:expr, $l:expr, $p:ident ) => { - { - static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); - unsafe { - let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); - } - LOGGER.create_future_from_class($p) + ( $x:expr, $l:expr, $p:ident ) => {{ + static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); + unsafe { + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); } - }; + LOGGER.create_future_from_class($p) + }}; } From b16cc04036da8bcbfe273cd796c092e8e2a074c9 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Mon, 8 Jan 2024 19:18:24 +0800 Subject: [PATCH 187/760] bug fix --- embassy-stm32/src/timer/simple_pwm.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 709278c0c..ba089ac8b 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -245,7 +245,8 @@ macro_rules! impl_waveform_chx { let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE; let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); - if original_cc_dma_on_update { + // redirect CC DMA request onto Update Event + if !original_cc_dma_on_update { self.inner.set_cc_dma_selection(Ccds::ONUPDATE) } From 45b76455257c9b8f213b23f1164e71d8ad94446a Mon Sep 17 00:00:00 2001 From: Henk Oordt Date: Mon, 8 Jan 2024 13:56:21 +0100 Subject: [PATCH 188/760] Make adc::Resolution::to_max_count const --- embassy-stm32/src/adc/resolution.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 64c25a776..9513e1df7 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -56,7 +56,7 @@ impl Resolution { /// Get the maximum reading value for this resolution. /// /// This is `2**n - 1`. - pub fn to_max_count(&self) -> u32 { + pub const fn to_max_count(&self) -> u32 { match self { #[cfg(adc_v4)] Resolution::SixteenBit => (1 << 16) - 1, From 2498fbdf52e1477ffbfcd8fafba1b04edaf8bc8c Mon Sep 17 00:00:00 2001 From: Vasil Nikolov Date: Tue, 9 Jan 2024 00:26:48 +0200 Subject: [PATCH 189/760] add example of pin sharing between tasks --- examples/rp/src/bin/blinky_two_tasks.rs | 61 +++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 examples/rp/src/bin/blinky_two_tasks.rs diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs new file mode 100644 index 000000000..d6c23b546 --- /dev/null +++ b/examples/rp/src/bin/blinky_two_tasks.rs @@ -0,0 +1,61 @@ +#![no_std] +#![no_main] +/// This example demonstrates how to access a given pin from more than one embassy task +/// The on-board LED is toggled by two tasks with slightly different periods, leading to the +/// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar +/// to interference and the 'beats' you can hear if you play two frequencies close to one another +/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::{gpio, PeripheralRef}; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::Duration; +use embassy_time::{Ticker, Timer}; +use gpio::{AnyPin, Level, Output}; +use {defmt_rtt as _, panic_probe as _}; + +type LedType = Mutex>>>; +static LED: LedType = Mutex::new(None); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + // set the content of the global LED reference to the real LED pin + let led = Output::new(AnyPin::from(p.PIN_25), Level::High); + // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the + // Mutex is released + { + *(LED.lock().await) = Some(PeripheralRef::new(led)); + } + let dt = 100 * 1_000_000; + let k = 1.003; + + unwrap!(spawner.spawn(toggle(&LED, Duration::from_nanos(dt)))); + unwrap!(spawner.spawn(toggle_slightly_slower( + &LED, + Duration::from_nanos((dt as f64 * k) as u64) + ))); +} + +async fn toggle_led(led: &'static LedType, delay: Duration) { + let mut ticker = Ticker::every(delay); + loop { + { + let mut led_unlocked = led.lock().await; + if let Some(pin_ref) = led_unlocked.as_mut() { + pin_ref.toggle(); + } + } + ticker.next().await; + } +} +#[embassy_executor::task] +async fn toggle(led: &'static LedType, delay: Duration) { + toggle_led(led, delay).await +} + +#[embassy_executor::task] +async fn toggle_slightly_slower(led: &'static LedType, delay: Duration) { + toggle_led(led, delay).await +} From ebf46d37aa7b8fd103c6d6008879f89f01cde70a Mon Sep 17 00:00:00 2001 From: Vasil Nikolov Date: Tue, 9 Jan 2024 00:35:11 +0200 Subject: [PATCH 190/760] remove unused import --- examples/rp/src/bin/blinky_two_tasks.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs index d6c23b546..6b4d35165 100644 --- a/examples/rp/src/bin/blinky_two_tasks.rs +++ b/examples/rp/src/bin/blinky_two_tasks.rs @@ -10,8 +10,7 @@ use embassy_executor::Spawner; use embassy_rp::{gpio, PeripheralRef}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; -use embassy_time::Duration; -use embassy_time::{Ticker, Timer}; +use embassy_time::{Duration, Ticker}; use gpio::{AnyPin, Level, Output}; use {defmt_rtt as _, panic_probe as _}; From 8dab88f96d0873851557281128aeb887a10d7c37 Mon Sep 17 00:00:00 2001 From: Chris Price Date: Mon, 8 Jan 2024 21:05:43 +0000 Subject: [PATCH 191/760] Merge TestDriver into MockDriver --- embassy-time/src/driver_mock.rs | 134 +++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 18 deletions(-) diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index c255615c7..128f48af9 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -1,4 +1,4 @@ -use core::cell::Cell; +use core::cell::RefCell; use critical_section::Mutex as CsMutex; @@ -8,7 +8,7 @@ use crate::{Duration, Instant}; /// A mock driver that can be manually advanced. /// This is useful for testing code that works with [`Instant`] and [`Duration`]. /// -/// This driver cannot currently be used to test runtime functionality, such as +/// This driver can also be used to test runtime functionality, such as /// timers, delays, etc. /// /// # Example @@ -26,43 +26,141 @@ use crate::{Duration, Instant}; /// assert_eq!(true, has_a_second_passed(reference)); /// } /// ``` -pub struct MockDriver { - now: CsMutex>, -} +pub struct MockDriver(CsMutex>); -crate::time_driver_impl!(static DRIVER: MockDriver = MockDriver { - now: CsMutex::new(Cell::new(Instant::from_ticks(0))), -}); +crate::time_driver_impl!(static DRIVER: MockDriver = MockDriver::new()); impl MockDriver { + /// Creates a new mock driver. + pub const fn new() -> Self { + Self(CsMutex::new(RefCell::new(InnerMockDriver::new()))) + } + /// Gets a reference to the global mock driver. pub fn get() -> &'static MockDriver { &DRIVER } - /// Advances the time by the specified [`Duration`]. - pub fn advance(&self, duration: Duration) { + /// Resets the internal state of the mock driver + /// This will clear and deallocate all alarms, and reset the current time to 0. + fn reset(&self) { critical_section::with(|cs| { - let now = self.now.borrow(cs).get().as_ticks(); - self.now.borrow(cs).set(Instant::from_ticks(now + duration.as_ticks())); + self.0.borrow(cs).replace(InnerMockDriver::new()); }); } + + /// Advances the time by the specified [`Duration`]. + /// Calling any alarm callbacks that are due. + pub fn advance(&self, duration: Duration) { + let notify = { + critical_section::with(|cs| { + let mut inner = self.0.borrow_ref_mut(cs); + + // TODO: store as Instant? + let now = (Instant::from_ticks(inner.now) + duration).as_ticks(); + + + inner.now = now; + + if inner.alarm <= now { + inner.alarm = u64::MAX; + + Some((inner.callback, inner.ctx)) + } else { + None + } + }) + }; + + if let Some((callback, ctx)) = notify { + (callback)(ctx); + } + } } impl Driver for MockDriver { fn now(&self) -> u64 { - critical_section::with(|cs| self.now.borrow(cs).get().as_ticks() as u64) + critical_section::with(|cs| self.0.borrow_ref(cs).now) } unsafe fn allocate_alarm(&self) -> Option { - unimplemented!("MockDriver does not support runtime features that require an executor"); + Some(AlarmHandle::new(0)) } - fn set_alarm_callback(&self, _alarm: AlarmHandle, _callback: fn(*mut ()), _ctx: *mut ()) { - unimplemented!("MockDriver does not support runtime features that require an executor"); + fn set_alarm_callback(&self, _alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { + critical_section::with(|cs| { + let mut inner = self.0.borrow_ref_mut(cs); + + inner.callback = callback; + inner.ctx = ctx; + }); } - fn set_alarm(&self, _alarm: AlarmHandle, _timestamp: u64) -> bool { - unimplemented!("MockDriver does not support runtime features that require an executor"); + fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool { + critical_section::with(|cs| { + let mut inner = self.0.borrow_ref_mut(cs); + + if timestamp <= inner.now { + false + } else { + inner.alarm = timestamp; + true + } + }) + } +} + +struct InnerMockDriver { + now: u64, + alarm: u64, + callback: fn(*mut ()), + ctx: *mut (), +} + +impl InnerMockDriver { + const fn new() -> Self { + Self { + now: 0, + alarm: u64::MAX, + callback: Self::noop, + ctx: core::ptr::null_mut(), + } + } + + fn noop(_ctx: *mut ()) {} +} + +unsafe impl Send for InnerMockDriver {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_advance() { + let driver = MockDriver::get(); + let reference = driver.now(); + driver.advance(Duration::from_secs(1)); + assert_eq!(Duration::from_secs(1).as_ticks(), driver.now() - reference); + } + + #[test] + fn test_set_alarm_not_in_future() { + let driver = MockDriver::get(); + let alarm = unsafe { AlarmHandle::new(0) }; + assert_eq!(false, driver.set_alarm(alarm, driver.now())); + } + + #[test] + fn test_alarm() { + let driver = MockDriver::get(); + let alarm = unsafe { driver.allocate_alarm() }.expect("No alarms available"); + static mut CALLBACK_CALLED: bool = false; + let ctx = &mut () as *mut (); + driver.set_alarm_callback(alarm, |_| unsafe { CALLBACK_CALLED = true }, ctx); + driver.set_alarm(alarm, driver.now() + 1); + assert_eq!(false, unsafe { CALLBACK_CALLED }); + driver.advance(Duration::from_secs(1)); + assert_eq!(true, unsafe { CALLBACK_CALLED }); } } From fdd7acd48499aac6b3d64eb86d67b198d7ebf5ee Mon Sep 17 00:00:00 2001 From: Chris Price Date: Tue, 9 Jan 2024 11:36:47 +0000 Subject: [PATCH 192/760] Restructure InnerMockDriver Failing test for overallocation of alarms --- embassy-time/src/driver_mock.rs | 63 ++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index 128f48af9..d1c21ab28 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -43,7 +43,7 @@ impl MockDriver { /// Resets the internal state of the mock driver /// This will clear and deallocate all alarms, and reset the current time to 0. - fn reset(&self) { + pub fn reset(&self) { critical_section::with(|cs| { self.0.borrow(cs).replace(InnerMockDriver::new()); }); @@ -56,19 +56,15 @@ impl MockDriver { critical_section::with(|cs| { let mut inner = self.0.borrow_ref_mut(cs); - // TODO: store as Instant? - let now = (Instant::from_ticks(inner.now) + duration).as_ticks(); + inner.now = inner.now + duration; + if inner.alarm.timestamp <= inner.now.as_ticks() { + inner.alarm.timestamp = u64::MAX; - inner.now = now; - - if inner.alarm <= now { - inner.alarm = u64::MAX; - - Some((inner.callback, inner.ctx)) - } else { - None - } + Some((inner.alarm.callback, inner.alarm.ctx)) + } else { + None + } }) }; @@ -80,7 +76,7 @@ impl MockDriver { impl Driver for MockDriver { fn now(&self) -> u64 { - critical_section::with(|cs| self.0.borrow_ref(cs).now) + critical_section::with(|cs| self.0.borrow_ref(cs).now).as_ticks() } unsafe fn allocate_alarm(&self) -> Option { @@ -91,8 +87,8 @@ impl Driver for MockDriver { critical_section::with(|cs| { let mut inner = self.0.borrow_ref_mut(cs); - inner.callback = callback; - inner.ctx = ctx; + inner.alarm.callback = callback; + inner.alarm.ctx = ctx; }); } @@ -100,10 +96,10 @@ impl Driver for MockDriver { critical_section::with(|cs| { let mut inner = self.0.borrow_ref_mut(cs); - if timestamp <= inner.now { + if timestamp <= inner.now.as_ticks() { false } else { - inner.alarm = timestamp; + inner.alarm.timestamp = timestamp; true } }) @@ -111,17 +107,29 @@ impl Driver for MockDriver { } struct InnerMockDriver { - now: u64, - alarm: u64, - callback: fn(*mut ()), - ctx: *mut (), + now: Instant, + alarm: AlarmState, } impl InnerMockDriver { const fn new() -> Self { Self { - now: 0, - alarm: u64::MAX, + now: Instant::from_ticks(0), + alarm: AlarmState::new(), + } + } +} + +struct AlarmState { + timestamp: u64, + callback: fn(*mut ()), + ctx: *mut (), +} + +impl AlarmState { + const fn new() -> Self { + Self { + timestamp: u64::MAX, callback: Self::noop, ctx: core::ptr::null_mut(), } @@ -130,7 +138,7 @@ impl InnerMockDriver { fn noop(_ctx: *mut ()) {} } -unsafe impl Send for InnerMockDriver {} +unsafe impl Send for AlarmState {} #[cfg(test)] mod tests { @@ -163,4 +171,11 @@ mod tests { driver.advance(Duration::from_secs(1)); assert_eq!(true, unsafe { CALLBACK_CALLED }); } + + #[test] + fn test_allocate_alarm() { + let driver = MockDriver::get(); + assert!(unsafe { driver.allocate_alarm() }.is_some()); + assert!(unsafe { driver.allocate_alarm() }.is_none()); + } } From e4e2b314025e82388c10d7847e873de767e6194f Mon Sep 17 00:00:00 2001 From: Chris Price Date: Tue, 9 Jan 2024 12:02:58 +0000 Subject: [PATCH 193/760] Prevent over-allocation --- embassy-time/src/driver_mock.rs | 46 ++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index d1c21ab28..5828dde41 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -58,13 +58,17 @@ impl MockDriver { inner.now = inner.now + duration; - if inner.alarm.timestamp <= inner.now.as_ticks() { - inner.alarm.timestamp = u64::MAX; + let now = inner.now.as_ticks(); - Some((inner.alarm.callback, inner.alarm.ctx)) - } else { - None - } + inner + .alarm + .as_mut() + .filter(|alarm| alarm.timestamp <= now) + .map(|alarm| { + alarm.timestamp = u64::MAX; + + (alarm.callback, alarm.ctx) + }) }) }; @@ -80,15 +84,29 @@ impl Driver for MockDriver { } unsafe fn allocate_alarm(&self) -> Option { - Some(AlarmHandle::new(0)) + critical_section::with(|cs| { + let mut inner = self.0.borrow_ref_mut(cs); + + if inner.alarm.is_some() { + None + } else { + inner.alarm.replace(AlarmState::new()); + + Some(AlarmHandle::new(0)) + } + }) } fn set_alarm_callback(&self, _alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { critical_section::with(|cs| { let mut inner = self.0.borrow_ref_mut(cs); - inner.alarm.callback = callback; - inner.alarm.ctx = ctx; + let Some(alarm) = inner.alarm.as_mut() else { + panic!("Alarm not allocated"); + }; + + alarm.callback = callback; + alarm.ctx = ctx; }); } @@ -99,7 +117,11 @@ impl Driver for MockDriver { if timestamp <= inner.now.as_ticks() { false } else { - inner.alarm.timestamp = timestamp; + let Some(alarm) = inner.alarm.as_mut() else { + panic!("Alarm not allocated"); + }; + + alarm.timestamp = timestamp; true } }) @@ -108,14 +130,14 @@ impl Driver for MockDriver { struct InnerMockDriver { now: Instant, - alarm: AlarmState, + alarm: Option, } impl InnerMockDriver { const fn new() -> Self { Self { now: Instant::from_ticks(0), - alarm: AlarmState::new(), + alarm: None, } } } From 9bf655ccd770a56e33c8de63382407538da094e6 Mon Sep 17 00:00:00 2001 From: Chris Price Date: Tue, 9 Jan 2024 14:07:06 +0000 Subject: [PATCH 194/760] Use MockDriver in queue_generic tests --- embassy-time/src/driver_mock.rs | 18 ++++++ embassy-time/src/queue_generic.rs | 100 +++--------------------------- 2 files changed, 25 insertions(+), 93 deletions(-) diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index 5828dde41..bbb012f62 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -164,10 +164,19 @@ unsafe impl Send for AlarmState {} #[cfg(test)] mod tests { + use serial_test::serial; + use super::*; + fn setup() { + DRIVER.reset(); + } + #[test] + #[serial] fn test_advance() { + setup(); + let driver = MockDriver::get(); let reference = driver.now(); driver.advance(Duration::from_secs(1)); @@ -175,14 +184,20 @@ mod tests { } #[test] + #[serial] fn test_set_alarm_not_in_future() { + setup(); + let driver = MockDriver::get(); let alarm = unsafe { AlarmHandle::new(0) }; assert_eq!(false, driver.set_alarm(alarm, driver.now())); } #[test] + #[serial] fn test_alarm() { + setup(); + let driver = MockDriver::get(); let alarm = unsafe { driver.allocate_alarm() }.expect("No alarms available"); static mut CALLBACK_CALLED: bool = false; @@ -195,7 +210,10 @@ mod tests { } #[test] + #[serial] fn test_allocate_alarm() { + setup(); + let driver = MockDriver::get(); assert!(unsafe { driver.allocate_alarm() }.is_some()); assert!(unsafe { driver.allocate_alarm() }.is_none()); diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs index 77947ab29..89fedf54c 100644 --- a/embassy-time/src/queue_generic.rs +++ b/embassy-time/src/queue_generic.rs @@ -175,6 +175,7 @@ impl TimerQueue for Queue { crate::timer_queue_impl!(static QUEUE: Queue = Queue::new()); #[cfg(test)] +#[cfg(feature = "mock-driver")] mod tests { use core::cell::Cell; use core::task::{RawWaker, RawWakerVTable, Waker}; @@ -184,94 +185,9 @@ mod tests { use serial_test::serial; use crate::driver::{AlarmHandle, Driver}; + use crate::driver_mock::MockDriver; use crate::queue_generic::QUEUE; - use crate::Instant; - - struct InnerTestDriver { - now: u64, - alarm: u64, - callback: fn(*mut ()), - ctx: *mut (), - } - - impl InnerTestDriver { - const fn new() -> Self { - Self { - now: 0, - alarm: u64::MAX, - callback: Self::noop, - ctx: core::ptr::null_mut(), - } - } - - fn noop(_ctx: *mut ()) {} - } - - unsafe impl Send for InnerTestDriver {} - - struct TestDriver(Mutex); - - impl TestDriver { - const fn new() -> Self { - Self(Mutex::new(InnerTestDriver::new())) - } - - fn reset(&self) { - *self.0.lock().unwrap() = InnerTestDriver::new(); - } - - fn set_now(&self, now: u64) { - let notify = { - let mut inner = self.0.lock().unwrap(); - - if inner.now < now { - inner.now = now; - - if inner.alarm <= now { - inner.alarm = u64::MAX; - - Some((inner.callback, inner.ctx)) - } else { - None - } - } else { - panic!("Going back in time?"); - } - }; - - if let Some((callback, ctx)) = notify { - (callback)(ctx); - } - } - } - - impl Driver for TestDriver { - fn now(&self) -> u64 { - self.0.lock().unwrap().now - } - - unsafe fn allocate_alarm(&self) -> Option { - Some(AlarmHandle::new(0)) - } - - fn set_alarm_callback(&self, _alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - let mut inner = self.0.lock().unwrap(); - - inner.callback = callback; - inner.ctx = ctx; - } - - fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool { - let mut inner = self.0.lock().unwrap(); - - if timestamp <= inner.now { - false - } else { - inner.alarm = timestamp; - true - } - } - } + use crate::{Instant, Duration}; struct TestWaker { pub awoken: Rc>, @@ -312,10 +228,8 @@ mod tests { } } - crate::time_driver_impl!(static DRIVER: TestDriver = TestDriver::new()); - fn setup() { - DRIVER.reset(); + MockDriver::get().reset(); critical_section::with(|cs| *QUEUE.inner.borrow_ref_mut(cs) = None); } @@ -382,13 +296,13 @@ mod tests { assert!(!waker.awoken.get()); - DRIVER.set_now(Instant::from_secs(99).as_ticks()); + MockDriver::get().advance(Duration::from_secs(99)); assert!(!waker.awoken.get()); assert_eq!(queue_len(), 1); - DRIVER.set_now(Instant::from_secs(100).as_ticks()); + MockDriver::get().advance(Duration::from_secs(1)); assert!(waker.awoken.get()); @@ -404,7 +318,7 @@ mod tests { QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker); - DRIVER.set_now(Instant::from_secs(50).as_ticks()); + MockDriver::get().advance(Duration::from_secs(50)); let waker2 = TestWaker::new(); From 102e8d8ad6d4a7bc97d8ced018b21e6ef744955f Mon Sep 17 00:00:00 2001 From: Chris Price Date: Tue, 9 Jan 2024 15:24:34 +0000 Subject: [PATCH 195/760] Add mock-driver to ci features for embassy-time --- .github/ci/test.sh | 2 +- ci.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 369f6d221..b16b3c20d 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -11,7 +11,7 @@ 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-time/Cargo.toml --features generic-queue +cargo test --manifest-path ./embassy-time/Cargo.toml --features generic-queue,mock-driver cargo test --manifest-path ./embassy-boot/boot/Cargo.toml cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features ed25519-dalek diff --git a/ci.sh b/ci.sh index 84a724ede..dd028ddda 100755 --- a/ci.sh +++ b/ci.sh @@ -34,7 +34,7 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ - --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ + --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,igmp,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ From 372a9b28334221f301b698cce09c206aca4df9a4 Mon Sep 17 00:00:00 2001 From: Chris Price Date: Tue, 9 Jan 2024 15:57:13 +0000 Subject: [PATCH 196/760] Lint/format fixes --- embassy-time/src/driver_mock.rs | 2 +- embassy-time/src/queue_generic.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index bbb012f62..7533d51e5 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -56,7 +56,7 @@ impl MockDriver { critical_section::with(|cs| { let mut inner = self.0.borrow_ref_mut(cs); - inner.now = inner.now + duration; + inner.now += duration; let now = inner.now.as_ticks(); diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs index 89fedf54c..829368ffc 100644 --- a/embassy-time/src/queue_generic.rs +++ b/embassy-time/src/queue_generic.rs @@ -180,14 +180,12 @@ mod tests { use core::cell::Cell; use core::task::{RawWaker, RawWakerVTable, Waker}; use std::rc::Rc; - use std::sync::Mutex; use serial_test::serial; - use crate::driver::{AlarmHandle, Driver}; use crate::driver_mock::MockDriver; use crate::queue_generic::QUEUE; - use crate::{Instant, Duration}; + use crate::{Duration, Instant}; struct TestWaker { pub awoken: Rc>, From 3db8655e25bf40d0f0b72e557a8d6e3d156119c8 Mon Sep 17 00:00:00 2001 From: Chris Price Date: Tue, 9 Jan 2024 17:36:39 +0000 Subject: [PATCH 197/760] Ignore the doctest driver registration to prevent duplicate registrations --- embassy-time/src/driver.rs | 4 +++- embassy-time/src/queue.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs index 2afa454fe..f966386b7 100644 --- a/embassy-time/src/driver.rs +++ b/embassy-time/src/driver.rs @@ -42,7 +42,6 @@ //! use embassy_time::driver::{Driver, AlarmHandle}; //! //! struct MyDriver{} // not public! -//! embassy_time::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); //! //! impl Driver for MyDriver { //! fn now(&self) -> u64 { @@ -59,6 +58,9 @@ //! } //! } //! ``` +//! ```ignore +//! embassy_time::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); +//! ``` /// Alarm handle, assigned by the driver. #[derive(Clone, Copy)] diff --git a/embassy-time/src/queue.rs b/embassy-time/src/queue.rs index c6f8b440a..d65197c54 100644 --- a/embassy-time/src/queue.rs +++ b/embassy-time/src/queue.rs @@ -23,7 +23,6 @@ //! use embassy_time::queue::{TimerQueue}; //! //! struct MyTimerQueue{}; // not public! -//! embassy_time::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); //! //! impl TimerQueue for MyTimerQueue { //! fn schedule_wake(&'static self, at: Instant, waker: &Waker) { @@ -31,6 +30,9 @@ //! } //! } //! ``` +//! ```ignore +//! embassy_time::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); +//! ``` use core::task::Waker; use crate::Instant; From c9ac39df9451e79958c5b9f40b9c8c982d10c241 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Dec 2023 17:38:34 +0100 Subject: [PATCH 198/760] Update embedded-hal to v1.0 --- cyw43/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 4 ++-- embassy-net-adin1110/Cargo.toml | 8 ++++---- embassy-net-adin1110/src/lib.rs | 10 +++++----- embassy-net-enc28j60/Cargo.toml | 4 ++-- embassy-net-esp-hosted/Cargo.toml | 4 ++-- embassy-net-wiznet/Cargo.toml | 4 ++-- embassy-nrf/Cargo.toml | 4 ++-- embassy-rp/Cargo.toml | 6 +++--- embassy-rp/src/gpio.rs | 18 ------------------ embassy-stm32/Cargo.toml | 6 +++--- embassy-stm32/src/gpio.rs | 21 --------------------- embassy-time/Cargo.toml | 4 ++-- examples/nrf52840/Cargo.toml | 6 +++--- examples/rp/Cargo.toml | 6 +++--- examples/stm32h5/Cargo.toml | 4 ++-- examples/stm32h7/Cargo.toml | 4 ++-- examples/stm32l4/Cargo.toml | 6 +++--- tests/nrf/Cargo.toml | 4 ++-- tests/rp/Cargo.toml | 6 +++--- tests/stm32/Cargo.toml | 4 ++-- 21 files changed, 48 insertions(+), 87 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 72faad805..1042f21bc 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -23,7 +23,7 @@ cortex-m = "0.7.6" cortex-m-rt = "0.7.0" futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } -embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } num_enum = { version = "0.5.7", default-features = false } [package.metadata.embassy_docs] diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index f292f952d..42382f834 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -23,8 +23,8 @@ embassy-time = { version = "0.2", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", ] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } nb = "1.0.0" diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index f1be52da5..52b89fce9 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -12,16 +12,16 @@ repository = "https://github.com/embassy-rs/embassy" heapless = "0.8" defmt = { version = "0.3", optional = true } log = { version = "0.4", default-features = false, optional = true } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } -embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-bus = { version = "0.1", features = ["async"] } embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } embassy-time = { version = "0.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" [dev-dependencies] -embedded-hal-mock = { version = "0.10.0-rc.4", features = ["embedded-hal-async", "eh1"] } +embedded-hal-mock = { git = "https://github.com/Dirbaio/embedded-hal-mock", rev = "e3c820094ea0fc71449916bd790d0e3d76f4c0e4", features = ["embedded-hal-async", "eh1"] } crc = "3.0.1" env_logger = "0.10" critical-section = { version = "1.1.2", features = ["std"] } diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 6ecfa587d..d98e98422 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -777,19 +777,19 @@ mod tests { } struct TestHarnass { - spe: ADIN1110, CsPinMock, MockDelay>>, - spi: Generic, + spe: ADIN1110>, CsPinMock, MockDelay>>, + spi: Generic>, } impl TestHarnass { - pub fn new(expectations: &[SpiTransaction], spi_crc: bool, append_fcs_on_tx: bool) -> Self { + pub fn new(expectations: &[SpiTransaction], spi_crc: bool, append_fcs_on_tx: bool) -> Self { let cs = CsPinMock::default(); let delay = MockDelay {}; let spi = SpiMock::new(expectations); - let spi_dev: ExclusiveDevice, CsPinMock, MockDelay> = + let spi_dev: ExclusiveDevice>, CsPinMock, MockDelay> = ExclusiveDevice::new(spi.clone(), cs, delay); let spe: ADIN1110< - ExclusiveDevice, CsPinMock, MockDelay>, + ExclusiveDevice>, CsPinMock, MockDelay>, > = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx); Self { spe, spi } diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index 8cd723c4c..6d18f708e 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" edition = "2021" [dependencies] -embedded-hal = { version = "1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal = { version = "1.0" } +embedded-hal-async = { version = "1.0" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-time = { version = "0.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 61984dd53..1b022de40 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -16,8 +16,8 @@ embassy-sync = { version = "0.5.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} -embedded-hal = { version = "1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal = { version = "1.0" } +embedded-hal-async = { version = "1.0" } noproto = "0.1.0" heapless = "0.8" diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index f628d8bd1..6ed308596 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -9,8 +9,8 @@ edition = "2021" repository = "https://github.com/embassy-rs/embassy" [dependencies] -embedded-hal = { version = "1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal = { version = "1.0" } +embedded-hal-async = { version = "1.0" } embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } embassy-time = { version = "0.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 837a941a9..7d7346d92 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -117,8 +117,8 @@ embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 4942ca507..8d7a11749 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -92,9 +92,9 @@ fixed = "1.23.1" rp-pac = { version = "6" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } -embedded-hal-nb = { version = "=1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-nb = { version = "1.0" } pio-proc = {version= "0.2" } pio = {version= "0.2.1" } diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 2e6692abe..d66ec0bfe 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -1152,12 +1152,6 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for Output<'d, T> { - fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) - } -} - impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { type Error = Infallible; } @@ -1182,12 +1176,6 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain< } } -impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrain<'d, T> { - fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) - } -} - impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { fn is_high(&mut self) -> Result { Ok(self.is_high()) @@ -1232,12 +1220,6 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for Flex<'d, T> { - fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) - } -} - impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { self.wait_for_high().await; diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 88faf569a..2e5bf0e24 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -42,9 +42,9 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-executor = { version = "0.4.0", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } -embedded-hal-nb = { version = "=1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-nb = { version = "1.0" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index c300a079e..d8677953f 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -1033,13 +1033,6 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for Output<'d, T> { - #[inline] - fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) - } -} - impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { type Error = Infallible; } @@ -1081,13 +1074,6 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain< } } -impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrain<'d, T> { - #[inline] - fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) - } -} - impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { #[inline] fn is_high(&mut self) -> Result { @@ -1112,13 +1098,6 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for Flex<'d, T> { - #[inline] - fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) - } -} - impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { type Error = Infallible; } diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 7259169cd..2beefac83 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -407,8 +407,8 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } futures-util = { version = "0.3.17", default-features = false } critical-section = "1.1" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 02e5cddec..933e8d59e 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -30,9 +30,9 @@ rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.1" usbd-hid = "0.6.0" serde = { version = "1.0.136", default-features = false } -embedded-hal = { version = "1.0.0-rc.3" } -embedded-hal-async = { version = "1.0.0-rc.3" } -embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] } +embedded-hal = { version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-bus = { version = "0.1", features = ["async"] } num-integer = { version = "0.1.45", default-features = false } microfft = "0.5.0" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 4f45e9cc1..07f2ae1c7 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -38,9 +38,9 @@ smart-leds = "0.3.0" heapless = "0.8" usbd-hid = "0.6.1" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = "1.0.0-rc.3" -embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = "1.0" +embedded-hal-bus = { version = "0.1", features = ["async"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-storage = { version = "0.3" } static_cell = "2" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 02e11731a..a636c0a33 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -19,8 +19,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } embedded-io-async = { version = "0.6.1" } embedded-nal-async = { version = "0.7.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index f4dca0e44..041408b9a 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -19,8 +19,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } embedded-nal-async = { version = "0.7.1" } embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 97a27efd2..e434f3bd9 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -24,9 +24,9 @@ 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" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } -embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-bus = { version = "0.1", features = ["async"] } 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 } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index c25388699..8ef51fcdb 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -16,8 +16,8 @@ embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } -embedded-hal-async = { version = "1.0.0-rc.3" } -embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] } +embedded-hal-async = { version = "1.0" } +embedded-hal-bus = { version = "0.1", features = ["async"] } static_cell = "2" perf-client = { path = "../perf-client" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 50a85e116..6be50a2f2 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -24,9 +24,9 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6" } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } -embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-bus = { version = "0.1", features = ["async"] } panic-probe = { version = "0.3.0", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } embedded-io-async = { version = "0.6.1" } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 2f5340a6a..c4ce42922 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -63,8 +63,8 @@ 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" -embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" } -embedded-hal-async = { version = "=1.0.0-rc.3" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } micromath = "2.0.0" panic-probe = { version = "0.3.0", features = ["print-defmt"] } rand_core = { version = "0.6", default-features = false } From 4843c060d0fcad11eb639558ccbf18d6362e94c1 Mon Sep 17 00:00:00 2001 From: Vasil Nikolov Date: Wed, 10 Jan 2024 00:47:45 +0200 Subject: [PATCH 199/760] no need for a PeripheralRef --- examples/rp/src/bin/blinky_two_tasks.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs index 6b4d35165..7e0b531e1 100644 --- a/examples/rp/src/bin/blinky_two_tasks.rs +++ b/examples/rp/src/bin/blinky_two_tasks.rs @@ -7,14 +7,14 @@ /// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) use defmt::*; use embassy_executor::Spawner; -use embassy_rp::{gpio, PeripheralRef}; +use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Ticker}; use gpio::{AnyPin, Level, Output}; use {defmt_rtt as _, panic_probe as _}; -type LedType = Mutex>>>; +type LedType = Mutex>>; static LED: LedType = Mutex::new(None); #[embassy_executor::main] @@ -25,7 +25,7 @@ async fn main(spawner: Spawner) { // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the // Mutex is released { - *(LED.lock().await) = Some(PeripheralRef::new(led)); + *(LED.lock().await) = Some(led); } let dt = 100 * 1_000_000; let k = 1.003; From 781e33023e3755bddecba23fb3c2dab10e16ccc6 Mon Sep 17 00:00:00 2001 From: Vasil Nikolov Date: Wed, 10 Jan 2024 00:49:54 +0200 Subject: [PATCH 200/760] add draft doc page for peripheral sharing --- docs/modules/ROOT/nav.adoc | 1 + .../ROOT/pages/sharing_peripherals.adoc | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 docs/modules/ROOT/pages/sharing_peripherals.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index fabb80e31..b692c44e1 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -6,6 +6,7 @@ * xref:layer_by_layer.adoc[Bare metal to async] * xref:runtime.adoc[Executor] * xref:delaying_a_task.adoc[Delaying a Task] +* xref:sharing_peripherals.adoc[Sharing peripherals between tasks] * xref:hal.adoc[HAL] ** xref:nrf.adoc[nRF] ** xref:stm32.adoc[STM32] diff --git a/docs/modules/ROOT/pages/sharing_peripherals.adoc b/docs/modules/ROOT/pages/sharing_peripherals.adoc new file mode 100644 index 000000000..41f467942 --- /dev/null +++ b/docs/modules/ROOT/pages/sharing_peripherals.adoc @@ -0,0 +1,78 @@ += Sharing peripherals between tasks + +Often times, more than one task needs access to the same resource (pin, communication interface, etc.). The following example shows how to use the on-board LED on a Raspberry Pi Pico board by two tasks simultaneously. + +[,rust] +---- +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::{Duration, Ticker}; +use gpio::{AnyPin, Level, Output}; +use {defmt_rtt as _, panic_probe as _}; + +type LedType = Mutex>>; +static LED: LedType = Mutex::new(None); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + // set the content of the global LED reference to the real LED pin + let led = Output::new(AnyPin::from(p.PIN_25), Level::High); + // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the + // Mutex is released + { + *(LED.lock().await) = Some(led); + } + let dt = 100 * 1_000_000; + let k = 1.003; + + unwrap!(spawner.spawn(toggle(&LED, Duration::from_nanos(dt)))); + unwrap!(spawner.spawn(toggle_slightly_slower( + &LED, + Duration::from_nanos((dt as f64 * k) as u64) + ))); +} + +async fn toggle_led(led: &'static LedType, delay: Duration) { + let mut ticker = Ticker::every(delay); + loop { + { + let mut led_unlocked = led.lock().await; + if let Some(pin_ref) = led_unlocked.as_mut() { + pin_ref.toggle(); + } + } + ticker.next().await; + } +} +#[embassy_executor::task] +async fn toggle(led: &'static LedType, delay: Duration) { + toggle_led(led, delay).await +} + +#[embassy_executor::task] +async fn toggle_slightly_slower(led: &'static LedType, delay: Duration) { + toggle_led(led, delay).await +} +---- + +The structure facilitating access to the resource is the defined `LedType`. + +== Why so complicated + +Unwrapping the layers gives insight into why each one is needed. + +=== `Mutex` + +The mutex is there so if one task gets the resource first and begins modifying it, all other tasks wanting to write will have to wait (the `led.lock().await` will return immediately if no task has locked the mutex, and will block if it is accessed somewhere else). + +=== `Option` + +The `LED` variable needs to be defined outside the main task as references accepted by tasks need to be `'static`. However, if it is outside the main task, it cannot be initialised to point to any pin, as the pins themselves are not initialised. Thus, it is set to `None`. + +=== `Output` + +To indicate that the pin will be set to an Output. The `AnyPin` could have been `embassy_rp::peripherals::PIN_25`, however this option lets the `toggle_led` function be more generic. From 495b8b739aaba3d1fe7e105559c830496fabb1d7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 9 Jan 2024 23:58:26 +0100 Subject: [PATCH 201/760] Change GPIO inherent methods back to `&self`. With the embedded-hal rc3 update I changed them to require `&mut self`, but in retrospect I think `&self` is better, for extra flexibility. This PR reverts the changes from the rc3 update to inherent methods. --- .../layer-by-layer/blinky-hal/src/main.rs | 2 +- embassy-nrf/src/gpio.rs | 66 +++++------- embassy-nrf/src/gpiote.rs | 6 +- embassy-rp/src/gpio.rs | 101 ++++++++---------- embassy-stm32/src/exti.rs | 14 +-- embassy-stm32/src/gpio.rs | 94 ++++++++-------- embassy-time/CHANGELOG.md | 4 +- examples/rp/src/bin/button.rs | 2 +- examples/stm32c0/src/bin/button.rs | 2 +- examples/stm32f3/src/bin/button.rs | 2 +- examples/stm32f4/src/bin/button.rs | 2 +- examples/stm32f7/src/bin/button.rs | 2 +- examples/stm32g0/src/bin/button.rs | 2 +- examples/stm32g4/src/bin/button.rs | 2 +- examples/stm32l0/src/bin/button.rs | 2 +- examples/stm32l4/src/bin/button.rs | 2 +- .../src/bin/spe_adin1110_http_server.rs | 8 +- .../stm32l4/src/bin/spi_blocking_async.rs | 2 +- examples/stm32l4/src/bin/spi_dma.rs | 2 +- examples/stm32wl/src/bin/button.rs | 2 +- tests/rp/src/bin/gpio.rs | 10 +- tests/rp/src/bin/pwm.rs | 8 +- tests/stm32/src/bin/gpio.rs | 12 +-- 23 files changed, 157 insertions(+), 192 deletions(-) diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs index 54b87662e..d0c9f4907 100644 --- a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs +++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs @@ -9,7 +9,7 @@ use {defmt_rtt as _, panic_probe as _}; fn main() -> ! { let p = embassy_stm32::init(Default::default()); let mut led = Output::new(p.PB14, Level::High, Speed::VeryHigh); - let mut button = Input::new(p.PC13, Pull::Up); + let button = Input::new(p.PC13, Pull::Up); loop { if button.is_low() { diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 27c18383f..eabf409dd 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -52,19 +52,19 @@ impl<'d, T: Pin> Input<'d, T> { /// Get whether the pin input level is high. #[inline] - pub fn is_high(&mut self) -> bool { + pub fn is_high(&self) -> bool { self.pin.is_high() } /// Get whether the pin input level is low. #[inline] - pub fn is_low(&mut self) -> bool { + pub fn is_low(&self) -> bool { self.pin.is_low() } /// Get the pin input level. #[inline] - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.pin.get_level() } } @@ -166,19 +166,19 @@ impl<'d, T: Pin> Output<'d, T> { /// Get whether the output level is set to high. #[inline] - pub fn is_set_high(&mut self) -> bool { + pub fn is_set_high(&self) -> bool { self.pin.is_set_high() } /// Get whether the output level is set to low. #[inline] - pub fn is_set_low(&mut self) -> bool { + pub fn is_set_low(&self) -> bool { self.pin.is_set_low() } /// Get the current output level. #[inline] - pub fn get_output_level(&mut self) -> Level { + pub fn get_output_level(&self) -> Level { self.pin.get_output_level() } } @@ -283,24 +283,19 @@ impl<'d, T: Pin> Flex<'d, T> { /// Get whether the pin input level is high. #[inline] - pub fn is_high(&mut self) -> bool { + pub fn is_high(&self) -> bool { !self.is_low() } /// Get whether the pin input level is low. #[inline] - pub fn is_low(&mut self) -> bool { - self.ref_is_low() - } - - #[inline] - pub(crate) fn ref_is_low(&self) -> bool { + pub fn is_low(&self) -> bool { self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 } /// Get the pin input level. #[inline] - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.is_high().into() } @@ -337,24 +332,19 @@ impl<'d, T: Pin> Flex<'d, T> { /// Get whether the output level is set to high. #[inline] - pub fn is_set_high(&mut self) -> bool { + pub fn is_set_high(&self) -> bool { !self.is_set_low() } /// Get whether the output level is set to low. #[inline] - pub fn is_set_low(&mut self) -> bool { - self.ref_is_set_low() - } - - #[inline] - pub(crate) fn ref_is_set_low(&self) -> bool { + pub fn is_set_low(&self) -> bool { self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 } /// Get the current output level. #[inline] - pub fn get_output_level(&mut self) -> Level { + pub fn get_output_level(&self) -> Level { self.is_set_high().into() } } @@ -524,11 +514,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(!self.pin.ref_is_low()) + Ok(self.is_high()) } fn is_low(&self) -> Result { - Ok(self.pin.ref_is_low()) + Ok(self.is_low()) } } @@ -546,11 +536,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { fn is_set_high(&self) -> Result { - Ok(!self.pin.ref_is_set_low()) + Ok(self.is_set_high()) } fn is_set_low(&self) -> Result { - Ok(self.pin.ref_is_set_low()) + Ok(self.is_set_low()) } } @@ -570,11 +560,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(!self.ref_is_low()) + Ok(self.is_high()) } fn is_low(&self) -> Result { - Ok(self.ref_is_low()) + Ok(self.is_low()) } } @@ -592,11 +582,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { fn is_set_high(&self) -> Result { - Ok(!self.ref_is_set_low()) + Ok(self.is_set_high()) } fn is_set_low(&self) -> Result { - Ok(self.ref_is_set_low()) + Ok(self.is_set_low()) } } @@ -616,11 +606,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } @@ -640,11 +630,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { fn is_set_high(&mut self) -> Result { - Ok(self.is_set_high()) + Ok((*self).is_set_high()) } fn is_set_low(&mut self) -> Result { - Ok(self.is_set_low()) + Ok((*self).is_set_low()) } } @@ -657,11 +647,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { /// If the pin is not in input mode the result is unspecified. impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } @@ -677,10 +667,10 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { fn is_set_high(&mut self) -> Result { - Ok(self.is_set_high()) + Ok((*self).is_set_high()) } fn is_set_low(&mut self) -> Result { - Ok(self.is_set_low()) + Ok((*self).is_set_low()) } } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 07196abf7..8020b8dc2 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -243,7 +243,7 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { /// Create a new GPIOTE output channel driver. - pub fn new(ch: impl Peripheral

+ 'd, mut pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { + pub fn new(ch: impl Peripheral

+ 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { into_ref!(ch); let g = regs(); let num = ch.number(); @@ -481,11 +481,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(!self.pin.pin.ref_is_low()) + Ok(self.pin.is_high()) } fn is_low(&self) -> Result { - Ok(self.pin.pin.ref_is_low()) + Ok(self.pin.is_low()) } } } diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index d66ec0bfe..7eb57bbe6 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -127,19 +127,19 @@ impl<'d, T: Pin> Input<'d, T> { /// Get whether the pin input level is high. #[inline] - pub fn is_high(&mut self) -> bool { + pub fn is_high(&self) -> bool { self.pin.is_high() } /// Get whether the pin input level is low. #[inline] - pub fn is_low(&mut self) -> bool { + pub fn is_low(&self) -> bool { self.pin.is_low() } /// Returns current pin level #[inline] - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.pin.get_level() } @@ -394,19 +394,19 @@ impl<'d, T: Pin> Output<'d, T> { /// Is the output pin set as high? #[inline] - pub fn is_set_high(&mut self) -> bool { + pub fn is_set_high(&self) -> bool { self.pin.is_set_high() } /// Is the output pin set as low? #[inline] - pub fn is_set_low(&mut self) -> bool { + pub fn is_set_low(&self) -> bool { self.pin.is_set_low() } /// What level output is set to #[inline] - pub fn get_output_level(&mut self) -> Level { + pub fn get_output_level(&self) -> Level { self.pin.get_output_level() } @@ -472,19 +472,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { /// Is the output level high? #[inline] - pub fn is_set_high(&mut self) -> bool { + pub fn is_set_high(&self) -> bool { !self.is_set_low() } /// Is the output level low? #[inline] - pub fn is_set_low(&mut self) -> bool { + pub fn is_set_low(&self) -> bool { self.pin.is_set_as_output() } /// What level output is set to #[inline] - pub fn get_output_level(&mut self) -> Level { + pub fn get_output_level(&self) -> Level { self.is_set_high().into() } @@ -496,19 +496,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { /// Get whether the pin input level is high. #[inline] - pub fn is_high(&mut self) -> bool { + pub fn is_high(&self) -> bool { self.pin.is_high() } /// Get whether the pin input level is low. #[inline] - pub fn is_low(&mut self) -> bool { + pub fn is_low(&self) -> bool { self.pin.is_low() } /// Returns current pin level #[inline] - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.is_high().into() } @@ -640,12 +640,7 @@ impl<'d, T: Pin> Flex<'d, T> { /// Set as output pin. #[inline] - pub fn is_set_as_output(&mut self) -> bool { - self.ref_is_set_as_output() - } - - #[inline] - pub(crate) fn ref_is_set_as_output(&self) -> bool { + fn is_set_as_output(&self) -> bool { (self.pin.sio_oe().value().read() & self.bit()) != 0 } @@ -657,24 +652,19 @@ impl<'d, T: Pin> Flex<'d, T> { /// Get whether the pin input level is high. #[inline] - pub fn is_high(&mut self) -> bool { + pub fn is_high(&self) -> bool { !self.is_low() } /// Get whether the pin input level is low. #[inline] - pub fn is_low(&mut self) -> bool { - self.ref_is_low() - } - - #[inline] - pub(crate) fn ref_is_low(&self) -> bool { + pub fn is_low(&self) -> bool { self.pin.sio_in().read() & self.bit() == 0 } /// Returns current pin level #[inline] - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.is_high().into() } @@ -701,24 +691,19 @@ impl<'d, T: Pin> Flex<'d, T> { /// Is the output level high? #[inline] - pub fn is_set_high(&mut self) -> bool { + pub fn is_set_high(&self) -> bool { !self.is_set_low() } /// Is the output level low? #[inline] - pub fn is_set_low(&mut self) -> bool { - self.ref_is_set_low() - } - - #[inline] - pub(crate) fn ref_is_set_low(&self) -> bool { + pub fn is_set_low(&self) -> bool { (self.pin.sio_out().value().read() & self.bit()) == 0 } /// What level output is set to #[inline] - pub fn get_output_level(&mut self) -> Level { + pub fn get_output_level(&self) -> Level { self.is_set_high().into() } @@ -989,11 +974,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(!self.pin.ref_is_low()) + Ok(self.is_high()) } fn is_low(&self) -> Result { - Ok(self.pin.ref_is_low()) + Ok(self.is_low()) } } @@ -1011,11 +996,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { fn is_set_high(&self) -> Result { - Ok(!self.pin.ref_is_set_low()) + Ok(self.is_set_high()) } fn is_set_low(&self) -> Result { - Ok(self.pin.ref_is_set_low()) + Ok(self.is_set_low()) } } @@ -1031,11 +1016,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(!self.pin.ref_is_low()) + Ok(self.is_high()) } fn is_low(&self) -> Result { - Ok(self.pin.ref_is_low()) + Ok(self.is_low()) } } @@ -1055,11 +1040,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { fn is_set_high(&self) -> Result { - Ok(!self.pin.ref_is_set_as_output()) + Ok(self.is_set_high()) } fn is_set_low(&self) -> Result { - Ok(self.pin.ref_is_set_as_output()) + Ok(self.is_set_low()) } } @@ -1075,11 +1060,11 @@ mod eh02 { type Error = Infallible; fn is_high(&self) -> Result { - Ok(!self.ref_is_low()) + Ok(self.is_high()) } fn is_low(&self) -> Result { - Ok(self.ref_is_low()) + Ok(self.is_low()) } } @@ -1097,11 +1082,11 @@ mod eh02 { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { fn is_set_high(&self) -> Result { - Ok(!self.ref_is_set_low()) + Ok(self.is_set_high()) } fn is_set_low(&self) -> Result { - Ok(self.ref_is_set_low()) + Ok(self.is_set_low()) } } @@ -1120,11 +1105,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } @@ -1144,11 +1129,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { fn is_set_high(&mut self) -> Result { - Ok(self.is_set_high()) + Ok((*self).is_set_high()) } fn is_set_low(&mut self) -> Result { - Ok(self.is_set_low()) + Ok((*self).is_set_low()) } } @@ -1168,21 +1153,21 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { fn is_set_high(&mut self) -> Result { - Ok(self.is_set_high()) + Ok((*self).is_set_high()) } fn is_set_low(&mut self) -> Result { - Ok(self.is_set_low()) + Ok((*self).is_set_low()) } } impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } @@ -1192,11 +1177,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } @@ -1212,11 +1197,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { fn is_set_high(&mut self) -> Result { - Ok(self.is_set_high()) + Ok((*self).is_set_high()) } fn is_set_low(&mut self) -> Result { - Ok(self.is_set_low()) + Ok((*self).is_set_low()) } } diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index f83bae3ff..2821435ef 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -106,17 +106,17 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { } /// Get whether the pin is high. - pub fn is_high(&mut self) -> bool { + pub fn is_high(&self) -> bool { self.pin.is_high() } /// Get whether the pin is low. - pub fn is_low(&mut self) -> bool { + pub fn is_low(&self) -> bool { self.pin.is_low() } /// Get the pin level. - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.pin.get_level() } @@ -166,11 +166,11 @@ impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T> type Error = Infallible; fn is_high(&self) -> Result { - Ok(!self.pin.pin.ref_is_low()) + Ok(self.is_high()) } fn is_low(&self) -> Result { - Ok(self.pin.pin.ref_is_low()) + Ok(self.is_low()) } } @@ -180,11 +180,11 @@ impl<'d, T: GpioPin> embedded_hal_1::digital::ErrorType for ExtiInput<'d, T> { impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index d8677953f..7eb70496f 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -150,49 +150,39 @@ impl<'d, T: Pin> Flex<'d, T> { /// Get whether the pin input level is high. #[inline] - pub fn is_high(&mut self) -> bool { - !self.ref_is_low() + pub fn is_high(&self) -> bool { + !self.is_low() } /// Get whether the pin input level is low. #[inline] - pub fn is_low(&mut self) -> bool { - self.ref_is_low() - } - - #[inline] - pub(crate) fn ref_is_low(&self) -> bool { + pub fn is_low(&self) -> bool { let state = self.pin.block().idr().read().idr(self.pin.pin() as _); state == vals::Idr::LOW } /// Get the current pin input level. #[inline] - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.is_high().into() } /// Get whether the output level is set to high. #[inline] - pub fn is_set_high(&mut self) -> bool { - !self.ref_is_set_low() + pub fn is_set_high(&self) -> bool { + !self.is_set_low() } /// Get whether the output level is set to low. #[inline] - pub fn is_set_low(&mut self) -> bool { - self.ref_is_set_low() - } - - #[inline] - pub(crate) fn ref_is_set_low(&self) -> bool { + pub fn is_set_low(&self) -> bool { let state = self.pin.block().odr().read().odr(self.pin.pin() as _); state == vals::Odr::LOW } /// Get the current output level. #[inline] - pub fn get_output_level(&mut self) -> Level { + pub fn get_output_level(&self) -> Level { self.is_set_high().into() } @@ -346,19 +336,19 @@ impl<'d, T: Pin> Input<'d, T> { /// Get whether the pin input level is high. #[inline] - pub fn is_high(&mut self) -> bool { + pub fn is_high(&self) -> bool { self.pin.is_high() } /// Get whether the pin input level is low. #[inline] - pub fn is_low(&mut self) -> bool { + pub fn is_low(&self) -> bool { self.pin.is_low() } /// Get the current pin input level. #[inline] - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.pin.get_level() } } @@ -445,19 +435,19 @@ impl<'d, T: Pin> Output<'d, T> { /// Is the output pin set as high? #[inline] - pub fn is_set_high(&mut self) -> bool { + pub fn is_set_high(&self) -> bool { self.pin.is_set_high() } /// Is the output pin set as low? #[inline] - pub fn is_set_low(&mut self) -> bool { + pub fn is_set_low(&self) -> bool { self.pin.is_set_low() } /// What level output is set to #[inline] - pub fn get_output_level(&mut self) -> Level { + pub fn get_output_level(&self) -> Level { self.pin.get_output_level() } @@ -506,19 +496,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { /// Get whether the pin input level is high. #[inline] - pub fn is_high(&mut self) -> bool { + pub fn is_high(&self) -> bool { !self.pin.is_low() } /// Get whether the pin input level is low. #[inline] - pub fn is_low(&mut self) -> bool { + pub fn is_low(&self) -> bool { self.pin.is_low() } /// Get the current pin input level. #[inline] - pub fn get_level(&mut self) -> Level { + pub fn get_level(&self) -> Level { self.pin.get_level() } @@ -542,19 +532,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { /// Get whether the output level is set to high. #[inline] - pub fn is_set_high(&mut self) -> bool { + pub fn is_set_high(&self) -> bool { self.pin.is_set_high() } /// Get whether the output level is set to low. #[inline] - pub fn is_set_low(&mut self) -> bool { + pub fn is_set_low(&self) -> bool { self.pin.is_set_low() } /// Get the current output level. #[inline] - pub fn get_output_level(&mut self) -> Level { + pub fn get_output_level(&self) -> Level { self.pin.get_output_level() } @@ -851,12 +841,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { #[inline] fn is_high(&self) -> Result { - Ok(!self.pin.ref_is_low()) + Ok(self.is_high()) } #[inline] fn is_low(&self) -> Result { - Ok(self.pin.ref_is_low()) + Ok(self.is_low()) } } @@ -879,13 +869,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { #[inline] fn is_set_high(&self) -> Result { - Ok(!self.pin.ref_is_set_low()) + Ok(self.is_set_high()) } /// Is the output pin set as low? #[inline] fn is_set_low(&self) -> Result { - Ok(self.pin.ref_is_set_low()) + Ok(self.is_set_low()) } } @@ -917,13 +907,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { #[inline] fn is_set_high(&self) -> Result { - Ok(!self.pin.ref_is_set_low()) + Ok(self.is_set_high()) } /// Is the output pin set as low? #[inline] fn is_set_low(&self) -> Result { - Ok(self.pin.ref_is_set_low()) + Ok(self.is_set_low()) } } @@ -941,12 +931,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { #[inline] fn is_high(&self) -> Result { - Ok(!self.ref_is_low()) + Ok(self.is_high()) } #[inline] fn is_low(&self) -> Result { - Ok(self.ref_is_low()) + Ok(self.is_low()) } } @@ -969,13 +959,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { #[inline] fn is_set_high(&self) -> Result { - Ok(!self.ref_is_set_low()) + Ok(self.is_set_high()) } /// Is the output pin set as low? #[inline] fn is_set_low(&self) -> Result { - Ok(self.ref_is_set_low()) + Ok(self.is_set_low()) } } @@ -995,12 +985,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { #[inline] fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } #[inline] fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } @@ -1023,13 +1013,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { #[inline] fn is_set_high(&mut self) -> Result { - Ok(self.is_set_high()) + Ok((*self).is_set_high()) } /// Is the output pin set as low? #[inline] fn is_set_low(&mut self) -> Result { - Ok(self.is_set_low()) + Ok((*self).is_set_low()) } } @@ -1040,12 +1030,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { #[inline] fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } #[inline] fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } @@ -1064,25 +1054,25 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { #[inline] fn is_set_high(&mut self) -> Result { - Ok(self.is_set_high()) + Ok((*self).is_set_high()) } /// Is the output pin set as low? #[inline] fn is_set_low(&mut self) -> Result { - Ok(self.is_set_low()) + Ok((*self).is_set_low()) } } impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { #[inline] fn is_high(&mut self) -> Result { - Ok(self.is_high()) + Ok((*self).is_high()) } #[inline] fn is_low(&mut self) -> Result { - Ok(self.is_low()) + Ok((*self).is_low()) } } @@ -1105,13 +1095,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { #[inline] fn is_set_high(&mut self) -> Result { - Ok(self.is_set_high()) + Ok((*self).is_set_high()) } /// Is the output pin set as low? #[inline] fn is_set_low(&mut self) -> Result { - Ok(self.is_set_low()) + Ok((*self).is_set_low()) } } diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 99f6ef7ac..d8c0c7d08 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -24,8 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.1.3 - 2023-08-28 -- Update `embedded-hal-async` to `1.0.0-rc.3` -- Update `embedded-hal v1` to `1.0.0-rc.3` +- Update `embedded-hal-async` to `1.0.0-rc.2` +- Update `embedded-hal v1` to `1.0.0-rc.2` ## 0.1.2 - 2023-07-05 diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs index e9054fd48..4ad2ca3b7 100644 --- a/examples/rp/src/bin/button.rs +++ b/examples/rp/src/bin/button.rs @@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) { // Use PIN_28, Pin34 on J0 for RP Pico, as a input. // You need to add your own button. - let mut button = Input::new(p.PIN_28, Pull::Up); + let button = Input::new(p.PIN_28, Pull::Up); loop { if button.is_high() { diff --git a/examples/stm32c0/src/bin/button.rs b/examples/stm32c0/src/bin/button.rs index 265200132..8017f0274 100644 --- a/examples/stm32c0/src/bin/button.rs +++ b/examples/stm32c0/src/bin/button.rs @@ -12,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut button = Input::new(p.PC13, Pull::Up); + let button = Input::new(p.PC13, Pull::Up); loop { if button.is_high() { diff --git a/examples/stm32f3/src/bin/button.rs b/examples/stm32f3/src/bin/button.rs index 2cd356787..406730aae 100644 --- a/examples/stm32f3/src/bin/button.rs +++ b/examples/stm32f3/src/bin/button.rs @@ -12,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut button = Input::new(p.PA0, Pull::Down); + let button = Input::new(p.PA0, Pull::Down); let mut led1 = Output::new(p.PE9, Level::High, Speed::Low); let mut led2 = Output::new(p.PE15, Level::High, Speed::Low); diff --git a/examples/stm32f4/src/bin/button.rs b/examples/stm32f4/src/bin/button.rs index ad30a56a2..564908998 100644 --- a/examples/stm32f4/src/bin/button.rs +++ b/examples/stm32f4/src/bin/button.rs @@ -12,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut button = Input::new(p.PC13, Pull::Down); + let button = Input::new(p.PC13, Pull::Down); let mut led1 = Output::new(p.PB0, Level::High, Speed::Low); let _led2 = Output::new(p.PB7, Level::High, Speed::Low); let mut led3 = Output::new(p.PB14, Level::High, Speed::Low); diff --git a/examples/stm32f7/src/bin/button.rs b/examples/stm32f7/src/bin/button.rs index ad30a56a2..564908998 100644 --- a/examples/stm32f7/src/bin/button.rs +++ b/examples/stm32f7/src/bin/button.rs @@ -12,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut button = Input::new(p.PC13, Pull::Down); + let button = Input::new(p.PC13, Pull::Down); let mut led1 = Output::new(p.PB0, Level::High, Speed::Low); let _led2 = Output::new(p.PB7, Level::High, Speed::Low); let mut led3 = Output::new(p.PB14, Level::High, Speed::Low); diff --git a/examples/stm32g0/src/bin/button.rs b/examples/stm32g0/src/bin/button.rs index 265200132..8017f0274 100644 --- a/examples/stm32g0/src/bin/button.rs +++ b/examples/stm32g0/src/bin/button.rs @@ -12,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut button = Input::new(p.PC13, Pull::Up); + let button = Input::new(p.PC13, Pull::Up); loop { if button.is_high() { diff --git a/examples/stm32g4/src/bin/button.rs b/examples/stm32g4/src/bin/button.rs index 6f3db0819..daebdd04d 100644 --- a/examples/stm32g4/src/bin/button.rs +++ b/examples/stm32g4/src/bin/button.rs @@ -12,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut button = Input::new(p.PC13, Pull::Down); + let button = Input::new(p.PC13, Pull::Down); loop { if button.is_high() { diff --git a/examples/stm32l0/src/bin/button.rs b/examples/stm32l0/src/bin/button.rs index 165a714a5..707486cdc 100644 --- a/examples/stm32l0/src/bin/button.rs +++ b/examples/stm32l0/src/bin/button.rs @@ -11,7 +11,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut button = Input::new(p.PB2, Pull::Up); + let button = Input::new(p.PB2, Pull::Up); let mut led1 = Output::new(p.PA5, Level::High, Speed::Low); let mut led2 = Output::new(p.PB5, Level::High, Speed::Low); diff --git a/examples/stm32l4/src/bin/button.rs b/examples/stm32l4/src/bin/button.rs index 15288c61e..1f3270214 100644 --- a/examples/stm32l4/src/bin/button.rs +++ b/examples/stm32l4/src/bin/button.rs @@ -11,7 +11,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut button = Input::new(p.PC13, Pull::Up); + let button = Input::new(p.PC13, Pull::Up); loop { if button.is_high() { diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 9565ae168..5b4cdfe5e 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -111,8 +111,8 @@ async fn main(spawner: Spawner) { let led_uc4_blue = Output::new(dp.PG15, Level::High, Speed::Low); // Read the uc_cfg switches - let mut uc_cfg0 = Input::new(dp.PB2, Pull::None); - let mut uc_cfg1 = Input::new(dp.PF11, Pull::None); + let uc_cfg0 = Input::new(dp.PB2, Pull::None); + let uc_cfg1 = Input::new(dp.PF11, Pull::None); let _uc_cfg2 = Input::new(dp.PG6, Pull::None); let _uc_cfg3 = Input::new(dp.PG11, Pull::None); @@ -130,8 +130,8 @@ async fn main(spawner: Spawner) { // Setup IO and SPI for the SPE chip let spe_reset_n = Output::new(dp.PC7, Level::Low, Speed::Low); - let mut spe_cfg0 = Input::new(dp.PC8, Pull::None); - let mut spe_cfg1 = Input::new(dp.PC9, Pull::None); + let spe_cfg0 = Input::new(dp.PC8, Pull::None); + let spe_cfg1 = Input::new(dp.PC9, Pull::None); let _spe_ts_capt = Output::new(dp.PC6, Level::Low, Speed::Low); let spe_int = Input::new(dp.PB11, Pull::None); diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs index a989a5a4a..68dbb70ad 100644 --- a/examples/stm32l4/src/bin/spi_blocking_async.rs +++ b/examples/stm32l4/src/bin/spi_blocking_async.rs @@ -29,7 +29,7 @@ async fn main(_spawner: Spawner) { let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh); let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh); let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); - let mut ready = Input::new(p.PE1, Pull::Up); + let ready = Input::new(p.PE1, Pull::Up); cortex_m::asm::delay(100_000); reset.set_high(); diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs index 7922165df..946a759b1 100644 --- a/examples/stm32l4/src/bin/spi_dma.rs +++ b/examples/stm32l4/src/bin/spi_dma.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh); let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh); let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); - let mut ready = Input::new(p.PE1, Pull::Up); + let ready = Input::new(p.PE1, Pull::Up); cortex_m::asm::delay(100_000); reset.set_high(); diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index 3397e5ba6..eccd211e2 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -12,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut button = Input::new(p.PA0, Pull::Up); + let button = Input::new(p.PA0, Pull::Up); let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); let mut led2 = Output::new(p.PB9, Level::High, Speed::Low); diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs index a57d5d9e8..e0c309887 100644 --- a/tests/rp/src/bin/gpio.rs +++ b/tests/rp/src/bin/gpio.rs @@ -16,10 +16,10 @@ async fn main(_spawner: Spawner) { // Test initial output { - let mut b = Input::new(&mut b, Pull::None); + let b = Input::new(&mut b, Pull::None); { - let mut a = Output::new(&mut a, Level::Low); + let a = Output::new(&mut a, Level::Low); delay(); assert!(b.is_low()); assert!(!b.is_high()); @@ -64,7 +64,7 @@ async fn main(_spawner: Spawner) { // Test input no pull { - let mut b = Input::new(&mut b, Pull::None); + let b = Input::new(&mut b, Pull::None); // no pull, the status is undefined let mut a = Output::new(&mut a, Level::Low); @@ -77,7 +77,7 @@ async fn main(_spawner: Spawner) { // Test input pulldown { - let mut b = Input::new(&mut b, Pull::Down); + let b = Input::new(&mut b, Pull::Down); delay(); assert!(b.is_low()); @@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) { // Test input pullup { - let mut b = Input::new(&mut b, Pull::Up); + let b = Input::new(&mut b, Pull::Up); delay(); assert!(b.is_high()); diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs index 3fc0bb2a0..e71d9e610 100644 --- a/tests/rp/src/bin/pwm.rs +++ b/tests/rp/src/bin/pwm.rs @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) { // Test output from A { - let mut pin1 = Input::new(&mut p9, Pull::None); + let pin1 = Input::new(&mut p9, Pull::None); let _pwm = Pwm::new_output_a(&mut p.PWM_CH3, &mut p6, cfg.clone()); Timer::after_millis(1).await; assert_eq!(pin1.is_low(), invert_a); @@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) { // Test output from B { - let mut pin2 = Input::new(&mut p11, Pull::None); + let pin2 = Input::new(&mut p11, Pull::None); let _pwm = Pwm::new_output_b(&mut p.PWM_CH3, &mut p7, cfg.clone()); Timer::after_millis(1).await; assert_ne!(pin2.is_low(), invert_a); @@ -73,8 +73,8 @@ async fn main(_spawner: Spawner) { // Test output from A+B { - let mut pin1 = Input::new(&mut p9, Pull::None); - let mut pin2 = Input::new(&mut p11, Pull::None); + let pin1 = Input::new(&mut p9, Pull::None); + let pin2 = Input::new(&mut p11, Pull::None); let _pwm = Pwm::new_output_ab(&mut p.PWM_CH3, &mut p6, &mut p7, cfg.clone()); Timer::after_millis(1).await; assert_eq!(pin1.is_low(), invert_a); diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs index 9f1993024..c4e2fe161 100644 --- a/tests/stm32/src/bin/gpio.rs +++ b/tests/stm32/src/bin/gpio.rs @@ -20,10 +20,10 @@ async fn main(_spawner: Spawner) { // Test initial output { - let mut b = Input::new(&mut b, Pull::None); + let b = Input::new(&mut b, Pull::None); { - let mut a = Output::new(&mut a, Level::Low, Speed::Low); + let a = Output::new(&mut a, Level::Low, Speed::Low); delay(); assert!(b.is_low()); assert!(!b.is_high()); @@ -68,7 +68,7 @@ async fn main(_spawner: Spawner) { // Test input no pull { - let mut b = Input::new(&mut b, Pull::None); + let b = Input::new(&mut b, Pull::None); // no pull, the status is undefined let mut a = Output::new(&mut a, Level::Low, Speed::Low); @@ -81,7 +81,7 @@ async fn main(_spawner: Spawner) { // Test input pulldown { - let mut b = Input::new(&mut b, Pull::Down); + let b = Input::new(&mut b, Pull::Down); delay(); assert!(b.is_low()); @@ -95,7 +95,7 @@ async fn main(_spawner: Spawner) { // Test input pullup { - let mut b = Input::new(&mut b, Pull::Up); + let b = Input::new(&mut b, Pull::Up); delay(); assert!(b.is_high()); @@ -109,7 +109,7 @@ async fn main(_spawner: Spawner) { // Test output open drain { - let mut b = Input::new(&mut b, Pull::Down); + let b = Input::new(&mut b, Pull::Down); // no pull, the status is undefined let mut a = OutputOpenDrain::new(&mut a, Level::Low, Speed::Low, Pull::None); From b8672458947b4d48b5d5c950a60edd677d87e29e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 10 Jan 2024 09:23:53 +0100 Subject: [PATCH 202/760] simplify example --- examples/rp/src/bin/blinky_two_tasks.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs index 7e0b531e1..a03f3a592 100644 --- a/examples/rp/src/bin/blinky_two_tasks.rs +++ b/examples/rp/src/bin/blinky_two_tasks.rs @@ -30,13 +30,11 @@ async fn main(spawner: Spawner) { let dt = 100 * 1_000_000; let k = 1.003; - unwrap!(spawner.spawn(toggle(&LED, Duration::from_nanos(dt)))); - unwrap!(spawner.spawn(toggle_slightly_slower( - &LED, - Duration::from_nanos((dt as f64 * k) as u64) - ))); + unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos(dt)))); + unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos((dt as f64 * k) as u64)))); } +#[embassy_executor::task(pool_size = 2)] async fn toggle_led(led: &'static LedType, delay: Duration) { let mut ticker = Ticker::every(delay); loop { @@ -49,12 +47,3 @@ async fn toggle_led(led: &'static LedType, delay: Duration) { ticker.next().await; } } -#[embassy_executor::task] -async fn toggle(led: &'static LedType, delay: Duration) { - toggle_led(led, delay).await -} - -#[embassy_executor::task] -async fn toggle_slightly_slower(led: &'static LedType, delay: Duration) { - toggle_led(led, delay).await -} From ff5f5021fb4f469f72b3645760238ebe1c4d99af Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 10 Jan 2024 09:48:09 +0100 Subject: [PATCH 203/760] cleanup docs and add channel synchronization example --- docs/README.md | 4 + docs/modules/ROOT/nav.adoc | 6 +- docs/modules/ROOT/pages/delaying_a_task.adoc | 28 ------ .../modules/ROOT/pages/project_structure.adoc | 10 +-- .../ROOT/pages/sharing_peripherals.adoc | 86 +++++++++++++++---- docs/modules/ROOT/pages/time_keeping.adoc | 60 +++++++++++++ examples/rp/.cargo/config.toml | 2 +- examples/rp/src/bin/blinky_two_channels.rs | 47 ++++++++++ 8 files changed, 187 insertions(+), 56 deletions(-) create mode 100644 docs/README.md delete mode 100644 docs/modules/ROOT/pages/delaying_a_task.adoc create mode 100644 docs/modules/ROOT/pages/time_keeping.adoc create mode 100644 examples/rp/src/bin/blinky_two_channels.rs diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..0bf3a6c89 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,4 @@ +# embassy docs + +The documentation hosted at [https://embassy.dev/book](https://embassy.dev/book). Building the documentation requires +cloning the [embassy-book](https://github.com/embassy-rs/embassy-book) repository and following the instructions. diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index b692c44e1..44b0eddb9 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -3,11 +3,11 @@ ** xref:project_structure.adoc[Project Structure] ** xref:new_project.adoc[Starting a new Embassy project] ** xref:best_practices.adoc[Best Practices] -* xref:layer_by_layer.adoc[Bare metal to async] * xref:runtime.adoc[Executor] -* xref:delaying_a_task.adoc[Delaying a Task] -* xref:sharing_peripherals.adoc[Sharing peripherals between tasks] +* xref::time_keeping.adoc[Time-keeping] +* xref:sharing_peripherals.adoc[Sharing peripherals] * xref:hal.adoc[HAL] +** xref:layer_by_layer.adoc[Anatomy of an async HAL] ** xref:nrf.adoc[nRF] ** xref:stm32.adoc[STM32] * xref:bootloader.adoc[Bootloader] diff --git a/docs/modules/ROOT/pages/delaying_a_task.adoc b/docs/modules/ROOT/pages/delaying_a_task.adoc deleted file mode 100644 index 3171e3515..000000000 --- a/docs/modules/ROOT/pages/delaying_a_task.adoc +++ /dev/null @@ -1,28 +0,0 @@ -= Delaying a Task - -In an embedded program, delaying a task is one of the most common actions taken. In an event loop, delays will need to be inserted to ensure -that other tasks have a chance to run before the next iteration of the loop is called, if no other I/O is performed. Embassy provides an abstraction -to delay the current task for a specified interval of time. - -Timing is serviced by the `embassy::time::Timer` struct, which provides two timing methods. - -`Timer::at` creates a future that completes at the specified `Instant`, relative to the system boot time. -`Timer::after` creates a future that completes after the specified `Duration`, relative to when the future was created. - -An example of a delay is provided as follows: - -[,rust] ----- -use embassy::executor::{task, Executor}; -use embassy::time::{Duration, Timer}; - -#[task] -/// Task that ticks periodically -async fn tick_periodic() -> ! { - loop { - rprintln!("tick!"); - // async sleep primitive, suspends the task for 500ms. - Timer::after(Duration::from_millis(500)).await; - } -} ----- \ No newline at end of file diff --git a/docs/modules/ROOT/pages/project_structure.adoc b/docs/modules/ROOT/pages/project_structure.adoc index 3e6008ec4..61ffd05a6 100644 --- a/docs/modules/ROOT/pages/project_structure.adoc +++ b/docs/modules/ROOT/pages/project_structure.adoc @@ -18,7 +18,7 @@ my-project |- rust-toolchain.toml ---- -=== .cargo/config.toml +== .cargo/config.toml This directory/file describes what platform you're on, and configures link:https://github.com/probe-rs/probe-rs[probe-rs] to deploy to your device. @@ -36,17 +36,17 @@ target = "thumbv6m-none-eabi" # <-change for your platform DEFMT_LOG = "trace" # <- can change to info, warn, or error ---- -=== build.rs +== build.rs This is the build script for your project. It links defmt (what is defmt?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example]. -=== Cargo.toml +== Cargo.toml This is your manifest file, where you can configure all of the embassy components to use the features you need. TODO: someone should exhaustively describe every feature for every component! -=== memory.x +== memory.x This file outlines the flash/ram usage of your program. It is especially useful when using link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] on an nRF5x. @@ -63,7 +63,7 @@ MEMORY } ---- -=== rust-toolchain.toml +== rust-toolchain.toml This file configures the rust version and configuration to use. diff --git a/docs/modules/ROOT/pages/sharing_peripherals.adoc b/docs/modules/ROOT/pages/sharing_peripherals.adoc index 41f467942..fcba0e27b 100644 --- a/docs/modules/ROOT/pages/sharing_peripherals.adoc +++ b/docs/modules/ROOT/pages/sharing_peripherals.adoc @@ -1,6 +1,12 @@ = Sharing peripherals between tasks -Often times, more than one task needs access to the same resource (pin, communication interface, etc.). The following example shows how to use the on-board LED on a Raspberry Pi Pico board by two tasks simultaneously. +Often times, more than one task needs access to the same resource (pin, communication interface, etc.). Embassy provides many different synchronization primitives in the link:https://crates.io/crates/embassy-sync[embassy-sync] crate. + +The following examples shows different ways to use the on-board LED on a Raspberry Pi Pico board by two tasks simultaneously. + +== Sharing using a Mutex + +Using mutual exclusion is the simplest way to share a peripheral. [,rust] ---- @@ -29,13 +35,12 @@ async fn main(spawner: Spawner) { let dt = 100 * 1_000_000; let k = 1.003; - unwrap!(spawner.spawn(toggle(&LED, Duration::from_nanos(dt)))); - unwrap!(spawner.spawn(toggle_slightly_slower( - &LED, - Duration::from_nanos((dt as f64 * k) as u64) - ))); + unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos(dt)))); + unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos((dt as f64 * k) as u64)))); } +// A pool size of 2 means you can spawn two instances of this task. +#[embassy_executor::task(pool_size = 2)] async fn toggle_led(led: &'static LedType, delay: Duration) { let mut ticker = Ticker::every(delay); loop { @@ -48,31 +53,74 @@ async fn toggle_led(led: &'static LedType, delay: Duration) { ticker.next().await; } } -#[embassy_executor::task] -async fn toggle(led: &'static LedType, delay: Duration) { - toggle_led(led, delay).await -} - -#[embassy_executor::task] -async fn toggle_slightly_slower(led: &'static LedType, delay: Duration) { - toggle_led(led, delay).await -} ---- The structure facilitating access to the resource is the defined `LedType`. -== Why so complicated +=== Why so complicated Unwrapping the layers gives insight into why each one is needed. -=== `Mutex` +==== `Mutex` The mutex is there so if one task gets the resource first and begins modifying it, all other tasks wanting to write will have to wait (the `led.lock().await` will return immediately if no task has locked the mutex, and will block if it is accessed somewhere else). -=== `Option` +==== `Option` The `LED` variable needs to be defined outside the main task as references accepted by tasks need to be `'static`. However, if it is outside the main task, it cannot be initialised to point to any pin, as the pins themselves are not initialised. Thus, it is set to `None`. -=== `Output` +==== `Output` To indicate that the pin will be set to an Output. The `AnyPin` could have been `embassy_rp::peripherals::PIN_25`, however this option lets the `toggle_led` function be more generic. + +== Sharing using a Channel + +A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things. + +[,rust] +---- +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::channel::{Channel, Sender}; +use embassy_time::{Duration, Ticker}; +use gpio::{AnyPin, Level, Output}; +use {defmt_rtt as _, panic_probe as _}; + +enum LedState { + Toggle, +} +static CHANNEL: Channel = Channel::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); + + let dt = 100 * 1_000_000; + let k = 1.003; + + unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt)))); + unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos((dt as f64 * k) as u64)))); + + loop { + match CHANNEL.receive().await { + LedState::Toggle => led.toggle(), + } + } +} + +// A pool size of 2 means you can spawn two instances of this task. +#[embassy_executor::task(pool_size = 2)] +async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>, delay: Duration) { + let mut ticker = Ticker::every(delay); + loop { + control.send(LedState::Toggle).await; + ticker.next().await; + } +} +---- + +This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure +that the operation is ecompleted before continuing to do other work in your task. diff --git a/docs/modules/ROOT/pages/time_keeping.adoc b/docs/modules/ROOT/pages/time_keeping.adoc new file mode 100644 index 000000000..5068216ed --- /dev/null +++ b/docs/modules/ROOT/pages/time_keeping.adoc @@ -0,0 +1,60 @@ += Time-keeping + +In an embedded program, delaying a task is one of the most common actions taken. In an event loop, delays will need to be inserted to ensure +that other tasks have a chance to run before the next iteration of the loop is called, if no other I/O is performed. Embassy provides abstractions +to delay the current task for a specified interval of time. + +The interface for time-keeping in Embassy is handled by the link:https://crates.io/crates/embassy-time[embassy-time] crate. The types can be used with the internal +timer queue in link:https://crates.io/crates/embassy-executor[embassy-executor] or a custom timer queue implementation. + +== Timer + +The `embassy::time::Timer` type provides two timing methods. + +`Timer::at` creates a future that completes at the specified `Instant`, relative to the system boot time. +`Timer::after` creates a future that completes after the specified `Duration`, relative to when the future was created. + +An example of a delay is provided as follows: + +[,rust] +---- +use embassy::executor::{task, Executor}; +use embassy::time::{Duration, Timer}; + +#[task] +/// Task that ticks periodically +async fn tick_periodic() -> ! { + loop { + rprintln!("tick!"); + // async sleep primitive, suspends the task for 500ms. + Timer::after(Duration::from_millis(500)).await; + } +} +---- + +== Delay + +The `embassy::time::Delay` type provides an implementation of the link:https://docs.rs/embedded-hal/1.0.0/embedded_hal/delay/index.html[embedded-hal] and +link:https://docs.rs/embedded-hal-async/latest/embedded_hal_async/delay/index.html[embedded-hal-async] traits. This can be used for drivers +that expect a generic delay implementation to be provided. + +An example of how this can be used: + +[,rust] +---- +use embassy::executor::{task, Executor}; + +#[task] +/// Task that ticks periodically +async fn tick_periodic() -> ! { + loop { + rprintln!("tick!"); + // async sleep primitive, suspends the task for 500ms. + generic_delay(embassy::time::Delay).await + } +} + +async fn generic_delay(delay: D) { + delay.delay_ms(500).await; +} +---- diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml index 3d7d61740..04490c789 100644 --- a/examples/rp/.cargo/config.toml +++ b/examples/rp/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs run --chip RP2040" +runner = "probe-rs run --chip RP2040 --probe 1209:4853:0e0039001450563641333620" [build] target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ diff --git a/examples/rp/src/bin/blinky_two_channels.rs b/examples/rp/src/bin/blinky_two_channels.rs new file mode 100644 index 000000000..6179dc260 --- /dev/null +++ b/examples/rp/src/bin/blinky_two_channels.rs @@ -0,0 +1,47 @@ +#![no_std] +#![no_main] +/// This example demonstrates how to access a given pin from more than one embassy task +/// The on-board LED is toggled by two tasks with slightly different periods, leading to the +/// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar +/// to interference and the 'beats' you can hear if you play two frequencies close to one another +/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::channel::{Channel, Sender}; +use embassy_time::{Duration, Ticker}; +use gpio::{AnyPin, Level, Output}; +use {defmt_rtt as _, panic_probe as _}; + +enum LedState { + Toggle, +} +static CHANNEL: Channel = Channel::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); + + let dt = 100 * 1_000_000; + let k = 1.003; + + unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt)))); + unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos((dt as f64 * k) as u64)))); + + loop { + match CHANNEL.receive().await { + LedState::Toggle => led.toggle(), + } + } +} + +#[embassy_executor::task(pool_size = 2)] +async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>, delay: Duration) { + let mut ticker = Ticker::every(delay); + loop { + control.send(LedState::Toggle).await; + ticker.next().await; + } +} From de08da0bf19f6b0f02c7803351e4c94391e1da12 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 10 Jan 2024 09:54:35 +0100 Subject: [PATCH 204/760] rustfmt --- examples/rp/src/bin/blinky_two_channels.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/rp/src/bin/blinky_two_channels.rs b/examples/rp/src/bin/blinky_two_channels.rs index 6179dc260..b2eec2a21 100644 --- a/examples/rp/src/bin/blinky_two_channels.rs +++ b/examples/rp/src/bin/blinky_two_channels.rs @@ -15,7 +15,7 @@ use gpio::{AnyPin, Level, Output}; use {defmt_rtt as _, panic_probe as _}; enum LedState { - Toggle, + Toggle, } static CHANNEL: Channel = Channel::new(); @@ -28,7 +28,10 @@ async fn main(spawner: Spawner) { let k = 1.003; unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt)))); - unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos((dt as f64 * k) as u64)))); + unwrap!(spawner.spawn(toggle_led( + CHANNEL.sender(), + Duration::from_nanos((dt as f64 * k) as u64) + ))); loop { match CHANNEL.receive().await { From 50630192b80ab04b234de495d70710ec2f79b622 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 10 Jan 2024 10:02:26 +0100 Subject: [PATCH 205/760] fix: revert unintended change --- examples/rp/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml index 04490c789..3d7d61740 100644 --- a/examples/rp/.cargo/config.toml +++ b/examples/rp/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs run --chip RP2040 --probe 1209:4853:0e0039001450563641333620" +runner = "probe-rs run --chip RP2040" [build] target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ From 01b0af5a84409a13264d799a8156bb965ad7989f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 10 Jan 2024 14:06:15 +0100 Subject: [PATCH 206/760] net: add packet-trace feature. --- ci.sh | 2 +- embassy-net/Cargo.toml | 3 +++ embassy-net/src/device.rs | 13 +++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index dd028ddda..9c6f58f9f 100755 --- a/ci.sh +++ b/ci.sh @@ -35,7 +35,7 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ - --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,igmp,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \ diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 67f0bd028..864956616 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -28,6 +28,9 @@ std = [] ## Enable defmt defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03"] +## Trace all raw received and transmitted packets using defmt or log. +packet-trace = [] + #! Many of the following feature flags are re-exports of smoltcp feature flags. See #! the [smoltcp feature flag documentation](https://github.com/smoltcp-rs/smoltcp#feature-flags) #! for more details diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index 54a0c47e8..3b1d3c47c 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -76,7 +76,11 @@ where where F: FnOnce(&mut [u8]) -> R, { - self.0.consume(|buf| f(buf)) + self.0.consume(|buf| { + #[cfg(feature = "packet-trace")] + trace!("rx: {:?}", buf); + f(buf) + }) } } @@ -92,6 +96,11 @@ where where F: FnOnce(&mut [u8]) -> R, { - self.0.consume(len, |buf| f(buf)) + self.0.consume(len, |buf| { + let r = f(buf); + #[cfg(feature = "packet-trace")] + trace!("tx: {:?}", buf); + r + }) } } From 3bc6e414f7b1d4b4d138c7e90f7f9e85a7ca2885 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 10 Jan 2024 18:06:47 +0100 Subject: [PATCH 207/760] stm32: update metapac. --- embassy-stm32/Cargo.toml | 4 +-- embassy-stm32/src/opamp.rs | 59 ++++++++++++------------------------ embassy-stm32/src/sai/mod.rs | 9 +----- 3 files changed, 22 insertions(+), 50 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 2e5bf0e24..a798a8c5f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d5096244fa0b7992454a894a2aeaa369ae674222" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-656ecf6714fa34fdfb3b3e2f2cd034bffed3f303" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d5096244fa0b7992454a894a2aeaa369ae674222", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-656ecf6714fa34fdfb3b3e2f2cd034bffed3f303", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index df8a78bcc..ae8b3cacc 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -3,6 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; +use crate::pac::opamp::vals::*; use crate::Peripheral; /// Gain @@ -25,11 +26,11 @@ pub enum OpAmpSpeed { } #[cfg(opamp_g4)] -impl From for crate::pac::opamp::vals::OpampCsrOpahsm { +impl From for crate::pac::opamp::vals::Opahsm { fn from(v: OpAmpSpeed) -> Self { match v { - OpAmpSpeed::Normal => crate::pac::opamp::vals::OpampCsrOpahsm::NORMAL, - OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::OpampCsrOpahsm::HIGHSPEED, + OpAmpSpeed::Normal => crate::pac::opamp::vals::Opahsm::NORMAL, + OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::Opahsm::HIGHSPEED, } } } @@ -61,7 +62,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { into_ref!(opamp); #[cfg(opamp_g4)] - T::regs().opamp_csr().modify(|w| { + T::regs().csr().modify(|w| { w.set_opahsm(speed.into()); }); @@ -97,25 +98,15 @@ impl<'d, T: Instance> OpAmp<'d, T> { OpAmpGain::Mul16 => (0b10, 0b11), }; - #[cfg(opamp_f3)] - T::regs().opampcsr().modify(|w| { - w.set_vp_sel(in_pin.channel()); - w.set_vm_sel(vm_sel); - w.set_pga_gain(pga_gain); + T::regs().csr().modify(|w| { + w.set_vp_sel(VpSel::from_bits(in_pin.channel())); + w.set_vm_sel(VmSel::from_bits(vm_sel)); + w.set_pga_gain(PgaGain::from_bits(pga_gain)); + #[cfg(opamp_g4)] + w.set_opaintoen(Opaintoen::OUTPUTPIN); w.set_opampen(true); }); - #[cfg(opamp_g4)] - T::regs().opamp_csr().modify(|w| { - use crate::pac::opamp::vals::*; - - w.set_vp_sel(OpampCsrVpSel::from_bits(in_pin.channel())); - w.set_vm_sel(OpampCsrVmSel::from_bits(vm_sel)); - w.set_pga_gain(OpampCsrPgaGain::from_bits(pga_gain)); - w.set_opaintoen(OpampCsrOpaintoen::OUTPUTPIN); - w.set_opaen(true); - }); - OpAmpOutput { _inner: self } } @@ -144,13 +135,13 @@ impl<'d, T: Instance> OpAmp<'d, T> { OpAmpGain::Mul16 => (0b10, 0b11), }; - T::regs().opamp_csr().modify(|w| { + T::regs().csr().modify(|w| { use crate::pac::opamp::vals::*; - w.set_vp_sel(OpampCsrVpSel::from_bits(pin.channel())); - w.set_vm_sel(OpampCsrVmSel::from_bits(vm_sel)); - w.set_pga_gain(OpampCsrPgaGain::from_bits(pga_gain)); - w.set_opaintoen(OpampCsrOpaintoen::ADCCHANNEL); - w.set_opaen(true); + w.set_vp_sel(VpSel::from_bits(pin.channel())); + w.set_vm_sel(VmSel::from_bits(vm_sel)); + w.set_pga_gain(PgaGain::from_bits(pga_gain)); + w.set_opaintoen(Opaintoen::ADCCHANNEL); + w.set_opampen(true); }); OpAmpInternalOutput { _inner: self } @@ -159,29 +150,17 @@ impl<'d, T: Instance> OpAmp<'d, T> { impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { fn drop(&mut self) { - #[cfg(opamp_f3)] - T::regs().opampcsr().modify(|w| { + T::regs().csr().modify(|w| { w.set_opampen(false); }); - - #[cfg(opamp_g4)] - T::regs().opamp_csr().modify(|w| { - w.set_opaen(false); - }); } } impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { fn drop(&mut self) { - #[cfg(opamp_f3)] - T::regs().opampcsr().modify(|w| { + T::regs().csr().modify(|w| { w.set_opampen(false); }); - - #[cfg(opamp_g4)] - T::regs().opamp_csr().modify(|w| { - w.set_opaen(false); - }); } } diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index ef8802184..5e647612c 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -846,14 +846,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { pub fn flush(&mut self) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); - #[cfg(any(sai_v1, sai_v2))] - { - ch.cr2().modify(|w| w.set_fflush(vals::Fflush::FLUSH)); - } - #[cfg(any(sai_v3, sai_v4))] - { - ch.cr2().modify(|w| w.set_fflush(true)); - } + ch.cr2().modify(|w| w.set_fflush(true)); ch.cr1().modify(|w| w.set_saien(true)); } From fe0b21e21e8a1144a37ef07892927062682206a1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 10 Jan 2024 18:25:45 +0100 Subject: [PATCH 208/760] Remove nightly autodetects. --- embassy-embedded-hal/build.rs | 18 ------------------ embassy-embedded-hal/src/lib.rs | 2 -- embassy-net/build.rs | 18 ------------------ embassy-sync/build.rs | 13 ------------- embassy-sync/src/lib.rs | 2 -- embassy-time/build.rs | 19 +------------------ embassy-time/src/lib.rs | 2 -- 7 files changed, 1 insertion(+), 73 deletions(-) delete mode 100644 embassy-embedded-hal/build.rs delete mode 100644 embassy-net/build.rs diff --git a/embassy-embedded-hal/build.rs b/embassy-embedded-hal/build.rs deleted file mode 100644 index 78bd27ec7..000000000 --- a/embassy-embedded-hal/build.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::env; -use std::ffi::OsString; -use std::process::Command; - -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to run `rustc --version`"); - - if String::from_utf8_lossy(&output.stdout).contains("nightly") { - println!("cargo:rustc-cfg=nightly"); - } -} diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs index b40f892f4..ee974324b 100644 --- a/embassy-embedded-hal/src/lib.rs +++ b/embassy-embedded-hal/src/lib.rs @@ -1,6 +1,4 @@ #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(nightly, feature(async_fn_in_trait, impl_trait_projections))] -#![cfg_attr(nightly, allow(stable_features, unknown_lints))] #![allow(async_fn_in_trait)] #![warn(missing_docs)] diff --git a/embassy-net/build.rs b/embassy-net/build.rs deleted file mode 100644 index 78bd27ec7..000000000 --- a/embassy-net/build.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::env; -use std::ffi::OsString; -use std::process::Command; - -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to run `rustc --version`"); - - if String::from_utf8_lossy(&output.stdout).contains("nightly") { - println!("cargo:rustc-cfg=nightly"); - } -} diff --git a/embassy-sync/build.rs b/embassy-sync/build.rs index 0a796b881..afd76dad1 100644 --- a/embassy-sync/build.rs +++ b/embassy-sync/build.rs @@ -1,21 +1,8 @@ use std::env; -use std::ffi::OsString; -use std::process::Command; fn main() { println!("cargo:rerun-if-changed=build.rs"); - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to run `rustc --version`"); - - if String::from_utf8_lossy(&output.stdout).contains("nightly") { - println!("cargo:rustc-cfg=nightly"); - } - let target = env::var("TARGET").unwrap(); if target.starts_with("thumbv6m-") { diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index b0ccfde57..d88c76db5 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -1,6 +1,4 @@ #![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] -#![cfg_attr(nightly, feature(async_fn_in_trait, impl_trait_projections))] -#![cfg_attr(nightly, allow(stable_features, unknown_lints))] #![allow(async_fn_in_trait)] #![allow(clippy::new_without_default)] #![doc = include_str!("../README.md")] diff --git a/embassy-time/build.rs b/embassy-time/build.rs index 78bd27ec7..f328e4d9d 100644 --- a/embassy-time/build.rs +++ b/embassy-time/build.rs @@ -1,18 +1 @@ -use std::env; -use std::ffi::OsString; -use std::process::Command; - -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to run `rustc --version`"); - - if String::from_utf8_lossy(&output.stdout).contains("nightly") { - println!("cargo:rustc-cfg=nightly"); - } -} +fn main() {} diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index a59ee68d2..7e2546f68 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -1,6 +1,4 @@ #![cfg_attr(not(any(feature = "std", feature = "wasm", test)), no_std)] -#![cfg_attr(nightly, feature(async_fn_in_trait, impl_trait_projections))] -#![cfg_attr(nightly, allow(stable_features, unknown_lints))] #![allow(async_fn_in_trait)] #![doc = include_str!("../README.md")] #![allow(clippy::new_without_default)] From 68166eda6820ece3219f221b76fe26bd6f71e3c4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 10 Jan 2024 18:26:59 +0100 Subject: [PATCH 209/760] update MSRV in readme, nightly is no longer needed. --- README.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 714104331..d2a24dfcc 100644 --- a/README.md +++ b/README.md @@ -136,14 +136,8 @@ please refer to the `.vscode/settings.json` file's `rust-analyzer.linkedProjects ## Minimum supported Rust version (MSRV) -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -Several features require nightly: - -- The `#[embassy_executor::main]` and `#[embassy_executor::task]` attribute macros. -- Async traits - -These are enabled by activating the `nightly` Cargo feature. If you do so, Embassy is guaranteed to compile on the exact nightly version specified in `rust-toolchain.toml`. It might compile with older or newer nightly versions, but that may change in any new patch release. +Embassy is guaranteed to compile on stable Rust 1.75 and up. It *might* +compile with older versions but that may change in any new patch release. ## Why the name? From db776c9623428b539cf49bcca13361e11bc1129b Mon Sep 17 00:00:00 2001 From: Ralf Date: Fri, 20 Oct 2023 19:31:55 +0200 Subject: [PATCH 210/760] stm32/simple_pwm: add set_output_compare_mode --- embassy-stm32/src/timer/simple_pwm.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 80f10424c..83a3e9291 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -151,6 +151,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { self.inner.set_output_polarity(channel, polarity); } + /// Set the output compare mode for a given channel. + pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { + self.inner.set_output_compare_mode(channel, mode); + } + /// Generate a sequence of PWM waveform /// /// Note: From 15f94fb0fc70463b9a50c997083fee3f5758b17a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 16:38:44 +0100 Subject: [PATCH 211/760] time: split driver into a separate embassy-time-driver crate. --- ci.sh | 40 +- embassy-nrf/Cargo.toml | 3 +- embassy-nrf/src/time_driver.rs | 4 +- embassy-rp/Cargo.toml | 5 +- embassy-rp/src/lib.rs | 4 +- embassy-rp/src/{timer.rs => time_driver.rs} | 4 +- embassy-stm32/Cargo.toml | 5 +- embassy-stm32/src/time_driver.rs | 5 +- embassy-time-driver/CHANGELOG.md | 51 +++ embassy-time-driver/Cargo.toml | 391 ++++++++++++++++++ embassy-time-driver/README.md | 20 + .../build.rs | 0 .../gen_tick.py | 32 +- .../src/lib.rs | 28 +- .../src/tick.rs | 0 embassy-time/Cargo.toml | 326 ++++++++------- embassy-time/README.md | 4 +- embassy-time/src/driver_mock.rs | 2 +- embassy-time/src/driver_std.rs | 2 +- embassy-time/src/driver_wasm.rs | 2 +- embassy-time/src/lib.rs | 10 +- 21 files changed, 711 insertions(+), 227 deletions(-) rename embassy-rp/src/{timer.rs => time_driver.rs} (97%) create mode 100644 embassy-time-driver/CHANGELOG.md create mode 100644 embassy-time-driver/Cargo.toml create mode 100644 embassy-time-driver/README.md rename {embassy-time => embassy-time-driver}/build.rs (100%) rename {embassy-time => embassy-time-driver}/gen_tick.py (71%) rename embassy-time/src/driver.rs => embassy-time-driver/src/lib.rs (89%) rename {embassy-time => embassy-time-driver}/src/tick.rs (100%) diff --git a/ci.sh b/ci.sh index 9c6f58f9f..ac0457679 100755 --- a/ci.sh +++ b/ci.sh @@ -47,24 +47,30 @@ cargo batch \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time-driver-rtc1,reset-pin-as-gpio \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time-driver-rtc1,nfc-pins-as-gpio \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time,time-driver-rtc1,reset-pin-as-gpio \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time,time-driver-rtc1,nfc-pins-as-gpio \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,log,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,defmt,gpiote,time-driver-rtc1 \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features defmt \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features log \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features intrinsics \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features qspi-as-gpio \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 7d7346d92..f62059eb1 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -96,7 +96,7 @@ _nrf5340 = ["_gpio-p1", "_dppi"] _nrf9160 = ["nrf9160-pac", "_dppi"] _nrf52 = ["_ppi"] -_time-driver = ["dep:embassy-time", "embassy-time?/tick-hz-32_768"] +_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"] # trustzone state. _s = [] @@ -110,6 +110,7 @@ _gpio-p1 = [] _nrf52832_anomaly_109 = [] [dependencies] +embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-time = { version = "0.2", path = "../embassy-time", optional = true } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index f1ab4f8fd..042f7c5f7 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -5,7 +5,7 @@ use core::{mem, ptr}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; -use embassy_time::driver::{AlarmHandle, Driver}; +use embassy_time_driver::{AlarmHandle, Driver}; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; @@ -119,7 +119,7 @@ struct RtcDriver { } const ALARM_STATE_NEW: AlarmState = AlarmState::new(); -embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { +embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarm_count: AtomicU8::new(0), alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 8d7a11749..b324eab82 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -30,7 +30,7 @@ critical-section-impl = ["critical-section/restore-state-u8"] unstable-pac = [] ## Enable the timer for use with `embassy-time` with a 1MHz tick rate -time-driver = [] +time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000"] ## Enable ROM function cache rom-func-cache = [] @@ -67,7 +67,8 @@ boot2-w25x10cl = [] [dependencies] embassy-sync = { version = "0.5.0", path = "../embassy-sync" } -embassy-time = { version = "0.2", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } +embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } +embassy-time = { version = "0.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 0a3714777..46973fdc8 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -30,7 +30,7 @@ pub mod rom_data; pub mod rtc; pub mod spi; #[cfg(feature = "time-driver")] -pub mod timer; +pub mod time_driver; pub mod uart; pub mod usb; pub mod watchdog; @@ -344,7 +344,7 @@ pub fn init(config: config::Config) -> Peripherals { unsafe { clocks::init(config.clocks); #[cfg(feature = "time-driver")] - timer::init(); + time_driver::init(); dma::init(); gpio::init(); } diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/time_driver.rs similarity index 97% rename from embassy-rp/src/timer.rs rename to embassy-rp/src/time_driver.rs index 69c0c85b1..bab1044cb 100644 --- a/embassy-rp/src/timer.rs +++ b/embassy-rp/src/time_driver.rs @@ -5,7 +5,7 @@ use atomic_polyfill::{AtomicU8, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; -use embassy_time::driver::{AlarmHandle, Driver}; +use embassy_time_driver::{AlarmHandle, Driver}; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; @@ -27,7 +27,7 @@ struct TimerDriver { next_alarm: AtomicU8, } -embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ +embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [DUMMY_ALARM; ALARM_COUNT]), next_alarm: AtomicU8::new(0), }); diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index a798a8c5f..60fc86135 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -34,6 +34,7 @@ flavors = [ [dependencies] embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-time = { version = "0.2", path = "../embassy-time", optional = true } +embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } @@ -88,7 +89,7 @@ rt = ["stm32-metapac/rt"] defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] exti = [] -low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m" ] +low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] low-power-debug-with-sleep = [] ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) @@ -107,7 +108,7 @@ time = ["dep:embassy-time"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. -_time-driver = ["time"] +_time-driver = ["dep:embassy-time-driver", "time"] ## Use any time driver time-driver-any = ["_time-driver"] diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 9981800b2..0dbadce0c 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -6,8 +6,7 @@ use core::{mem, ptr}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; -use embassy_time::driver::{AlarmHandle, Driver}; -use embassy_time::TICK_HZ; +use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; use stm32_metapac::timer::regs; use crate::interrupt::typelevel::Interrupt; @@ -173,7 +172,7 @@ pub(crate) struct RtcDriver { const ALARM_STATE_NEW: AlarmState = AlarmState::new(); -embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { +embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarm_count: AtomicU8::new(0), alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md new file mode 100644 index 000000000..d8c0c7d08 --- /dev/null +++ b/embassy-time-driver/CHANGELOG.md @@ -0,0 +1,51 @@ +# Changelog + +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). + +## 0.2.0 - 2023-12-04 + +- Added tick rates in multiples of 10 kHz +- Remove nightly and unstable-traits features in preparation for 1.75. +- Update heapless to 0.8. + +## 0.1.5 - 2023-10-16 + +- Added `links` key to Cargo.toml, to prevent multiple copies of this crate in the same binary. + Needed because different copies might get different tick rates, causing + wrong delays if the time driver is using one copy and user code is using another. + This is especially common when mixing crates from crates.io and git. + +## 0.1.4 - 2023-10-12 + +- Added more tick rates + +## 0.1.3 - 2023-08-28 + +- Update `embedded-hal-async` to `1.0.0-rc.2` +- Update `embedded-hal v1` to `1.0.0-rc.2` + +## 0.1.2 - 2023-07-05 + +- Update `embedded-hal-async` to `0.2.0-alpha.2`. +- Update `embedded-hal v1` to `1.0.0-alpha.11`. (Note: v0.2 support is kept unchanged). + +## 0.1.1 - 2023-04-13 + +- Update `embedded-hal-async` to `0.2.0-alpha.1` (uses `async fn` in traits). +- Update `embedded-hal v1` to `1.0.0-alpha.10`. (Note: v0.2 support is kept unchanged). +- Remove dep on `embassy-sync`. +- Fix reentrancy issues in the `std` time driver (#1177) +- Add `Duration::from_hz()`. +- impl `From` conversions to/from `core::time::Duration`. +- Add `#[must_use]` to all futures. +- Add inherent `async fn tick()` to `Ticker`, so you can use it directly without the `Stream` trait. +- Add more tick rates. +- impl `Default` for `Signal` +- Remove unnecessary uses of `atomic-polyfill` + +## 0.1.0 - 2022-08-26 + +- First release diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml new file mode 100644 index 000000000..2ed250d4d --- /dev/null +++ b/embassy-time-driver/Cargo.toml @@ -0,0 +1,391 @@ +[package] +name = "embassy-time-driver" +version = "0.1.0" +edition = "2021" +description = "Driver trait for embassy-time" +repository = "https://github.com/embassy-rs/embassy" +readme = "README.md" +license = "MIT OR Apache-2.0" +categories = [ + "embedded", + "no-std", + "concurrency", + "asynchronous", +] + +# Prevent multiple copies of this crate in the same binary. +# Needed because different copies might get different tick rates, causing +# wrong delays if the time driver is using one copy and user code is using another. +# This is especially common when mixing crates from crates.io and git. +links = "embassy-time" + +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-driver-v$VERSION/embassy-time-driver/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-driver/src/" +target = "x86_64-unknown-linux-gnu" + +[features] +#! ### Tick Rate +#! +#! At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. +#! +#! If the time driver in use supports using arbitrary tick rates, you can enable one `tick-*` +#! feature from your binary crate to set the tick rate. The driver will use configured tick rate. +#! If the time driver supports a fixed tick rate, it will enable one feature itself, so you should +#! not enable one. Check the time driver documentation for details. +#! +#! When using embassy-time from libraries, you should *not* enable any `tick-*` feature, to allow the +#! end user or the driver to pick. +#!

+#! Available tick rates: +#! +#! + +# BEGIN TICKS +# Generated by gen_tick.py. DO NOT EDIT. +## 1Hz Tick Rate +tick-hz-1 = [] +## 2Hz Tick Rate +tick-hz-2 = [] +## 4Hz Tick Rate +tick-hz-4 = [] +## 8Hz Tick Rate +tick-hz-8 = [] +## 10Hz Tick Rate +tick-hz-10 = [] +## 16Hz Tick Rate +tick-hz-16 = [] +## 32Hz Tick Rate +tick-hz-32 = [] +## 64Hz Tick Rate +tick-hz-64 = [] +## 100Hz Tick Rate +tick-hz-100 = [] +## 128Hz Tick Rate +tick-hz-128 = [] +## 256Hz Tick Rate +tick-hz-256 = [] +## 512Hz Tick Rate +tick-hz-512 = [] +## 1.0kHz Tick Rate +tick-hz-1_000 = [] +## 1.024kHz Tick Rate +tick-hz-1_024 = [] +## 2.0kHz Tick Rate +tick-hz-2_000 = [] +## 2.048kHz Tick Rate +tick-hz-2_048 = [] +## 4.0kHz Tick Rate +tick-hz-4_000 = [] +## 4.096kHz Tick Rate +tick-hz-4_096 = [] +## 8.0kHz Tick Rate +tick-hz-8_000 = [] +## 8.192kHz Tick Rate +tick-hz-8_192 = [] +## 10.0kHz Tick Rate +tick-hz-10_000 = [] +## 16.0kHz Tick Rate +tick-hz-16_000 = [] +## 16.384kHz Tick Rate +tick-hz-16_384 = [] +## 20.0kHz Tick Rate +tick-hz-20_000 = [] +## 32.0kHz Tick Rate +tick-hz-32_000 = [] +## 32.768kHz Tick Rate +tick-hz-32_768 = [] +## 40.0kHz Tick Rate +tick-hz-40_000 = [] +## 64.0kHz Tick Rate +tick-hz-64_000 = [] +## 65.536kHz Tick Rate +tick-hz-65_536 = [] +## 80.0kHz Tick Rate +tick-hz-80_000 = [] +## 100.0kHz Tick Rate +tick-hz-100_000 = [] +## 128.0kHz Tick Rate +tick-hz-128_000 = [] +## 131.072kHz Tick Rate +tick-hz-131_072 = [] +## 160.0kHz Tick Rate +tick-hz-160_000 = [] +## 256.0kHz Tick Rate +tick-hz-256_000 = [] +## 262.144kHz Tick Rate +tick-hz-262_144 = [] +## 320.0kHz Tick Rate +tick-hz-320_000 = [] +## 512.0kHz Tick Rate +tick-hz-512_000 = [] +## 524.288kHz Tick Rate +tick-hz-524_288 = [] +## 640.0kHz Tick Rate +tick-hz-640_000 = [] +## 1.0MHz Tick Rate +tick-hz-1_000_000 = [] +## 1.024MHz Tick Rate +tick-hz-1_024_000 = [] +## 1.048576MHz Tick Rate +tick-hz-1_048_576 = [] +## 1.28MHz Tick Rate +tick-hz-1_280_000 = [] +## 2.0MHz Tick Rate +tick-hz-2_000_000 = [] +## 2.048MHz Tick Rate +tick-hz-2_048_000 = [] +## 2.097152MHz Tick Rate +tick-hz-2_097_152 = [] +## 2.56MHz Tick Rate +tick-hz-2_560_000 = [] +## 3.0MHz Tick Rate +tick-hz-3_000_000 = [] +## 4.0MHz Tick Rate +tick-hz-4_000_000 = [] +## 4.096MHz Tick Rate +tick-hz-4_096_000 = [] +## 4.194304MHz Tick Rate +tick-hz-4_194_304 = [] +## 5.12MHz Tick Rate +tick-hz-5_120_000 = [] +## 6.0MHz Tick Rate +tick-hz-6_000_000 = [] +## 8.0MHz Tick Rate +tick-hz-8_000_000 = [] +## 8.192MHz Tick Rate +tick-hz-8_192_000 = [] +## 8.388608MHz Tick Rate +tick-hz-8_388_608 = [] +## 9.0MHz Tick Rate +tick-hz-9_000_000 = [] +## 10.0MHz Tick Rate +tick-hz-10_000_000 = [] +## 10.24MHz Tick Rate +tick-hz-10_240_000 = [] +## 12.0MHz Tick Rate +tick-hz-12_000_000 = [] +## 16.0MHz Tick Rate +tick-hz-16_000_000 = [] +## 16.384MHz Tick Rate +tick-hz-16_384_000 = [] +## 16.777216MHz Tick Rate +tick-hz-16_777_216 = [] +## 18.0MHz Tick Rate +tick-hz-18_000_000 = [] +## 20.0MHz Tick Rate +tick-hz-20_000_000 = [] +## 20.48MHz Tick Rate +tick-hz-20_480_000 = [] +## 24.0MHz Tick Rate +tick-hz-24_000_000 = [] +## 30.0MHz Tick Rate +tick-hz-30_000_000 = [] +## 32.0MHz Tick Rate +tick-hz-32_000_000 = [] +## 32.768MHz Tick Rate +tick-hz-32_768_000 = [] +## 36.0MHz Tick Rate +tick-hz-36_000_000 = [] +## 40.0MHz Tick Rate +tick-hz-40_000_000 = [] +## 40.96MHz Tick Rate +tick-hz-40_960_000 = [] +## 48.0MHz Tick Rate +tick-hz-48_000_000 = [] +## 50.0MHz Tick Rate +tick-hz-50_000_000 = [] +## 60.0MHz Tick Rate +tick-hz-60_000_000 = [] +## 64.0MHz Tick Rate +tick-hz-64_000_000 = [] +## 65.536MHz Tick Rate +tick-hz-65_536_000 = [] +## 70.0MHz Tick Rate +tick-hz-70_000_000 = [] +## 72.0MHz Tick Rate +tick-hz-72_000_000 = [] +## 80.0MHz Tick Rate +tick-hz-80_000_000 = [] +## 81.92MHz Tick Rate +tick-hz-81_920_000 = [] +## 90.0MHz Tick Rate +tick-hz-90_000_000 = [] +## 96.0MHz Tick Rate +tick-hz-96_000_000 = [] +## 100.0MHz Tick Rate +tick-hz-100_000_000 = [] +## 110.0MHz Tick Rate +tick-hz-110_000_000 = [] +## 120.0MHz Tick Rate +tick-hz-120_000_000 = [] +## 128.0MHz Tick Rate +tick-hz-128_000_000 = [] +## 130.0MHz Tick Rate +tick-hz-130_000_000 = [] +## 131.072MHz Tick Rate +tick-hz-131_072_000 = [] +## 140.0MHz Tick Rate +tick-hz-140_000_000 = [] +## 144.0MHz Tick Rate +tick-hz-144_000_000 = [] +## 150.0MHz Tick Rate +tick-hz-150_000_000 = [] +## 160.0MHz Tick Rate +tick-hz-160_000_000 = [] +## 163.84MHz Tick Rate +tick-hz-163_840_000 = [] +## 170.0MHz Tick Rate +tick-hz-170_000_000 = [] +## 180.0MHz Tick Rate +tick-hz-180_000_000 = [] +## 190.0MHz Tick Rate +tick-hz-190_000_000 = [] +## 192.0MHz Tick Rate +tick-hz-192_000_000 = [] +## 200.0MHz Tick Rate +tick-hz-200_000_000 = [] +## 210.0MHz Tick Rate +tick-hz-210_000_000 = [] +## 220.0MHz Tick Rate +tick-hz-220_000_000 = [] +## 230.0MHz Tick Rate +tick-hz-230_000_000 = [] +## 240.0MHz Tick Rate +tick-hz-240_000_000 = [] +## 250.0MHz Tick Rate +tick-hz-250_000_000 = [] +## 256.0MHz Tick Rate +tick-hz-256_000_000 = [] +## 260.0MHz Tick Rate +tick-hz-260_000_000 = [] +## 262.144MHz Tick Rate +tick-hz-262_144_000 = [] +## 270.0MHz Tick Rate +tick-hz-270_000_000 = [] +## 280.0MHz Tick Rate +tick-hz-280_000_000 = [] +## 288.0MHz Tick Rate +tick-hz-288_000_000 = [] +## 290.0MHz Tick Rate +tick-hz-290_000_000 = [] +## 300.0MHz Tick Rate +tick-hz-300_000_000 = [] +## 320.0MHz Tick Rate +tick-hz-320_000_000 = [] +## 327.68MHz Tick Rate +tick-hz-327_680_000 = [] +## 340.0MHz Tick Rate +tick-hz-340_000_000 = [] +## 360.0MHz Tick Rate +tick-hz-360_000_000 = [] +## 380.0MHz Tick Rate +tick-hz-380_000_000 = [] +## 384.0MHz Tick Rate +tick-hz-384_000_000 = [] +## 400.0MHz Tick Rate +tick-hz-400_000_000 = [] +## 420.0MHz Tick Rate +tick-hz-420_000_000 = [] +## 440.0MHz Tick Rate +tick-hz-440_000_000 = [] +## 460.0MHz Tick Rate +tick-hz-460_000_000 = [] +## 480.0MHz Tick Rate +tick-hz-480_000_000 = [] +## 500.0MHz Tick Rate +tick-hz-500_000_000 = [] +## 512.0MHz Tick Rate +tick-hz-512_000_000 = [] +## 520.0MHz Tick Rate +tick-hz-520_000_000 = [] +## 524.288MHz Tick Rate +tick-hz-524_288_000 = [] +## 540.0MHz Tick Rate +tick-hz-540_000_000 = [] +## 560.0MHz Tick Rate +tick-hz-560_000_000 = [] +## 576.0MHz Tick Rate +tick-hz-576_000_000 = [] +## 580.0MHz Tick Rate +tick-hz-580_000_000 = [] +## 600.0MHz Tick Rate +tick-hz-600_000_000 = [] +## 620.0MHz Tick Rate +tick-hz-620_000_000 = [] +## 640.0MHz Tick Rate +tick-hz-640_000_000 = [] +## 655.36MHz Tick Rate +tick-hz-655_360_000 = [] +## 660.0MHz Tick Rate +tick-hz-660_000_000 = [] +## 680.0MHz Tick Rate +tick-hz-680_000_000 = [] +## 700.0MHz Tick Rate +tick-hz-700_000_000 = [] +## 720.0MHz Tick Rate +tick-hz-720_000_000 = [] +## 740.0MHz Tick Rate +tick-hz-740_000_000 = [] +## 760.0MHz Tick Rate +tick-hz-760_000_000 = [] +## 768.0MHz Tick Rate +tick-hz-768_000_000 = [] +## 780.0MHz Tick Rate +tick-hz-780_000_000 = [] +## 800.0MHz Tick Rate +tick-hz-800_000_000 = [] +## 820.0MHz Tick Rate +tick-hz-820_000_000 = [] +## 840.0MHz Tick Rate +tick-hz-840_000_000 = [] +## 860.0MHz Tick Rate +tick-hz-860_000_000 = [] +## 880.0MHz Tick Rate +tick-hz-880_000_000 = [] +## 900.0MHz Tick Rate +tick-hz-900_000_000 = [] +## 920.0MHz Tick Rate +tick-hz-920_000_000 = [] +## 940.0MHz Tick Rate +tick-hz-940_000_000 = [] +## 960.0MHz Tick Rate +tick-hz-960_000_000 = [] +## 980.0MHz Tick Rate +tick-hz-980_000_000 = [] +## 1.0GHz Tick Rate +tick-hz-1_000_000_000 = [] +## 1.31072GHz Tick Rate +tick-hz-1_310_720_000 = [] +## 2.62144GHz Tick Rate +tick-hz-2_621_440_000 = [] +## 5.24288GHz Tick Rate +tick-hz-5_242_880_000 = [] +# END TICKS + +#!
+ +[dependencies] +defmt = { version = "0.3", optional = true } +log = { version = "0.4.14", optional = true } + +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } + +futures-util = { version = "0.3.17", default-features = false } +critical-section = "1.1" +cfg-if = "1.0.0" +heapless = "0.8" + +document-features = "0.2.7" + +# WASM dependencies +wasm-bindgen = { version = "0.2.81", optional = true } +js-sys = { version = "0.3", optional = true } +wasm-timer = { version = "0.2.5", optional = true } + +[dev-dependencies] +serial_test = "0.9" +critical-section = { version = "1.1", features = ["std"] } +embassy-executor = { version = "0.4.0", path = "../embassy-executor" } diff --git a/embassy-time-driver/README.md b/embassy-time-driver/README.md new file mode 100644 index 000000000..74a5b7876 --- /dev/null +++ b/embassy-time-driver/README.md @@ -0,0 +1,20 @@ +# embassy-time-driver + + +This crate contains the driver trait necessary for adding [`embassy-time`](https://crates.io/crates/embassy-time) support +for a new hardware platform. + +If you want to *use* `embassy-time` with already made drivers, you should depend on the main `embassy-time` crate, not on this crate. + +If you are writing a driver, you should depend only on this crate, not on the main `embassy-time` crate. +This will allow your driver to continue working for newer `embassy-time` major versions, without needing an update, +if the driver trait has not had breaking changes. + +## How it works + +`embassy-time` module is backed by a global "time driver" specified at build time. +Only one driver can be active in a program. + +All methods and structs transparently call into the active driver. This makes it +possible for libraries to use `embassy-time` in a driver-agnostic way without +requiring generic parameters. diff --git a/embassy-time/build.rs b/embassy-time-driver/build.rs similarity index 100% rename from embassy-time/build.rs rename to embassy-time-driver/build.rs diff --git a/embassy-time/gen_tick.py b/embassy-time-driver/gen_tick.py similarity index 71% rename from embassy-time/gen_tick.py rename to embassy-time-driver/gen_tick.py index 8961fb7e6..af194c31f 100644 --- a/embassy-time/gen_tick.py +++ b/embassy-time-driver/gen_tick.py @@ -28,18 +28,14 @@ ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))]) # ========= Update Cargo.toml -things = [(hz, f'tick-hz-{hz:_}') for hz in ticks] - SEPARATOR_START = '# BEGIN TICKS\n' SEPARATOR_END = '# END TICKS\n' HELP = '# Generated by gen_tick.py. DO NOT EDIT.\n' -with open('Cargo.toml', 'r') as f: - data = f.read() -before, data = data.split(SEPARATOR_START, maxsplit=1) -_, after = data.split(SEPARATOR_END, maxsplit=1) -data = before + SEPARATOR_START + HELP -for freq, feature in things: +feats_time = '' +feats_driver = '' +for freq in ticks: + feature = f'tick-hz-{freq:_}' if freq >= 1_000_000_000: freq_human = f"{freq / 1_000_000_000}GHz" elif freq >= 1_000_000: @@ -49,12 +45,24 @@ for freq, feature in things: else: freq_human = f"{freq}Hz" - data += f"## {freq_human} Tick Rate\n" - data += f"{feature} = []\n" -data += SEPARATOR_END + after + feats_time += f"## {freq_human} Tick Rate\n" + feats_time += f"{feature} = [\"embassy-time-driver/{feature}\"]\n" + feats_driver += f"## {freq_human} Tick Rate\n" + feats_driver += f"{feature} = []\n" +with open('Cargo.toml', 'r') as f: + data = f.read() +before, data = data.split(SEPARATOR_START, maxsplit=1) +_, after = data.split(SEPARATOR_END, maxsplit=1) with open('Cargo.toml', 'w') as f: - f.write(data) + f.write(before + SEPARATOR_START + HELP + feats_driver + SEPARATOR_END + after) + +with open('../embassy-time/Cargo.toml', 'r') as f: + data = f.read() +before, data = data.split(SEPARATOR_START, maxsplit=1) +_, after = data.split(SEPARATOR_END, maxsplit=1) +with open('../embassy-time/Cargo.toml', 'w') as f: + f.write(before + SEPARATOR_START + HELP + feats_time + SEPARATOR_END + after) # ========= Update src/tick.rs diff --git a/embassy-time/src/driver.rs b/embassy-time-driver/src/lib.rs similarity index 89% rename from embassy-time/src/driver.rs rename to embassy-time-driver/src/lib.rs index f966386b7..39a772aa5 100644 --- a/embassy-time/src/driver.rs +++ b/embassy-time-driver/src/lib.rs @@ -1,3 +1,7 @@ +#![no_std] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] + //! Time driver interface //! //! This module defines the interface a driver needs to implement to power the `embassy_time` module. @@ -62,6 +66,16 @@ //! embassy_time::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); //! ``` +//! ## Feature flags +#![doc = document_features::document_features!(feature_label = r#"{feature}"#)] + +mod tick; + +/// Ticks per second of the global timebase. +/// +/// This value is specified by the [`tick-*` Cargo features](crate#tick-rate) +pub const TICK_HZ: u64 = tick::TICK_HZ; + /// Alarm handle, assigned by the driver. #[derive(Clone, Copy)] pub struct AlarmHandle { @@ -165,22 +179,22 @@ macro_rules! time_driver_impl { #[no_mangle] fn _embassy_time_now() -> u64 { - <$t as $crate::driver::Driver>::now(&$name) + <$t as $crate::Driver>::now(&$name) } #[no_mangle] - unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::driver::AlarmHandle> { - <$t as $crate::driver::Driver>::allocate_alarm(&$name) + unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::AlarmHandle> { + <$t as $crate::Driver>::allocate_alarm(&$name) } #[no_mangle] - fn _embassy_time_set_alarm_callback(alarm: $crate::driver::AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - <$t as $crate::driver::Driver>::set_alarm_callback(&$name, alarm, callback, ctx) + fn _embassy_time_set_alarm_callback(alarm: $crate::AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { + <$t as $crate::Driver>::set_alarm_callback(&$name, alarm, callback, ctx) } #[no_mangle] - fn _embassy_time_set_alarm(alarm: $crate::driver::AlarmHandle, timestamp: u64) -> bool { - <$t as $crate::driver::Driver>::set_alarm(&$name, alarm, timestamp) + fn _embassy_time_set_alarm(alarm: $crate::AlarmHandle, timestamp: u64) -> bool { + <$t as $crate::Driver>::set_alarm(&$name, alarm, timestamp) } }; } diff --git a/embassy-time/src/tick.rs b/embassy-time-driver/src/tick.rs similarity index 100% rename from embassy-time/src/tick.rs rename to embassy-time-driver/src/tick.rs diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 2beefac83..729a2bd4f 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -13,12 +13,6 @@ categories = [ "asynchronous", ] -# Prevent multiple copies of this crate in the same binary. -# Needed because different copies might get different tick rates, causing -# wrong delays if the time driver is using one copy and user code is using another. -# This is especially common when mixing crates from crates.io and git. -links = "embassy-time" - [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-v$VERSION/embassy-time/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time/src/" @@ -81,328 +75,330 @@ generic-queue-128 = ["generic-queue"] # BEGIN TICKS # Generated by gen_tick.py. DO NOT EDIT. ## 1Hz Tick Rate -tick-hz-1 = [] +tick-hz-1 = ["embassy-time-driver/tick-hz-1"] ## 2Hz Tick Rate -tick-hz-2 = [] +tick-hz-2 = ["embassy-time-driver/tick-hz-2"] ## 4Hz Tick Rate -tick-hz-4 = [] +tick-hz-4 = ["embassy-time-driver/tick-hz-4"] ## 8Hz Tick Rate -tick-hz-8 = [] +tick-hz-8 = ["embassy-time-driver/tick-hz-8"] ## 10Hz Tick Rate -tick-hz-10 = [] +tick-hz-10 = ["embassy-time-driver/tick-hz-10"] ## 16Hz Tick Rate -tick-hz-16 = [] +tick-hz-16 = ["embassy-time-driver/tick-hz-16"] ## 32Hz Tick Rate -tick-hz-32 = [] +tick-hz-32 = ["embassy-time-driver/tick-hz-32"] ## 64Hz Tick Rate -tick-hz-64 = [] +tick-hz-64 = ["embassy-time-driver/tick-hz-64"] ## 100Hz Tick Rate -tick-hz-100 = [] +tick-hz-100 = ["embassy-time-driver/tick-hz-100"] ## 128Hz Tick Rate -tick-hz-128 = [] +tick-hz-128 = ["embassy-time-driver/tick-hz-128"] ## 256Hz Tick Rate -tick-hz-256 = [] +tick-hz-256 = ["embassy-time-driver/tick-hz-256"] ## 512Hz Tick Rate -tick-hz-512 = [] +tick-hz-512 = ["embassy-time-driver/tick-hz-512"] ## 1.0kHz Tick Rate -tick-hz-1_000 = [] +tick-hz-1_000 = ["embassy-time-driver/tick-hz-1_000"] ## 1.024kHz Tick Rate -tick-hz-1_024 = [] +tick-hz-1_024 = ["embassy-time-driver/tick-hz-1_024"] ## 2.0kHz Tick Rate -tick-hz-2_000 = [] +tick-hz-2_000 = ["embassy-time-driver/tick-hz-2_000"] ## 2.048kHz Tick Rate -tick-hz-2_048 = [] +tick-hz-2_048 = ["embassy-time-driver/tick-hz-2_048"] ## 4.0kHz Tick Rate -tick-hz-4_000 = [] +tick-hz-4_000 = ["embassy-time-driver/tick-hz-4_000"] ## 4.096kHz Tick Rate -tick-hz-4_096 = [] +tick-hz-4_096 = ["embassy-time-driver/tick-hz-4_096"] ## 8.0kHz Tick Rate -tick-hz-8_000 = [] +tick-hz-8_000 = ["embassy-time-driver/tick-hz-8_000"] ## 8.192kHz Tick Rate -tick-hz-8_192 = [] +tick-hz-8_192 = ["embassy-time-driver/tick-hz-8_192"] ## 10.0kHz Tick Rate -tick-hz-10_000 = [] +tick-hz-10_000 = ["embassy-time-driver/tick-hz-10_000"] ## 16.0kHz Tick Rate -tick-hz-16_000 = [] +tick-hz-16_000 = ["embassy-time-driver/tick-hz-16_000"] ## 16.384kHz Tick Rate -tick-hz-16_384 = [] +tick-hz-16_384 = ["embassy-time-driver/tick-hz-16_384"] ## 20.0kHz Tick Rate -tick-hz-20_000 = [] +tick-hz-20_000 = ["embassy-time-driver/tick-hz-20_000"] ## 32.0kHz Tick Rate -tick-hz-32_000 = [] +tick-hz-32_000 = ["embassy-time-driver/tick-hz-32_000"] ## 32.768kHz Tick Rate -tick-hz-32_768 = [] +tick-hz-32_768 = ["embassy-time-driver/tick-hz-32_768"] ## 40.0kHz Tick Rate -tick-hz-40_000 = [] +tick-hz-40_000 = ["embassy-time-driver/tick-hz-40_000"] ## 64.0kHz Tick Rate -tick-hz-64_000 = [] +tick-hz-64_000 = ["embassy-time-driver/tick-hz-64_000"] ## 65.536kHz Tick Rate -tick-hz-65_536 = [] +tick-hz-65_536 = ["embassy-time-driver/tick-hz-65_536"] ## 80.0kHz Tick Rate -tick-hz-80_000 = [] +tick-hz-80_000 = ["embassy-time-driver/tick-hz-80_000"] ## 100.0kHz Tick Rate -tick-hz-100_000 = [] +tick-hz-100_000 = ["embassy-time-driver/tick-hz-100_000"] ## 128.0kHz Tick Rate -tick-hz-128_000 = [] +tick-hz-128_000 = ["embassy-time-driver/tick-hz-128_000"] ## 131.072kHz Tick Rate -tick-hz-131_072 = [] +tick-hz-131_072 = ["embassy-time-driver/tick-hz-131_072"] ## 160.0kHz Tick Rate -tick-hz-160_000 = [] +tick-hz-160_000 = ["embassy-time-driver/tick-hz-160_000"] ## 256.0kHz Tick Rate -tick-hz-256_000 = [] +tick-hz-256_000 = ["embassy-time-driver/tick-hz-256_000"] ## 262.144kHz Tick Rate -tick-hz-262_144 = [] +tick-hz-262_144 = ["embassy-time-driver/tick-hz-262_144"] ## 320.0kHz Tick Rate -tick-hz-320_000 = [] +tick-hz-320_000 = ["embassy-time-driver/tick-hz-320_000"] ## 512.0kHz Tick Rate -tick-hz-512_000 = [] +tick-hz-512_000 = ["embassy-time-driver/tick-hz-512_000"] ## 524.288kHz Tick Rate -tick-hz-524_288 = [] +tick-hz-524_288 = ["embassy-time-driver/tick-hz-524_288"] ## 640.0kHz Tick Rate -tick-hz-640_000 = [] +tick-hz-640_000 = ["embassy-time-driver/tick-hz-640_000"] ## 1.0MHz Tick Rate -tick-hz-1_000_000 = [] +tick-hz-1_000_000 = ["embassy-time-driver/tick-hz-1_000_000"] ## 1.024MHz Tick Rate -tick-hz-1_024_000 = [] +tick-hz-1_024_000 = ["embassy-time-driver/tick-hz-1_024_000"] ## 1.048576MHz Tick Rate -tick-hz-1_048_576 = [] +tick-hz-1_048_576 = ["embassy-time-driver/tick-hz-1_048_576"] ## 1.28MHz Tick Rate -tick-hz-1_280_000 = [] +tick-hz-1_280_000 = ["embassy-time-driver/tick-hz-1_280_000"] ## 2.0MHz Tick Rate -tick-hz-2_000_000 = [] +tick-hz-2_000_000 = ["embassy-time-driver/tick-hz-2_000_000"] ## 2.048MHz Tick Rate -tick-hz-2_048_000 = [] +tick-hz-2_048_000 = ["embassy-time-driver/tick-hz-2_048_000"] ## 2.097152MHz Tick Rate -tick-hz-2_097_152 = [] +tick-hz-2_097_152 = ["embassy-time-driver/tick-hz-2_097_152"] ## 2.56MHz Tick Rate -tick-hz-2_560_000 = [] +tick-hz-2_560_000 = ["embassy-time-driver/tick-hz-2_560_000"] ## 3.0MHz Tick Rate -tick-hz-3_000_000 = [] +tick-hz-3_000_000 = ["embassy-time-driver/tick-hz-3_000_000"] ## 4.0MHz Tick Rate -tick-hz-4_000_000 = [] +tick-hz-4_000_000 = ["embassy-time-driver/tick-hz-4_000_000"] ## 4.096MHz Tick Rate -tick-hz-4_096_000 = [] +tick-hz-4_096_000 = ["embassy-time-driver/tick-hz-4_096_000"] ## 4.194304MHz Tick Rate -tick-hz-4_194_304 = [] +tick-hz-4_194_304 = ["embassy-time-driver/tick-hz-4_194_304"] ## 5.12MHz Tick Rate -tick-hz-5_120_000 = [] +tick-hz-5_120_000 = ["embassy-time-driver/tick-hz-5_120_000"] ## 6.0MHz Tick Rate -tick-hz-6_000_000 = [] +tick-hz-6_000_000 = ["embassy-time-driver/tick-hz-6_000_000"] ## 8.0MHz Tick Rate -tick-hz-8_000_000 = [] +tick-hz-8_000_000 = ["embassy-time-driver/tick-hz-8_000_000"] ## 8.192MHz Tick Rate -tick-hz-8_192_000 = [] +tick-hz-8_192_000 = ["embassy-time-driver/tick-hz-8_192_000"] ## 8.388608MHz Tick Rate -tick-hz-8_388_608 = [] +tick-hz-8_388_608 = ["embassy-time-driver/tick-hz-8_388_608"] ## 9.0MHz Tick Rate -tick-hz-9_000_000 = [] +tick-hz-9_000_000 = ["embassy-time-driver/tick-hz-9_000_000"] ## 10.0MHz Tick Rate -tick-hz-10_000_000 = [] +tick-hz-10_000_000 = ["embassy-time-driver/tick-hz-10_000_000"] ## 10.24MHz Tick Rate -tick-hz-10_240_000 = [] +tick-hz-10_240_000 = ["embassy-time-driver/tick-hz-10_240_000"] ## 12.0MHz Tick Rate -tick-hz-12_000_000 = [] +tick-hz-12_000_000 = ["embassy-time-driver/tick-hz-12_000_000"] ## 16.0MHz Tick Rate -tick-hz-16_000_000 = [] +tick-hz-16_000_000 = ["embassy-time-driver/tick-hz-16_000_000"] ## 16.384MHz Tick Rate -tick-hz-16_384_000 = [] +tick-hz-16_384_000 = ["embassy-time-driver/tick-hz-16_384_000"] ## 16.777216MHz Tick Rate -tick-hz-16_777_216 = [] +tick-hz-16_777_216 = ["embassy-time-driver/tick-hz-16_777_216"] ## 18.0MHz Tick Rate -tick-hz-18_000_000 = [] +tick-hz-18_000_000 = ["embassy-time-driver/tick-hz-18_000_000"] ## 20.0MHz Tick Rate -tick-hz-20_000_000 = [] +tick-hz-20_000_000 = ["embassy-time-driver/tick-hz-20_000_000"] ## 20.48MHz Tick Rate -tick-hz-20_480_000 = [] +tick-hz-20_480_000 = ["embassy-time-driver/tick-hz-20_480_000"] ## 24.0MHz Tick Rate -tick-hz-24_000_000 = [] +tick-hz-24_000_000 = ["embassy-time-driver/tick-hz-24_000_000"] ## 30.0MHz Tick Rate -tick-hz-30_000_000 = [] +tick-hz-30_000_000 = ["embassy-time-driver/tick-hz-30_000_000"] ## 32.0MHz Tick Rate -tick-hz-32_000_000 = [] +tick-hz-32_000_000 = ["embassy-time-driver/tick-hz-32_000_000"] ## 32.768MHz Tick Rate -tick-hz-32_768_000 = [] +tick-hz-32_768_000 = ["embassy-time-driver/tick-hz-32_768_000"] ## 36.0MHz Tick Rate -tick-hz-36_000_000 = [] +tick-hz-36_000_000 = ["embassy-time-driver/tick-hz-36_000_000"] ## 40.0MHz Tick Rate -tick-hz-40_000_000 = [] +tick-hz-40_000_000 = ["embassy-time-driver/tick-hz-40_000_000"] ## 40.96MHz Tick Rate -tick-hz-40_960_000 = [] +tick-hz-40_960_000 = ["embassy-time-driver/tick-hz-40_960_000"] ## 48.0MHz Tick Rate -tick-hz-48_000_000 = [] +tick-hz-48_000_000 = ["embassy-time-driver/tick-hz-48_000_000"] ## 50.0MHz Tick Rate -tick-hz-50_000_000 = [] +tick-hz-50_000_000 = ["embassy-time-driver/tick-hz-50_000_000"] ## 60.0MHz Tick Rate -tick-hz-60_000_000 = [] +tick-hz-60_000_000 = ["embassy-time-driver/tick-hz-60_000_000"] ## 64.0MHz Tick Rate -tick-hz-64_000_000 = [] +tick-hz-64_000_000 = ["embassy-time-driver/tick-hz-64_000_000"] ## 65.536MHz Tick Rate -tick-hz-65_536_000 = [] +tick-hz-65_536_000 = ["embassy-time-driver/tick-hz-65_536_000"] ## 70.0MHz Tick Rate -tick-hz-70_000_000 = [] +tick-hz-70_000_000 = ["embassy-time-driver/tick-hz-70_000_000"] ## 72.0MHz Tick Rate -tick-hz-72_000_000 = [] +tick-hz-72_000_000 = ["embassy-time-driver/tick-hz-72_000_000"] ## 80.0MHz Tick Rate -tick-hz-80_000_000 = [] +tick-hz-80_000_000 = ["embassy-time-driver/tick-hz-80_000_000"] ## 81.92MHz Tick Rate -tick-hz-81_920_000 = [] +tick-hz-81_920_000 = ["embassy-time-driver/tick-hz-81_920_000"] ## 90.0MHz Tick Rate -tick-hz-90_000_000 = [] +tick-hz-90_000_000 = ["embassy-time-driver/tick-hz-90_000_000"] ## 96.0MHz Tick Rate -tick-hz-96_000_000 = [] +tick-hz-96_000_000 = ["embassy-time-driver/tick-hz-96_000_000"] ## 100.0MHz Tick Rate -tick-hz-100_000_000 = [] +tick-hz-100_000_000 = ["embassy-time-driver/tick-hz-100_000_000"] ## 110.0MHz Tick Rate -tick-hz-110_000_000 = [] +tick-hz-110_000_000 = ["embassy-time-driver/tick-hz-110_000_000"] ## 120.0MHz Tick Rate -tick-hz-120_000_000 = [] +tick-hz-120_000_000 = ["embassy-time-driver/tick-hz-120_000_000"] ## 128.0MHz Tick Rate -tick-hz-128_000_000 = [] +tick-hz-128_000_000 = ["embassy-time-driver/tick-hz-128_000_000"] ## 130.0MHz Tick Rate -tick-hz-130_000_000 = [] +tick-hz-130_000_000 = ["embassy-time-driver/tick-hz-130_000_000"] ## 131.072MHz Tick Rate -tick-hz-131_072_000 = [] +tick-hz-131_072_000 = ["embassy-time-driver/tick-hz-131_072_000"] ## 140.0MHz Tick Rate -tick-hz-140_000_000 = [] +tick-hz-140_000_000 = ["embassy-time-driver/tick-hz-140_000_000"] ## 144.0MHz Tick Rate -tick-hz-144_000_000 = [] +tick-hz-144_000_000 = ["embassy-time-driver/tick-hz-144_000_000"] ## 150.0MHz Tick Rate -tick-hz-150_000_000 = [] +tick-hz-150_000_000 = ["embassy-time-driver/tick-hz-150_000_000"] ## 160.0MHz Tick Rate -tick-hz-160_000_000 = [] +tick-hz-160_000_000 = ["embassy-time-driver/tick-hz-160_000_000"] ## 163.84MHz Tick Rate -tick-hz-163_840_000 = [] +tick-hz-163_840_000 = ["embassy-time-driver/tick-hz-163_840_000"] ## 170.0MHz Tick Rate -tick-hz-170_000_000 = [] +tick-hz-170_000_000 = ["embassy-time-driver/tick-hz-170_000_000"] ## 180.0MHz Tick Rate -tick-hz-180_000_000 = [] +tick-hz-180_000_000 = ["embassy-time-driver/tick-hz-180_000_000"] ## 190.0MHz Tick Rate -tick-hz-190_000_000 = [] +tick-hz-190_000_000 = ["embassy-time-driver/tick-hz-190_000_000"] ## 192.0MHz Tick Rate -tick-hz-192_000_000 = [] +tick-hz-192_000_000 = ["embassy-time-driver/tick-hz-192_000_000"] ## 200.0MHz Tick Rate -tick-hz-200_000_000 = [] +tick-hz-200_000_000 = ["embassy-time-driver/tick-hz-200_000_000"] ## 210.0MHz Tick Rate -tick-hz-210_000_000 = [] +tick-hz-210_000_000 = ["embassy-time-driver/tick-hz-210_000_000"] ## 220.0MHz Tick Rate -tick-hz-220_000_000 = [] +tick-hz-220_000_000 = ["embassy-time-driver/tick-hz-220_000_000"] ## 230.0MHz Tick Rate -tick-hz-230_000_000 = [] +tick-hz-230_000_000 = ["embassy-time-driver/tick-hz-230_000_000"] ## 240.0MHz Tick Rate -tick-hz-240_000_000 = [] +tick-hz-240_000_000 = ["embassy-time-driver/tick-hz-240_000_000"] ## 250.0MHz Tick Rate -tick-hz-250_000_000 = [] +tick-hz-250_000_000 = ["embassy-time-driver/tick-hz-250_000_000"] ## 256.0MHz Tick Rate -tick-hz-256_000_000 = [] +tick-hz-256_000_000 = ["embassy-time-driver/tick-hz-256_000_000"] ## 260.0MHz Tick Rate -tick-hz-260_000_000 = [] +tick-hz-260_000_000 = ["embassy-time-driver/tick-hz-260_000_000"] ## 262.144MHz Tick Rate -tick-hz-262_144_000 = [] +tick-hz-262_144_000 = ["embassy-time-driver/tick-hz-262_144_000"] ## 270.0MHz Tick Rate -tick-hz-270_000_000 = [] +tick-hz-270_000_000 = ["embassy-time-driver/tick-hz-270_000_000"] ## 280.0MHz Tick Rate -tick-hz-280_000_000 = [] +tick-hz-280_000_000 = ["embassy-time-driver/tick-hz-280_000_000"] ## 288.0MHz Tick Rate -tick-hz-288_000_000 = [] +tick-hz-288_000_000 = ["embassy-time-driver/tick-hz-288_000_000"] ## 290.0MHz Tick Rate -tick-hz-290_000_000 = [] +tick-hz-290_000_000 = ["embassy-time-driver/tick-hz-290_000_000"] ## 300.0MHz Tick Rate -tick-hz-300_000_000 = [] +tick-hz-300_000_000 = ["embassy-time-driver/tick-hz-300_000_000"] ## 320.0MHz Tick Rate -tick-hz-320_000_000 = [] +tick-hz-320_000_000 = ["embassy-time-driver/tick-hz-320_000_000"] ## 327.68MHz Tick Rate -tick-hz-327_680_000 = [] +tick-hz-327_680_000 = ["embassy-time-driver/tick-hz-327_680_000"] ## 340.0MHz Tick Rate -tick-hz-340_000_000 = [] +tick-hz-340_000_000 = ["embassy-time-driver/tick-hz-340_000_000"] ## 360.0MHz Tick Rate -tick-hz-360_000_000 = [] +tick-hz-360_000_000 = ["embassy-time-driver/tick-hz-360_000_000"] ## 380.0MHz Tick Rate -tick-hz-380_000_000 = [] +tick-hz-380_000_000 = ["embassy-time-driver/tick-hz-380_000_000"] ## 384.0MHz Tick Rate -tick-hz-384_000_000 = [] +tick-hz-384_000_000 = ["embassy-time-driver/tick-hz-384_000_000"] ## 400.0MHz Tick Rate -tick-hz-400_000_000 = [] +tick-hz-400_000_000 = ["embassy-time-driver/tick-hz-400_000_000"] ## 420.0MHz Tick Rate -tick-hz-420_000_000 = [] +tick-hz-420_000_000 = ["embassy-time-driver/tick-hz-420_000_000"] ## 440.0MHz Tick Rate -tick-hz-440_000_000 = [] +tick-hz-440_000_000 = ["embassy-time-driver/tick-hz-440_000_000"] ## 460.0MHz Tick Rate -tick-hz-460_000_000 = [] +tick-hz-460_000_000 = ["embassy-time-driver/tick-hz-460_000_000"] ## 480.0MHz Tick Rate -tick-hz-480_000_000 = [] +tick-hz-480_000_000 = ["embassy-time-driver/tick-hz-480_000_000"] ## 500.0MHz Tick Rate -tick-hz-500_000_000 = [] +tick-hz-500_000_000 = ["embassy-time-driver/tick-hz-500_000_000"] ## 512.0MHz Tick Rate -tick-hz-512_000_000 = [] +tick-hz-512_000_000 = ["embassy-time-driver/tick-hz-512_000_000"] ## 520.0MHz Tick Rate -tick-hz-520_000_000 = [] +tick-hz-520_000_000 = ["embassy-time-driver/tick-hz-520_000_000"] ## 524.288MHz Tick Rate -tick-hz-524_288_000 = [] +tick-hz-524_288_000 = ["embassy-time-driver/tick-hz-524_288_000"] ## 540.0MHz Tick Rate -tick-hz-540_000_000 = [] +tick-hz-540_000_000 = ["embassy-time-driver/tick-hz-540_000_000"] ## 560.0MHz Tick Rate -tick-hz-560_000_000 = [] +tick-hz-560_000_000 = ["embassy-time-driver/tick-hz-560_000_000"] ## 576.0MHz Tick Rate -tick-hz-576_000_000 = [] +tick-hz-576_000_000 = ["embassy-time-driver/tick-hz-576_000_000"] ## 580.0MHz Tick Rate -tick-hz-580_000_000 = [] +tick-hz-580_000_000 = ["embassy-time-driver/tick-hz-580_000_000"] ## 600.0MHz Tick Rate -tick-hz-600_000_000 = [] +tick-hz-600_000_000 = ["embassy-time-driver/tick-hz-600_000_000"] ## 620.0MHz Tick Rate -tick-hz-620_000_000 = [] +tick-hz-620_000_000 = ["embassy-time-driver/tick-hz-620_000_000"] ## 640.0MHz Tick Rate -tick-hz-640_000_000 = [] +tick-hz-640_000_000 = ["embassy-time-driver/tick-hz-640_000_000"] ## 655.36MHz Tick Rate -tick-hz-655_360_000 = [] +tick-hz-655_360_000 = ["embassy-time-driver/tick-hz-655_360_000"] ## 660.0MHz Tick Rate -tick-hz-660_000_000 = [] +tick-hz-660_000_000 = ["embassy-time-driver/tick-hz-660_000_000"] ## 680.0MHz Tick Rate -tick-hz-680_000_000 = [] +tick-hz-680_000_000 = ["embassy-time-driver/tick-hz-680_000_000"] ## 700.0MHz Tick Rate -tick-hz-700_000_000 = [] +tick-hz-700_000_000 = ["embassy-time-driver/tick-hz-700_000_000"] ## 720.0MHz Tick Rate -tick-hz-720_000_000 = [] +tick-hz-720_000_000 = ["embassy-time-driver/tick-hz-720_000_000"] ## 740.0MHz Tick Rate -tick-hz-740_000_000 = [] +tick-hz-740_000_000 = ["embassy-time-driver/tick-hz-740_000_000"] ## 760.0MHz Tick Rate -tick-hz-760_000_000 = [] +tick-hz-760_000_000 = ["embassy-time-driver/tick-hz-760_000_000"] ## 768.0MHz Tick Rate -tick-hz-768_000_000 = [] +tick-hz-768_000_000 = ["embassy-time-driver/tick-hz-768_000_000"] ## 780.0MHz Tick Rate -tick-hz-780_000_000 = [] +tick-hz-780_000_000 = ["embassy-time-driver/tick-hz-780_000_000"] ## 800.0MHz Tick Rate -tick-hz-800_000_000 = [] +tick-hz-800_000_000 = ["embassy-time-driver/tick-hz-800_000_000"] ## 820.0MHz Tick Rate -tick-hz-820_000_000 = [] +tick-hz-820_000_000 = ["embassy-time-driver/tick-hz-820_000_000"] ## 840.0MHz Tick Rate -tick-hz-840_000_000 = [] +tick-hz-840_000_000 = ["embassy-time-driver/tick-hz-840_000_000"] ## 860.0MHz Tick Rate -tick-hz-860_000_000 = [] +tick-hz-860_000_000 = ["embassy-time-driver/tick-hz-860_000_000"] ## 880.0MHz Tick Rate -tick-hz-880_000_000 = [] +tick-hz-880_000_000 = ["embassy-time-driver/tick-hz-880_000_000"] ## 900.0MHz Tick Rate -tick-hz-900_000_000 = [] +tick-hz-900_000_000 = ["embassy-time-driver/tick-hz-900_000_000"] ## 920.0MHz Tick Rate -tick-hz-920_000_000 = [] +tick-hz-920_000_000 = ["embassy-time-driver/tick-hz-920_000_000"] ## 940.0MHz Tick Rate -tick-hz-940_000_000 = [] +tick-hz-940_000_000 = ["embassy-time-driver/tick-hz-940_000_000"] ## 960.0MHz Tick Rate -tick-hz-960_000_000 = [] +tick-hz-960_000_000 = ["embassy-time-driver/tick-hz-960_000_000"] ## 980.0MHz Tick Rate -tick-hz-980_000_000 = [] +tick-hz-980_000_000 = ["embassy-time-driver/tick-hz-980_000_000"] ## 1.0GHz Tick Rate -tick-hz-1_000_000_000 = [] +tick-hz-1_000_000_000 = ["embassy-time-driver/tick-hz-1_000_000_000"] ## 1.31072GHz Tick Rate -tick-hz-1_310_720_000 = [] +tick-hz-1_310_720_000 = ["embassy-time-driver/tick-hz-1_310_720_000"] ## 2.62144GHz Tick Rate -tick-hz-2_621_440_000 = [] +tick-hz-2_621_440_000 = ["embassy-time-driver/tick-hz-2_621_440_000"] ## 5.24288GHz Tick Rate -tick-hz-5_242_880_000 = [] +tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"] # END TICKS #!
[dependencies] +embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } + defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-time/README.md b/embassy-time/README.md index a4e150c14..20772f1d8 100644 --- a/embassy-time/README.md +++ b/embassy-time/README.md @@ -12,7 +12,7 @@ Tick counts are 64 bits. The default tick rate of 1Mhz supports representing time spans of up to ~584558 years, which is big enough for all practical purposes and allows not having to worry about overflows. -## Time driver +## Global time driver The `time` module is backed by a global "time driver" specified at build time. Only one driver can be active in a program. @@ -21,7 +21,7 @@ All methods and structs transparently call into the active driver. This makes it possible for libraries to use `embassy_time` in a driver-agnostic way without requiring generic parameters. -For more details, check the [`driver`] module. +For more details, check the [`embassy_time_driver`] crate. ## Instants and Durations diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index 7533d51e5..7abc2bd70 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -28,7 +28,7 @@ use crate::{Duration, Instant}; /// ``` pub struct MockDriver(CsMutex>); -crate::time_driver_impl!(static DRIVER: MockDriver = MockDriver::new()); +crate::driver::time_driver_impl!(static DRIVER: MockDriver = MockDriver::new()); impl MockDriver { /// Creates a new mock driver. diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index 32db47a37..3b5524f9e 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs @@ -45,7 +45,7 @@ struct TimeDriver { } const ALARM_NEW: AlarmState = AlarmState::new(); -crate::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { +crate::driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { alarm_count: AtomicU8::new(0), once: Once::new(), diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs index 0f672dc75..d75856c26 100644 --- a/embassy-time/src/driver_wasm.rs +++ b/embassy-time/src/driver_wasm.rs @@ -42,7 +42,7 @@ struct TimeDriver { } const ALARM_NEW: AlarmState = AlarmState::new(); -crate::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { +crate::driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { alarm_count: AtomicU8::new(0), once: Once::new(), alarms: UninitCell::uninit(), diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index 7e2546f68..3f8c09f1a 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -10,12 +10,12 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +pub use embassy_time_driver as driver; + mod delay; -pub mod driver; mod duration; mod instant; pub mod queue; -mod tick; mod timer; #[cfg(feature = "mock-driver")] @@ -32,15 +32,11 @@ mod driver_wasm; mod queue_generic; pub use delay::{block_for, Delay}; +pub use driver::TICK_HZ; pub use duration::Duration; pub use instant::Instant; pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; -/// Ticks per second of the global timebase. -/// -/// This value is specified by the [`tick-*` Cargo features](crate#tick-rate) -pub const TICK_HZ: u64 = tick::TICK_HZ; - const fn gcd(a: u64, b: u64) -> u64 { if b == 0 { a From 75b05fb3447c449ed14648edbf8382d046acafea Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 17:17:36 +0100 Subject: [PATCH 212/760] time: docs improvements, add ci. --- .github/ci/doc.sh | 1 + .github/ci/test.sh | 1 + embassy-time-driver/README.md | 3 +-- embassy-time-driver/src/lib.rs | 16 +++++----------- embassy-time/README.md | 2 +- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index fbed2752a..0bbe7f690 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -30,6 +30,7 @@ docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup docserver-builder -i ./embassy-time -o webroot/crates/embassy-time/git.zup +docserver-builder -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup diff --git a/.github/ci/test.sh b/.github/ci/test.sh index b16b3c20d..b6a5bcd56 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -12,6 +12,7 @@ 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 cargo test --manifest-path ./embassy-boot/boot/Cargo.toml cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features ed25519-dalek diff --git a/embassy-time-driver/README.md b/embassy-time-driver/README.md index 74a5b7876..426252d2c 100644 --- a/embassy-time-driver/README.md +++ b/embassy-time-driver/README.md @@ -1,6 +1,5 @@ # embassy-time-driver - This crate contains the driver trait necessary for adding [`embassy-time`](https://crates.io/crates/embassy-time) support for a new hardware platform. @@ -12,7 +11,7 @@ if the driver trait has not had breaking changes. ## How it works -`embassy-time` module is backed by a global "time driver" specified at build time. +`embassy-time` is backed by a global "time driver" specified at build time. Only one driver can be active in a program. All methods and structs transparently call into the active driver. This makes it diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 39a772aa5..565597935 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -2,22 +2,17 @@ #![doc = include_str!("../README.md")] #![warn(missing_docs)] -//! Time driver interface -//! -//! This module defines the interface a driver needs to implement to power the `embassy_time` module. -//! -//! # Implementing a driver +//! ## Implementing a driver //! //! - Define a struct `MyDriver` //! - Implement [`Driver`] for it //! - Register it as the global driver with [`time_driver_impl`](crate::time_driver_impl). -//! - Enable the Cargo feature `embassy-executor/time` //! //! If your driver has a single set tick rate, enable the corresponding [`tick-hz-*`](crate#tick-rate) feature, //! which will prevent users from needing to configure it themselves (or selecting an incorrect configuration). //! //! If your driver supports a small number of set tick rates, expose your own cargo features and have each one -//! enable the corresponding `embassy-time/tick-*`. +//! enable the corresponding `embassy-time-driver/tick-*`. //! //! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by //! enabling a feature on `embassy-time`. @@ -43,7 +38,7 @@ //! # Example //! //! ``` -//! use embassy_time::driver::{Driver, AlarmHandle}; +//! use embassy_time_driver::{Driver, AlarmHandle}; //! //! struct MyDriver{} // not public! //! @@ -61,9 +56,8 @@ //! todo!() //! } //! } -//! ``` -//! ```ignore -//! embassy_time::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); +//! +//! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); //! ``` //! ## Feature flags diff --git a/embassy-time/README.md b/embassy-time/README.md index 20772f1d8..f5d46df7b 100644 --- a/embassy-time/README.md +++ b/embassy-time/README.md @@ -21,7 +21,7 @@ All methods and structs transparently call into the active driver. This makes it possible for libraries to use `embassy_time` in a driver-agnostic way without requiring generic parameters. -For more details, check the [`embassy_time_driver`] crate. +For more details, check the [`embassy_time_driver`](https://crates.io/crates/embassy-time-driver) crate. ## Instants and Durations From b452a6bcf6858893a85882614e2dcde5a3405748 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 18:18:35 +0100 Subject: [PATCH 213/760] Centralize license and MSRV boilerplate into the repo readme. --- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- README.md | 8 +++++++- cyw43-pio/README.md | 14 -------------- cyw43/README.md | 15 --------------- embassy-boot/boot/README.md | 15 --------------- embassy-boot/nrf/README.md | 15 --------------- embassy-boot/rp/README.md | 14 -------------- embassy-boot/stm32/README.md | 14 -------------- embassy-executor-macros/README.md | 10 ---------- embassy-futures/README.md | 15 --------------- embassy-hal-internal/README.md | 10 ---------- embassy-net-adin1110/README.md | 10 ---------- embassy-net-driver-channel/README.md | 10 ---------- embassy-net-driver/README.md | 10 ---------- embassy-net-enc28j60/README.md | 10 ---------- embassy-net-esp-hosted/README.md | 11 ----------- embassy-net-ppp/README.md | 10 ---------- embassy-net-tuntap/README.md | 10 ---------- embassy-net-wiznet/README.md | 11 ----------- embassy-net/README.md | 10 ---------- embassy-nrf/README.md | 15 --------------- embassy-rp/README.md | 14 -------------- embassy-sync/README.md | 14 -------------- embassy-usb-dfu/README.md | 14 -------------- embassy-usb-driver/README.md | 15 --------------- embassy-usb-logger/README.md | 14 -------------- embassy-usb/README.md | 16 ---------------- 28 files changed, 9 insertions(+), 319 deletions(-) diff --git a/LICENSE-APACHE b/LICENSE-APACHE index ea4fa15c9..8f7956e20 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2019-2022 Embassy project contributors +Copyright (c) Embassy project contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 87c052836..1fe5730a4 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2019-2022 Embassy project contributors +Copyright (c) Embassy project contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index d2a24dfcc..24347a43f 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ EMBedded ASYnc! :) ## License -This work is licensed under either of +Embassy is licensed under either of - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or ) @@ -153,5 +153,11 @@ This work is licensed under either of at your option. +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + [1]: https://github.com/embassy-rs/embassy/wiki/Getting-Started [2]: https://github.com/embassy-rs/embassy/wiki/Running-the-Examples diff --git a/cyw43-pio/README.md b/cyw43-pio/README.md index 2b22db360..4a2b2aa4b 100644 --- a/cyw43-pio/README.md +++ b/cyw43-pio/README.md @@ -1,17 +1,3 @@ # cyw43-pio RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. The PIO driver offloads SPI communication with the WiFi chip and improves throughput. - -## Minimum supported Rust version (MSRV) - -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/cyw43/README.md b/cyw43/README.md index 2c24c7d36..dabdf0471 100644 --- a/cyw43/README.md +++ b/cyw43/README.md @@ -44,18 +44,3 @@ This example implements a TCP echo server on port 1234. You can try connecting t nc 192.168.0.250 1234 ``` Send it some data, you should see it echoed back and printed in the firmware's logs. - -## Minimum supported Rust version (MSRV) - -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. - diff --git a/embassy-boot/boot/README.md b/embassy-boot/boot/README.md index 3fc81f24b..3c2d45e96 100644 --- a/embassy-boot/boot/README.md +++ b/embassy-boot/boot/README.md @@ -33,18 +33,3 @@ The bootloader supports different hardware in separate crates: * `embassy-boot-nrf` - for the nRF microcontrollers. * `embassy-boot-rp` - for the RP2040 microcontrollers. * `embassy-boot-stm32` - for the STM32 microcontrollers. - - -## Minimum supported Rust version (MSRV) - -`embassy-boot` is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-boot/nrf/README.md b/embassy-boot/nrf/README.md index fe581823d..9dc5b0eb9 100644 --- a/embassy-boot/nrf/README.md +++ b/embassy-boot/nrf/README.md @@ -9,18 +9,3 @@ An adaptation of `embassy-boot` for nRF. * Load applications with or without the softdevice. * Configure bootloader partitions based on linker script. * Using watchdog timer to detect application failure. - - -## Minimum supported Rust version (MSRV) - -`embassy-boot-nrf` is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-boot/rp/README.md b/embassy-boot/rp/README.md index 315d655e3..b664145a9 100644 --- a/embassy-boot/rp/README.md +++ b/embassy-boot/rp/README.md @@ -10,17 +10,3 @@ NOTE: The applications using this bootloader should not link with the `link-rp.x * Configure bootloader partitions based on linker script. * Load applications from active partition. - -## Minimum supported Rust version (MSRV) - -`embassy-boot-rp` is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-boot/stm32/README.md b/embassy-boot/stm32/README.md index b4d7ba5a4..f6dadc8e7 100644 --- a/embassy-boot/stm32/README.md +++ b/embassy-boot/stm32/README.md @@ -8,17 +8,3 @@ An adaptation of `embassy-boot` for STM32. * Configure bootloader partitions based on linker script. * Load applications from active partition. - -## Minimum supported Rust version (MSRV) - -`embassy-boot-stm32` is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-executor-macros/README.md b/embassy-executor-macros/README.md index a959c85d5..3a8d49aa1 100644 --- a/embassy-executor-macros/README.md +++ b/embassy-executor-macros/README.md @@ -3,13 +3,3 @@ An [Embassy](https://embassy.dev) project. NOTE: Do not use this crate directly. The macros are re-exported by `embassy-executor`. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-futures/README.md b/embassy-futures/README.md index 7add22c7b..b28a8431a 100644 --- a/embassy-futures/README.md +++ b/embassy-futures/README.md @@ -11,18 +11,3 @@ ideal for embedded systems. ## Interoperability Futures from this crate can run on any executor. - -## Minimum supported Rust version (MSRV) - -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. - diff --git a/embassy-hal-internal/README.md b/embassy-hal-internal/README.md index 6b060d1c0..1adce5b33 100644 --- a/embassy-hal-internal/README.md +++ b/embassy-hal-internal/README.md @@ -4,13 +4,3 @@ An [Embassy](https://embassy.dev) project. Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY. Embassy HALs (`embassy-nrf`, `embassy-stm32`, `embassy-rp`) already reexport everything you need to use them effectively. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md index 8ea10b714..39a38960d 100644 --- a/embassy-net-adin1110/README.md +++ b/embassy-net-adin1110/README.md @@ -76,13 +76,3 @@ Summary: Size/request: 289 B Size/sec: 51.11 KiB ``` - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-net-driver-channel/README.md b/embassy-net-driver-channel/README.md index 90a216388..1955624d1 100644 --- a/embassy-net-driver-channel/README.md +++ b/embassy-net-driver-channel/README.md @@ -84,13 +84,3 @@ These `embassy-net` drivers are implemented using this crate. You can look at th ## Interoperability This crate can run on any executor. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-net-driver/README.md b/embassy-net-driver/README.md index 6a757380d..24fcaafc4 100644 --- a/embassy-net-driver/README.md +++ b/embassy-net-driver/README.md @@ -16,13 +16,3 @@ packet queues for RX and TX. ## Interoperability This crate can run on any executor. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-net-enc28j60/README.md b/embassy-net-enc28j60/README.md index 39011ca13..5c663b52e 100644 --- a/embassy-net-enc28j60/README.md +++ b/embassy-net-enc28j60/README.md @@ -7,13 +7,3 @@ Based on [@japaric](https://github.com/japaric)'s [`enc28j60`](https://github.co ## Interoperability This crate can run on any executor. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-net-esp-hosted/README.md b/embassy-net-esp-hosted/README.md index 3c9cc4c9e..f6c216835 100644 --- a/embassy-net-esp-hosted/README.md +++ b/embassy-net-esp-hosted/README.md @@ -14,14 +14,3 @@ See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf528 This crate can run on any executor. It supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async). - - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-net-ppp/README.md b/embassy-net-ppp/README.md index 58d67395a..0eb7cee87 100644 --- a/embassy-net-ppp/README.md +++ b/embassy-net-ppp/README.md @@ -7,13 +7,3 @@ This crate can run on any executor. It supports any serial port implementing [`embedded-io-async`](https://crates.io/crates/embedded-io-async). - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-net-tuntap/README.md b/embassy-net-tuntap/README.md index c5d9e746c..60a4a1bd9 100644 --- a/embassy-net-tuntap/README.md +++ b/embassy-net-tuntap/README.md @@ -5,13 +5,3 @@ ## Interoperability This crate can run on any executor. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-net-wiznet/README.md b/embassy-net-wiznet/README.md index b8e4bdc8e..786aab18d 100644 --- a/embassy-net-wiznet/README.md +++ b/embassy-net-wiznet/README.md @@ -14,14 +14,3 @@ See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/rp) di This crate can run on any executor. It supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async). - - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-net/README.md b/embassy-net/README.md index 52d048e6a..94aa6f550 100644 --- a/embassy-net/README.md +++ b/embassy-net/README.md @@ -51,13 +51,3 @@ This crate can run on any executor. [`embassy-time`](https://crates.io/crates/embassy-time) is used for timekeeping and timeouts. You must link an `embassy-time` driver in your project to use this crate. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md index 39de3854b..5e2bd86de 100644 --- a/embassy-nrf/README.md +++ b/embassy-nrf/README.md @@ -43,18 +43,3 @@ as the methods without the suffix will be allocating a statically sized buffer ( Note that the methods that read data like [`read`](spim::Spim::read) and [`transfer_in_place`](spim::Spim::transfer_in_place) do not have the corresponding `_from_ram` variants as mutable slices always reside in RAM. - -## Minimum supported Rust version (MSRV) - -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. - diff --git a/embassy-rp/README.md b/embassy-rp/README.md index cd79fe501..1d14eca52 100644 --- a/embassy-rp/README.md +++ b/embassy-rp/README.md @@ -7,17 +7,3 @@ for many peripherals. The benefit of using the async APIs is that the HAL takes complete operations in low power mod and handling interrupts, so that applications can focus on more important matters. NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use. - -## Minimum supported Rust version (MSRV) - -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-sync/README.md b/embassy-sync/README.md index 55618f72d..c2e13799e 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md @@ -17,17 +17,3 @@ Synchronization primitives and data structures with async support: ## Interoperability Futures from this crate can run on any executor. - -## Minimum supported Rust version (MSRV) - -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-usb-dfu/README.md b/embassy-usb-dfu/README.md index d8bc19bfd..bdd5b033a 100644 --- a/embassy-usb-dfu/README.md +++ b/embassy-usb-dfu/README.md @@ -4,17 +4,3 @@ An implementation of the USB DFU 1.1 protocol using embassy-boot. It has 2 compo * DFU protocol mode, enabled by the `dfu` feature. This mode corresponds to the transfer phase DFU protocol described by the USB IF. It supports DFU_DNLOAD requests if marked by the user, and will automatically reset the chip once a DFU transaction has been completed. It also responds to DFU_GETSTATUS, DFU_GETSTATE, DFU_ABORT, and DFU_CLRSTATUS with no user intervention. * DFU runtime mode, enabled by the `application feature`. This mode allows users to expose a DFU interface on their USB device, informing the host of the capability to DFU over USB, and allowing the host to reset the device into its bootloader to complete a DFU operation. Supports DFU_GETSTATUS and DFU_DETACH. When detach/reset is seen by the device as described by the standard, will write a new DFU magic number into the bootloader state in flash, and reset the system. - -## Minimum supported Rust version (MSRV) - -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-usb-driver/README.md b/embassy-usb-driver/README.md index 93aef7596..7628a6937 100644 --- a/embassy-usb-driver/README.md +++ b/embassy-usb-driver/README.md @@ -15,18 +15,3 @@ instead of this one. ## Interoperability This crate can run on any executor. - -## Minimum supported Rust version (MSRV) - -This crate requires nightly Rust, due to using "async fn in trait" support. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. - diff --git a/embassy-usb-logger/README.md b/embassy-usb-logger/README.md index 6cb18e87d..81b0dcd0e 100644 --- a/embassy-usb-logger/README.md +++ b/embassy-usb-logger/README.md @@ -13,17 +13,3 @@ async fn logger_task(driver: Driver<'static, USB>) { embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver); } ``` - -## Minimum supported Rust version (MSRV) - -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. diff --git a/embassy-usb/README.md b/embassy-usb/README.md index a3d45b561..da656e8e9 100644 --- a/embassy-usb/README.md +++ b/embassy-usb/README.md @@ -23,22 +23,6 @@ with different values, compilation fails. Max amount of interfaces that can be created in one device. Default: 4. - ## Interoperability This crate can run on any executor. - -## Minimum supported Rust version (MSRV) - -This crate requires nightly Rust, due to using "async fn in trait" support. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. - From e0775fbc8ab1ecc83bce42fe6e11accf481bc9e1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 18:55:59 +0100 Subject: [PATCH 214/760] Flatten embassy-boot dir tree --- .github/ci/doc.sh | 8 ++++---- .github/ci/test.sh | 6 +++--- ci.sh | 8 ++++---- {embassy-boot/nrf => embassy-boot-nrf}/Cargo.toml | 10 +++++----- {embassy-boot/nrf => embassy-boot-nrf}/README.md | 0 {embassy-boot/boot => embassy-boot-nrf}/src/fmt.rs | 0 {embassy-boot/nrf => embassy-boot-nrf}/src/lib.rs | 0 {embassy-boot/rp => embassy-boot-rp}/Cargo.toml | 10 +++++----- {embassy-boot/rp => embassy-boot-rp}/README.md | 0 {embassy-boot/rp => embassy-boot-rp}/build.rs | 0 {embassy-boot/nrf => embassy-boot-rp}/src/fmt.rs | 0 {embassy-boot/rp => embassy-boot-rp}/src/lib.rs | 0 {embassy-boot/stm32 => embassy-boot-stm32}/Cargo.toml | 10 +++++----- {embassy-boot/stm32 => embassy-boot-stm32}/README.md | 0 {embassy-boot/stm32 => embassy-boot-stm32}/build.rs | 0 {embassy-boot/rp => embassy-boot-stm32}/src/fmt.rs | 0 {embassy-boot/stm32 => embassy-boot-stm32}/src/lib.rs | 0 embassy-boot/{boot => }/Cargo.toml | 8 ++++---- embassy-boot/{boot => }/README.md | 0 embassy-boot/{boot => }/src/boot_loader.rs | 0 .../{boot => }/src/digest_adapters/ed25519_dalek.rs | 0 embassy-boot/{boot => }/src/digest_adapters/mod.rs | 0 embassy-boot/{boot => }/src/digest_adapters/salty.rs | 0 embassy-boot/{boot => }/src/firmware_updater/asynch.rs | 0 .../{boot => }/src/firmware_updater/blocking.rs | 0 embassy-boot/{boot => }/src/firmware_updater/mod.rs | 0 embassy-boot/{stm32 => }/src/fmt.rs | 0 embassy-boot/{boot => }/src/lib.rs | 0 embassy-boot/{boot => }/src/mem_flash.rs | 0 embassy-boot/{boot => }/src/test_flash/asynch.rs | 0 embassy-boot/{boot => }/src/test_flash/blocking.rs | 0 embassy-boot/{boot => }/src/test_flash/mod.rs | 0 embassy-usb-dfu/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 4 ++-- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/boot/bootloader/nrf/Cargo.toml | 2 +- examples/boot/bootloader/rp/Cargo.toml | 2 +- examples/boot/bootloader/stm32/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- 47 files changed, 46 insertions(+), 46 deletions(-) rename {embassy-boot/nrf => embassy-boot-nrf}/Cargo.toml (76%) rename {embassy-boot/nrf => embassy-boot-nrf}/README.md (100%) rename {embassy-boot/boot => embassy-boot-nrf}/src/fmt.rs (100%) rename {embassy-boot/nrf => embassy-boot-nrf}/src/lib.rs (100%) rename {embassy-boot/rp => embassy-boot-rp}/Cargo.toml (83%) rename {embassy-boot/rp => embassy-boot-rp}/README.md (100%) rename {embassy-boot/rp => embassy-boot-rp}/build.rs (100%) rename {embassy-boot/nrf => embassy-boot-rp}/src/fmt.rs (100%) rename {embassy-boot/rp => embassy-boot-rp}/src/lib.rs (100%) rename {embassy-boot/stm32 => embassy-boot-stm32}/Cargo.toml (84%) rename {embassy-boot/stm32 => embassy-boot-stm32}/README.md (100%) rename {embassy-boot/stm32 => embassy-boot-stm32}/build.rs (100%) rename {embassy-boot/rp => embassy-boot-stm32}/src/fmt.rs (100%) rename {embassy-boot/stm32 => embassy-boot-stm32}/src/lib.rs (100%) rename embassy-boot/{boot => }/Cargo.toml (87%) rename embassy-boot/{boot => }/README.md (100%) rename embassy-boot/{boot => }/src/boot_loader.rs (100%) rename embassy-boot/{boot => }/src/digest_adapters/ed25519_dalek.rs (100%) rename embassy-boot/{boot => }/src/digest_adapters/mod.rs (100%) rename embassy-boot/{boot => }/src/digest_adapters/salty.rs (100%) rename embassy-boot/{boot => }/src/firmware_updater/asynch.rs (100%) rename embassy-boot/{boot => }/src/firmware_updater/blocking.rs (100%) rename embassy-boot/{boot => }/src/firmware_updater/mod.rs (100%) rename embassy-boot/{stm32 => }/src/fmt.rs (100%) rename embassy-boot/{boot => }/src/lib.rs (100%) rename embassy-boot/{boot => }/src/mem_flash.rs (100%) rename embassy-boot/{boot => }/src/test_flash/asynch.rs (100%) rename embassy-boot/{boot => }/src/test_flash/blocking.rs (100%) rename embassy-boot/{boot => }/src/test_flash/mod.rs (100%) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index 0bbe7f690..aaccb8a67 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -16,10 +16,10 @@ mv rust-toolchain-nightly.toml rust-toolchain.toml # which makes rustup very sad rustc --version > /dev/null -docserver-builder -i ./embassy-boot/boot -o webroot/crates/embassy-boot/git.zup -docserver-builder -i ./embassy-boot/nrf -o webroot/crates/embassy-boot-nrf/git.zup -docserver-builder -i ./embassy-boot/rp -o webroot/crates/embassy-boot-rp/git.zup -docserver-builder -i ./embassy-boot/stm32 -o webroot/crates/embassy-boot-stm32/git.zup +docserver-builder -i ./embassy-boot -o webroot/crates/embassy-boot/git.zup +docserver-builder -i ./embassy-boot-nrf -o webroot/crates/embassy-boot-nrf/git.zup +docserver-builder -i ./embassy-boot-rp -o webroot/crates/embassy-boot-rp/git.zup +docserver-builder -i ./embassy-boot-stm32 -o webroot/crates/embassy-boot-stm32/git.zup docserver-builder -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup diff --git a/.github/ci/test.sh b/.github/ci/test.sh index b6a5bcd56..8a58939f6 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -14,9 +14,9 @@ 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 -cargo test --manifest-path ./embassy-boot/boot/Cargo.toml -cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features ed25519-dalek -cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features ed25519-salty +cargo test --manifest-path ./embassy-boot/Cargo.toml +cargo test --manifest-path ./embassy-boot/Cargo.toml --features ed25519-dalek +cargo test --manifest-path ./embassy-boot/Cargo.toml --features ed25519-salty cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nrf52840,time-driver-rtc1,gpiote diff --git a/ci.sh b/ci.sh index ac0457679..7805c8ad1 100755 --- a/ci.sh +++ b/ci.sh @@ -136,10 +136,10 @@ cargo batch \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \ - --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ - --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ - --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi \ - --- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ + --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ + --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ + --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi \ + --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ diff --git a/embassy-boot/nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml similarity index 76% rename from embassy-boot/nrf/Cargo.toml rename to embassy-boot-nrf/Cargo.toml index 9f74fb126..7fc53648a 100644 --- a/embassy-boot/nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -12,8 +12,8 @@ categories = [ ] [package.metadata.embassy_docs] -src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/nrf/src/" -src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/nrf/src/" +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot-nrf/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot-nrf/src/" features = ["embassy-nrf/nrf52840"] target = "thumbv7em-none-eabi" @@ -22,9 +22,9 @@ target = "thumbv7em-none-eabi" [dependencies] defmt = { version = "0.3", optional = true } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } -embassy-nrf = { path = "../../embassy-nrf" } -embassy-boot = { path = "../boot", default-features = false } +embassy-sync = { version = "0.5.0", path = "../embassy-sync" } +embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false } +embassy-boot = { version = "0.1.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" diff --git a/embassy-boot/nrf/README.md b/embassy-boot-nrf/README.md similarity index 100% rename from embassy-boot/nrf/README.md rename to embassy-boot-nrf/README.md diff --git a/embassy-boot/boot/src/fmt.rs b/embassy-boot-nrf/src/fmt.rs similarity index 100% rename from embassy-boot/boot/src/fmt.rs rename to embassy-boot-nrf/src/fmt.rs diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs similarity index 100% rename from embassy-boot/nrf/src/lib.rs rename to embassy-boot-nrf/src/lib.rs diff --git a/embassy-boot/rp/Cargo.toml b/embassy-boot-rp/Cargo.toml similarity index 83% rename from embassy-boot/rp/Cargo.toml rename to embassy-boot-rp/Cargo.toml index 90bab0996..dacb27747 100644 --- a/embassy-boot/rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -13,7 +13,7 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/" -src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/rp/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot-rp/src/" target = "thumbv6m-none-eabi" [lib] @@ -23,10 +23,10 @@ defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } log = { version = "0.4", optional = true } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } -embassy-rp = { path = "../../embassy-rp", default-features = false } -embassy-boot = { path = "../boot", default-features = false } -embassy-time = { path = "../../embassy-time" } +embassy-sync = { version = "0.5.0", path = "../embassy-sync" } +embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false } +embassy-boot = { version = "0.1.0", path = "../embassy-boot" } +embassy-time = { version = "0.2.0", path = "../embassy-time" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-boot/rp/README.md b/embassy-boot-rp/README.md similarity index 100% rename from embassy-boot/rp/README.md rename to embassy-boot-rp/README.md diff --git a/embassy-boot/rp/build.rs b/embassy-boot-rp/build.rs similarity index 100% rename from embassy-boot/rp/build.rs rename to embassy-boot-rp/build.rs diff --git a/embassy-boot/nrf/src/fmt.rs b/embassy-boot-rp/src/fmt.rs similarity index 100% rename from embassy-boot/nrf/src/fmt.rs rename to embassy-boot-rp/src/fmt.rs diff --git a/embassy-boot/rp/src/lib.rs b/embassy-boot-rp/src/lib.rs similarity index 100% rename from embassy-boot/rp/src/lib.rs rename to embassy-boot-rp/src/lib.rs diff --git a/embassy-boot/stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml similarity index 84% rename from embassy-boot/stm32/Cargo.toml rename to embassy-boot-stm32/Cargo.toml index 70919b76d..f4e31bae8 100644 --- a/embassy-boot/stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -12,8 +12,8 @@ categories = [ ] [package.metadata.embassy_docs] -src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/stm32/src/" -src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/stm32/src/" +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot-stm32/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot-stm32/src/" features = ["embassy-stm32/stm32f429zi"] target = "thumbv7em-none-eabi" @@ -24,9 +24,9 @@ defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } log = { version = "0.4", optional = true } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } -embassy-stm32 = { path = "../../embassy-stm32", default-features = false } -embassy-boot = { path = "../boot", default-features = false } +embassy-sync = { version = "0.5.0", path = "../embassy-sync" } +embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false } +embassy-boot = { version = "0.1.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" diff --git a/embassy-boot/stm32/README.md b/embassy-boot-stm32/README.md similarity index 100% rename from embassy-boot/stm32/README.md rename to embassy-boot-stm32/README.md diff --git a/embassy-boot/stm32/build.rs b/embassy-boot-stm32/build.rs similarity index 100% rename from embassy-boot/stm32/build.rs rename to embassy-boot-stm32/build.rs diff --git a/embassy-boot/rp/src/fmt.rs b/embassy-boot-stm32/src/fmt.rs similarity index 100% rename from embassy-boot/rp/src/fmt.rs rename to embassy-boot-stm32/src/fmt.rs diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot-stm32/src/lib.rs similarity index 100% rename from embassy-boot/stm32/src/lib.rs rename to embassy-boot-stm32/src/lib.rs diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/Cargo.toml similarity index 87% rename from embassy-boot/boot/Cargo.toml rename to embassy-boot/Cargo.toml index 3c84ffcd3..a70849018 100644 --- a/embassy-boot/boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -12,8 +12,8 @@ categories = [ ] [package.metadata.embassy_docs] -src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-v$VERSION/embassy-boot/boot/src/" -src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/boot/src/" +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-v$VERSION/embassy-boot/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/src/" target = "thumbv7em-none-eabi" features = ["defmt"] @@ -27,8 +27,8 @@ defmt = { version = "0.3", optional = true } digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true } -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } +embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } salty = { version = "0.3", optional = true } diff --git a/embassy-boot/boot/README.md b/embassy-boot/README.md similarity index 100% rename from embassy-boot/boot/README.md rename to embassy-boot/README.md diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs similarity index 100% rename from embassy-boot/boot/src/boot_loader.rs rename to embassy-boot/src/boot_loader.rs diff --git a/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs b/embassy-boot/src/digest_adapters/ed25519_dalek.rs similarity index 100% rename from embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs rename to embassy-boot/src/digest_adapters/ed25519_dalek.rs diff --git a/embassy-boot/boot/src/digest_adapters/mod.rs b/embassy-boot/src/digest_adapters/mod.rs similarity index 100% rename from embassy-boot/boot/src/digest_adapters/mod.rs rename to embassy-boot/src/digest_adapters/mod.rs diff --git a/embassy-boot/boot/src/digest_adapters/salty.rs b/embassy-boot/src/digest_adapters/salty.rs similarity index 100% rename from embassy-boot/boot/src/digest_adapters/salty.rs rename to embassy-boot/src/digest_adapters/salty.rs diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs similarity index 100% rename from embassy-boot/boot/src/firmware_updater/asynch.rs rename to embassy-boot/src/firmware_updater/asynch.rs diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs similarity index 100% rename from embassy-boot/boot/src/firmware_updater/blocking.rs rename to embassy-boot/src/firmware_updater/blocking.rs diff --git a/embassy-boot/boot/src/firmware_updater/mod.rs b/embassy-boot/src/firmware_updater/mod.rs similarity index 100% rename from embassy-boot/boot/src/firmware_updater/mod.rs rename to embassy-boot/src/firmware_updater/mod.rs diff --git a/embassy-boot/stm32/src/fmt.rs b/embassy-boot/src/fmt.rs similarity index 100% rename from embassy-boot/stm32/src/fmt.rs rename to embassy-boot/src/fmt.rs diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/src/lib.rs similarity index 100% rename from embassy-boot/boot/src/lib.rs rename to embassy-boot/src/lib.rs diff --git a/embassy-boot/boot/src/mem_flash.rs b/embassy-boot/src/mem_flash.rs similarity index 100% rename from embassy-boot/boot/src/mem_flash.rs rename to embassy-boot/src/mem_flash.rs diff --git a/embassy-boot/boot/src/test_flash/asynch.rs b/embassy-boot/src/test_flash/asynch.rs similarity index 100% rename from embassy-boot/boot/src/test_flash/asynch.rs rename to embassy-boot/src/test_flash/asynch.rs diff --git a/embassy-boot/boot/src/test_flash/blocking.rs b/embassy-boot/src/test_flash/blocking.rs similarity index 100% rename from embassy-boot/boot/src/test_flash/blocking.rs rename to embassy-boot/src/test_flash/blocking.rs diff --git a/embassy-boot/boot/src/test_flash/mod.rs b/embassy-boot/src/test_flash/mod.rs similarity index 100% rename from embassy-boot/boot/src/test_flash/mod.rs rename to embassy-boot/src/test_flash/mod.rs diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index ee110ee87..2d8895123 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -17,7 +17,7 @@ categories = [ bitflags = "2.4.1" cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } defmt = { version = "0.3.5", optional = true } -embassy-boot = { version = "0.1.1", path = "../embassy-boot/boot" } +embassy-boot = { version = "0.1.1", path = "../embassy-boot" } # embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index eba9a0579..7b62d9a20 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -9,8 +9,8 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } -embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] } -embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = [] } +embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot", features = [] } +embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 38c9f8cff..ccaa9f8ef 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } -embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] } +embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = "0.3" diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 9c0aeb463..f4bc285bf 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32" } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index e81ff618e..575220ade 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index f75ffc8e6..12c34565a 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index f58bd9557..9f705dc26 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 887126f9d..7ba5f143b 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index d5fabac82..08cb87e0b 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 394546b75..58bba66d7 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 6c4dc7975..7ce560de2 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } +embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index a7273175f..3e41d1479 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -10,7 +10,7 @@ defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } embassy-nrf = { path = "../../../../embassy-nrf", features = [] } -embassy-boot-nrf = { path = "../../../../embassy-boot/nrf" } +embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 5bc61e9ec..3cf61a002 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -10,7 +10,7 @@ defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } embassy-rp = { path = "../../../../embassy-rp", features = [] } -embassy-boot-rp = { path = "../../../../embassy-boot/rp" } +embassy-boot-rp = { path = "../../../../embassy-boot-rp" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-time = { path = "../../../../embassy-time", features = [] } diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index 2d88b0f78..74c01b0f4 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -10,7 +10,7 @@ defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } -embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32" } +embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index ada073970..96635afa2 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -10,7 +10,7 @@ defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = ["stm32wb55rg"] } -embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32" } +embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } From ddacbf68aff53447bdfac7db2380a9f0aaaf0b83 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 18:56:17 +0100 Subject: [PATCH 215/760] net-esp-hosted: fix readme. --- embassy-net-esp-hosted/README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/embassy-net-esp-hosted/README.md b/embassy-net-esp-hosted/README.md index f6c216835..524231e6c 100644 --- a/embassy-net-esp-hosted/README.md +++ b/embassy-net-esp-hosted/README.md @@ -1,14 +1,9 @@ # ESP-Hosted `embassy-net` integration -[`embassy-net`](https://crates.io/crates/embassy-net) integration for Espressif SoCs running the the ESP-Hosted stack. +[`embassy-net`](https://crates.io/crates/embassy-net) integration for Espressif SoCs running the the [ESP-Hosted](https://github.com/espressif/esp-hosted) stack. See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840) directory for usage examples with the nRF52840. -## Supported chips - -- W5500 -- W5100S - ## Interoperability This crate can run on any executor. From 0af44292a0862b1c115def1ed1a48e29daae241c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 19:10:56 +0100 Subject: [PATCH 216/760] usb: add readme. --- embassy-usb/README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/embassy-usb/README.md b/embassy-usb/README.md index da656e8e9..7411fcf52 100644 --- a/embassy-usb/README.md +++ b/embassy-usb/README.md @@ -1,6 +1,28 @@ # embassy-usb -TODO crate description +Async USB device stack for embedded devices in Rust. + +## Features + +- Native async. +- Fully lock-free: endpoints are separate objects that can be used independently without needing a central mutex. If the driver supports it, they can even be used from different priority levels. +- Suspend/resume, remote wakeup. +- USB composite devices. +- Ergonomic descriptor builder. +- Ready-to-use implementations for a few USB classes (note you can still implement any class yourself oustide the crate). + - Serial ports (CDC ACM) + - Ethernet (CDC NCM) + - Human Interface Devices (HID) + - MIDI + +## Adding support for new hardware + +To add `embassy-usb` support for new hardware (i.e. a new MCU chip), you have to write a driver that implements +the [`embassy-usb-driver`](https://crates.io/crates/embassy-usb-driver) traits. + +Driver crates should depend only on `embassy-usb-driver`, not on the main `embassy-usb` crate. +This allows existing drivers to continue working for newer `embassy-usb` major versions, without needing an update, if the driver +trait has not had breaking changes. ## Configuration From 3119aeec5cc05f78a6551ae845f2dbc659bb631a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 11 Jan 2024 19:19:16 +0100 Subject: [PATCH 217/760] add nrf9160 example (assumes SPM from zephyr) --- examples/nrf9160/.cargo/config.toml | 9 +++++++ examples/nrf9160/Cargo.toml | 40 +++++++++++++++++++++++++++++ examples/nrf9160/build.rs | 35 +++++++++++++++++++++++++ examples/nrf9160/memory.x | 7 +++++ examples/nrf9160/src/bin/blinky.rs | 20 +++++++++++++++ 5 files changed, 111 insertions(+) create mode 100644 examples/nrf9160/.cargo/config.toml create mode 100644 examples/nrf9160/Cargo.toml create mode 100644 examples/nrf9160/build.rs create mode 100644 examples/nrf9160/memory.x create mode 100644 examples/nrf9160/src/bin/blinky.rs diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml new file mode 100644 index 000000000..1444b0cd1 --- /dev/null +++ b/examples/nrf9160/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF9160_xxAA" + +[build] +target = "thumbv8m.main-none-eabihf" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml new file mode 100644 index 000000000..b35b7778d --- /dev/null +++ b/examples/nrf9160/Cargo.toml @@ -0,0 +1,40 @@ +[package] +edition = "2021" +name = "embassy-nrf9160-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } +embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embedded-io = { version = "0.6.0", features = ["defmt-03"] } +embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } +embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } +embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } + +defmt = "0.3" +defmt-rtt = "0.4" + +fixed = "1.10.0" +static_cell = { version = "2" } +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +panic-probe = { version = "0.3", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +rand = { version = "0.8.4", default-features = false } +embedded-storage = "0.3.1" +usbd-hid = "0.6.0" +serde = { version = "1.0.136", default-features = false } +embedded-hal = { version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-bus = { version = "0.1", features = ["async"] } +num-integer = { version = "0.1.45", default-features = false } +microfft = "0.5.0" + +[profile.release] +debug = 2 diff --git a/examples/nrf9160/build.rs b/examples/nrf9160/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf9160/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + 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/nrf9160/memory.x b/examples/nrf9160/memory.x new file mode 100644 index 000000000..4d1d77c00 --- /dev/null +++ b/examples/nrf9160/memory.x @@ -0,0 +1,7 @@ +MEMORY +{ + /* Assumes Secure Partition Manager (SPM) flashed at the start */ + SPM : ORIGIN = 0x00000000, LENGTH = 320K + FLASH : ORIGIN = 0x00050000, LENGTH = 704K + RAM : ORIGIN = 0x20018000, LENGTH = 160K +} diff --git a/examples/nrf9160/src/bin/blinky.rs b/examples/nrf9160/src/bin/blinky.rs new file mode 100644 index 000000000..7ac5c31e1 --- /dev/null +++ b/examples/nrf9160/src/bin/blinky.rs @@ -0,0 +1,20 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P0_02, Level::Low, OutputDrive::Standard); + + loop { + led.set_high(); + Timer::after_millis(300).await; + led.set_low(); + Timer::after_millis(300).await; + } +} From f9e274e0574c58b0132612eb5aae81ea51a4b931 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 11 Jan 2024 19:21:33 +0100 Subject: [PATCH 218/760] docs: more docs on nrf --- embassy-nrf/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md index 39de3854b..18cb21f46 100644 --- a/embassy-nrf/README.md +++ b/embassy-nrf/README.md @@ -8,6 +8,20 @@ complete operations in low power mod and handling interrupts, so that applicatio NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use. +## Hardware support + +The `embassy-nrf` HAL supports most variants of the nRF family: + +* nRF52 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840)) +* nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340)) +* nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160)) + +Most peripherals are supported. For a complete list of available peripherals and features, see the [documentation](https://docs.embassy.dev/embassy-nrf/git/nrf52805/index.html). + +## API + +The `embassy-nrf` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async). + ## EasyDMA considerations On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting From 46602903f5defa77c1bdc07afe4a57dbb9d51904 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 11 Jan 2024 19:26:49 +0100 Subject: [PATCH 219/760] note on timer --- embassy-nrf/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md index 18cb21f46..ae5256a2a 100644 --- a/embassy-nrf/README.md +++ b/embassy-nrf/README.md @@ -16,7 +16,9 @@ The `embassy-nrf` HAL supports most variants of the nRF family: * nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340)) * nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160)) -Most peripherals are supported. For a complete list of available peripherals and features, see the [documentation](https://docs.embassy.dev/embassy-nrf/git/nrf52805/index.html). +Most peripherals are supported. If the `time` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz. + +For a complete list of available peripherals and features, see the [documentation](https://docs.embassy.dev/embassy-nrf/git/nrf52805/index.html). ## API From 4caafe10aeb0b884a820f1e317f131b61e701e3c Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Thu, 11 Jan 2024 19:49:05 +0100 Subject: [PATCH 220/760] Expanded readme for crates release --- embassy-stm32/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 embassy-stm32/README.md diff --git a/embassy-stm32/README.md b/embassy-stm32/README.md new file mode 100644 index 000000000..b9b1f7820 --- /dev/null +++ b/embassy-stm32/README.md @@ -0,0 +1,28 @@ +# Embassy STM32 HAL + +The embassy-stm32 HAL aims to provide a safe, idiomatic hardware abstraction layer for all STM32 families. The HAL implements both blocking and async APIs for many peripherals. Where appropriate, traits from both blocking and asynchronous versions of [embedded-hal](https://docs.rs/embedded-hal/latest/embedded_hal/) v0.2 and v1.0 are implemented, as well as serial traits from embedded-io\[-async]. + +* [embassy-stm32 on crates.io](https://crates.io/crates/embassy-stm32) +* [Documentation](https://docs.embassy.dev/embassy-stm32/) (**Important:** use docs.embassy.dev rather than docs.rs to see the specific docs for the chip you’re using!) +* [Source](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) +* [Examples](https://github.com/embassy-rs/embassy/tree/main/examples) + +## embassy-stm32 supports all STM32 chip families + +STM32 microcontrollers come in many families and flavors, and supporting all of them is a big undertaking. Embassy takes advantage of the fact that the STM32 peripheral versions are shared across chip families. For example, instead of re-implementing the SPI peripheral for every STM32 chip family, embassy has a single SPI implementation that depends on code-generated register types that are identical for STM32 families with the same version of a given peripheral. + +In practice, this works as follows: + +1. You tell the compiler which chip you’re using with a feature flag +1. The stm32-metapac module generates register types for that chip at compile time, based on data from the stm32-data module +1. The embassy-stm32 HAL picks the correct implementation each peripheral based on automatically-generated feature flags, and applies any other tweaks which are required for the HAL to work on that chip + +Be aware that, while embassy-stm32 strives to consistently support all peripherals across all chips, this approach can lead to slightly different APIs and capabilities being available on different families. Check the [documentation](https://docs.embassy.dev/embassy-stm32/) for the specific chip you’re using to confirm exactly what’s available. + +## Minimum supported Rust version (MSRV) +Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. + +## embassy-time Timer Driver +If the `time` feature is enabled, embassy-stm32 provides a timer driver for use with [embassy-time](https://docs.embassy.dev/embassy-time/). You can pick which hardware timer is used for this internally via the `time-driver-*` features, or let embassy pick with `time-driver-any`. + +embassy-time has a default tick rate of 1MHz, which is fast enough to cause problems with the 16-bit timers currently supported by the embassy-stm32 time driver (specifically, if a critical section delays an IRQ by more than 32ms). To avoid this, it’s recommended to pick a lower tick rate. 32.768kHz is a reasonable default for many purposes. \ No newline at end of file From ccf61f50feba45c496de1c3dc49b58cad5b8f7a1 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Thu, 11 Jan 2024 19:55:15 +0100 Subject: [PATCH 221/760] Corrections from review --- embassy-stm32/README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/embassy-stm32/README.md b/embassy-stm32/README.md index b9b1f7820..7cce97d5e 100644 --- a/embassy-stm32/README.md +++ b/embassy-stm32/README.md @@ -19,10 +19,7 @@ In practice, this works as follows: Be aware that, while embassy-stm32 strives to consistently support all peripherals across all chips, this approach can lead to slightly different APIs and capabilities being available on different families. Check the [documentation](https://docs.embassy.dev/embassy-stm32/) for the specific chip you’re using to confirm exactly what’s available. -## Minimum supported Rust version (MSRV) -Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. - -## embassy-time Timer Driver +## embassy-time Time Driver If the `time` feature is enabled, embassy-stm32 provides a timer driver for use with [embassy-time](https://docs.embassy.dev/embassy-time/). You can pick which hardware timer is used for this internally via the `time-driver-*` features, or let embassy pick with `time-driver-any`. embassy-time has a default tick rate of 1MHz, which is fast enough to cause problems with the 16-bit timers currently supported by the embassy-stm32 time driver (specifically, if a critical section delays an IRQ by more than 32ms). To avoid this, it’s recommended to pick a lower tick rate. 32.768kHz is a reasonable default for many purposes. \ No newline at end of file From 1697386820993f7fc8ab39708a1b7349d9ed621e Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Thu, 11 Jan 2024 19:57:24 +0100 Subject: [PATCH 222/760] Correction from review --- embassy-stm32/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/README.md b/embassy-stm32/README.md index 7cce97d5e..23c1bf967 100644 --- a/embassy-stm32/README.md +++ b/embassy-stm32/README.md @@ -20,6 +20,6 @@ In practice, this works as follows: Be aware that, while embassy-stm32 strives to consistently support all peripherals across all chips, this approach can lead to slightly different APIs and capabilities being available on different families. Check the [documentation](https://docs.embassy.dev/embassy-stm32/) for the specific chip you’re using to confirm exactly what’s available. ## embassy-time Time Driver -If the `time` feature is enabled, embassy-stm32 provides a timer driver for use with [embassy-time](https://docs.embassy.dev/embassy-time/). You can pick which hardware timer is used for this internally via the `time-driver-*` features, or let embassy pick with `time-driver-any`. +If the `time` feature is enabled, embassy-stm32 provides a time driver for use with [embassy-time](https://docs.embassy.dev/embassy-time/). You can pick which hardware timer is used for this internally via the `time-driver-*` features, or let embassy pick with `time-driver-any`. embassy-time has a default tick rate of 1MHz, which is fast enough to cause problems with the 16-bit timers currently supported by the embassy-stm32 time driver (specifically, if a critical section delays an IRQ by more than 32ms). To avoid this, it’s recommended to pick a lower tick rate. 32.768kHz is a reasonable default for many purposes. \ No newline at end of file From 557399e2d6537ee64691e44f7a1f4a3e61e20490 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Thu, 11 Jan 2024 20:00:33 +0100 Subject: [PATCH 223/760] Included README.md in docs --- embassy-stm32/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 45a2ab63e..18871e83b 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(test), no_std)] #![allow(async_fn_in_trait)] +#![doc = include_str!("../README.md")] #![warn(missing_docs)] //! ## Feature flags From 9a269803bdaa29c9b36fd70d6651b4f2ea10b220 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 11 Jan 2024 20:32:07 +0100 Subject: [PATCH 224/760] restructure --- embassy-nrf/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md index ae5256a2a..59fb4f1bf 100644 --- a/embassy-nrf/README.md +++ b/embassy-nrf/README.md @@ -8,6 +8,8 @@ complete operations in low power mod and handling interrupts, so that applicatio NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use. +For a complete list of available peripherals and features, see the [embassy-nrf documentation](https://docs.embassy.dev/embassy-nrf). + ## Hardware support The `embassy-nrf` HAL supports most variants of the nRF family: @@ -16,9 +18,11 @@ The `embassy-nrf` HAL supports most variants of the nRF family: * nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340)) * nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160)) -Most peripherals are supported. If the `time` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz. +Most peripherals are supported. -For a complete list of available peripherals and features, see the [documentation](https://docs.embassy.dev/embassy-nrf/git/nrf52805/index.html). +## Time driver + +If the `time` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz. ## API From b161dd4b11d5aab145950e6ce41eae4d4378d25b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 11 Jan 2024 20:33:27 +0100 Subject: [PATCH 225/760] use secure mode --- examples/nrf9160/Cargo.toml | 2 +- examples/nrf9160/memory.x | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index b35b7778d..b6ee40a37 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/nrf9160/memory.x b/examples/nrf9160/memory.x index 4d1d77c00..4c7d4ebf0 100644 --- a/examples/nrf9160/memory.x +++ b/examples/nrf9160/memory.x @@ -1,7 +1,5 @@ MEMORY { - /* Assumes Secure Partition Manager (SPM) flashed at the start */ - SPM : ORIGIN = 0x00000000, LENGTH = 320K - FLASH : ORIGIN = 0x00050000, LENGTH = 704K + FLASH : ORIGIN = 0x00000000, LENGTH = 1024K RAM : ORIGIN = 0x20018000, LENGTH = 160K } From 4cc2648547491b13d3705b3869274d0f274a0721 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 11 Jan 2024 20:34:30 +0100 Subject: [PATCH 226/760] change title --- embassy-nrf/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md index 59fb4f1bf..87147fab4 100644 --- a/embassy-nrf/README.md +++ b/embassy-nrf/README.md @@ -24,7 +24,7 @@ Most peripherals are supported. If the `time` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz. -## API +## Embedded-hal The `embassy-nrf` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async). From 510b1ce4811f4d620a63148f9fa0fa6f96791b7b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 11 Jan 2024 20:36:43 +0100 Subject: [PATCH 227/760] add nrf9160 example to CI --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index ac0457679..6605d7fc4 100755 --- a/ci.sh +++ b/ci.sh @@ -147,6 +147,7 @@ cargo batch \ --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ + --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ From 10b857250c6de54ccab568d1f139e856773ef113 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 11 Jan 2024 20:45:45 +0100 Subject: [PATCH 228/760] trim nrf9160 example deps --- examples/nrf9160/Cargo.toml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index b6ee40a37..107b294d5 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,36 +5,16 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } -embedded-io = { version = "0.6.0", features = ["defmt-03"] } -embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } -embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } -embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" -fixed = "1.10.0" -static_cell = { version = "2" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } -rand = { version = "0.8.4", default-features = false } -embedded-storage = "0.3.1" -usbd-hid = "0.6.0" -serde = { version = "1.0.136", default-features = false } -embedded-hal = { version = "1.0" } -embedded-hal-async = { version = "1.0" } -embedded-hal-bus = { version = "0.1", features = ["async"] } -num-integer = { version = "0.1.45", default-features = false } -microfft = "0.5.0" [profile.release] debug = 2 From cf7da1c2bb4913c377633f004a5b3d8008a3c170 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 21:05:09 +0100 Subject: [PATCH 229/760] embassy-embedded-hal: add README. --- embassy-embedded-hal/README.md | 12 ++++++++++++ embassy-embedded-hal/src/lib.rs | 3 +-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 embassy-embedded-hal/README.md diff --git a/embassy-embedded-hal/README.md b/embassy-embedded-hal/README.md new file mode 100644 index 000000000..69581c788 --- /dev/null +++ b/embassy-embedded-hal/README.md @@ -0,0 +1,12 @@ +# embassy-embedded-hal + +Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy. + +- Shared SPI and I2C buses, both blocking and async, with a `SetConfig` trait allowing changing bus configuration (e.g. frequency) between devices on the same bus. +- Async utilities + - Adapters to convert from blocking to (fake) async. + - Adapters to insert yields on trait operations. +- Flash utilities + - Split a flash memory into smaller partitions. + - Concatenate flash memories together. + - Simulated in-memory flash. diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs index ee974324b..99a2d93c7 100644 --- a/embassy-embedded-hal/src/lib.rs +++ b/embassy-embedded-hal/src/lib.rs @@ -1,8 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(async_fn_in_trait)] #![warn(missing_docs)] - -//! Utilities to use `embedded-hal` traits with Embassy. +#![doc = include_str!("../README.md")] pub mod adapter; pub mod flash; From e18d6737212fe9a2a606cef210c64bf45ecc925c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 21:23:07 +0100 Subject: [PATCH 230/760] More readme fixes. --- embassy-nrf/README.md | 16 +++++++++++++--- embassy-rp/README.md | 24 +++++++++++++++++++++--- embassy-stm32/README.md | 19 ++++++++++++++++--- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md index 1ead96b2c..50662749d 100644 --- a/embassy-nrf/README.md +++ b/embassy-nrf/README.md @@ -4,7 +4,7 @@ HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so ra The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The HAL implements both blocking and async APIs for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to -complete operations in low power mod and handling interrupts, so that applications can focus on more important matters. +complete operations in low power mode and handling interrupts, so that applications can focus on more important matters. NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use. @@ -18,16 +18,26 @@ The `embassy-nrf` HAL supports most variants of the nRF family: * nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340)) * nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160)) -Most peripherals are supported. +Most peripherals are supported. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf). + +For MCUs with TrustZone support, both Secure (S) and Non-Secure (NS) modes are supported. Running in Secure mode +allows running Rust code without a SPM or TF-M binary, saving flash space and simplifying development. ## Time driver -If the `time` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz. +If the `time-driver-rtc1` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz. ## Embedded-hal The `embassy-nrf` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async). +## Interoperability + +This crate can run on any executor. + +Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time` feature. If you enable it, +you must link an `embassy-time` driver in your project. + ## EasyDMA considerations On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting diff --git a/embassy-rp/README.md b/embassy-rp/README.md index 1d14eca52..8cf7da994 100644 --- a/embassy-rp/README.md +++ b/embassy-rp/README.md @@ -2,8 +2,26 @@ HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. -The Embassy RP HAL targets the Raspberry Pi 2040 family of hardware. The HAL implements both blocking and async APIs +The embassy-rp HAL targets the Raspberry Pi RP2040 microcontroller. The HAL implements both blocking and async APIs for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to -complete operations in low power mod and handling interrupts, so that applications can focus on more important matters. +complete operations in low power mode and handling interrupts, so that applications can focus on more important matters. -NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use. +* [embassy-rp on crates.io](https://crates.io/crates/embassy-rp) +* [Documentation](https://docs.embassy.dev/embassy-rp/) +* [Source](https://github.com/embassy-rs/embassy/tree/main/embassy-rp) +* [Examples](https://github.com/embassy-rs/embassy/tree/main/examples/rp/src/bin) + +## `embassy-time` time driver + +If the `time-driver` feature is enabled, the HAL uses the TIMER peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 1MHz. + +## Embedded-hal + +The `embassy-rp` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async). + +## Interoperability + +This crate can run on any executor. + +Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time` feature. If you enable it, +you must link an `embassy-time` driver in your project. diff --git a/embassy-stm32/README.md b/embassy-stm32/README.md index 23c1bf967..e9ae455a4 100644 --- a/embassy-stm32/README.md +++ b/embassy-stm32/README.md @@ -19,7 +19,20 @@ In practice, this works as follows: Be aware that, while embassy-stm32 strives to consistently support all peripherals across all chips, this approach can lead to slightly different APIs and capabilities being available on different families. Check the [documentation](https://docs.embassy.dev/embassy-stm32/) for the specific chip you’re using to confirm exactly what’s available. -## embassy-time Time Driver -If the `time` feature is enabled, embassy-stm32 provides a time driver for use with [embassy-time](https://docs.embassy.dev/embassy-time/). You can pick which hardware timer is used for this internally via the `time-driver-*` features, or let embassy pick with `time-driver-any`. +## Embedded-hal -embassy-time has a default tick rate of 1MHz, which is fast enough to cause problems with the 16-bit timers currently supported by the embassy-stm32 time driver (specifically, if a critical section delays an IRQ by more than 32ms). To avoid this, it’s recommended to pick a lower tick rate. 32.768kHz is a reasonable default for many purposes. \ No newline at end of file +The `embassy-stm32` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async). + +## `embassy-time` time driver +If a `time-driver-*` feature is enabled, embassy-stm32 provides a time driver for use with [embassy-time](https://docs.embassy.dev/embassy-time/). You can pick which hardware timer is used for this internally via the `time-driver-tim*` features, or let embassy pick with `time-driver-any`. + +embassy-time has a default tick rate of 1MHz, which is fast enough to cause problems with the 16-bit timers currently supported by the embassy-stm32 time driver (specifically, if a critical section delays an IRQ by more than 32ms). To avoid this, it’s recommended to pick a lower tick rate. 32.768kHz is a reasonable default for many purposes. + +## Interoperability + +This crate can run on any executor. + +Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time` feature. If you enable it, +you must link an `embassy-time` driver in your project. + +The `low-power` feature integrates specifically with `embassy-executor`, it can't be ued on other executors for now. From 75835f4c742a21d01cdeef8d0e7ca1c53e418105 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 21:57:35 +0100 Subject: [PATCH 231/760] Use released embedded-hal-mock. --- embassy-net-adin1110/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 52b89fce9..ad7fd819e 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -21,7 +21,7 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" [dev-dependencies] -embedded-hal-mock = { git = "https://github.com/Dirbaio/embedded-hal-mock", rev = "e3c820094ea0fc71449916bd790d0e3d76f4c0e4", features = ["embedded-hal-async", "eh1"] } +embedded-hal-mock = { version = "0.10.0", features = ["embedded-hal-async", "eh1"] } crc = "3.0.1" env_logger = "0.10" critical-section = { version = "1.1.2", features = ["std"] } From b3ab2d91f7ed48e6a377661e7e504cb0ae0091a3 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 22:05:01 +0100 Subject: [PATCH 232/760] stm32: use released metapac. --- embassy-stm32/Cargo.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 60fc86135..452b0a84f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,8 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-656ecf6714fa34fdfb3b3e2f2cd034bffed3f303" } +stm32-metapac = { version = "15" } +#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-656ecf6714fa34fdfb3b3e2f2cd034bffed3f303" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -76,7 +77,8 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-656ecf6714fa34fdfb3b3e2f2cd034bffed3f303", default-features = false, features = ["metadata"]} +stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} +#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-656ecf6714fa34fdfb3b3e2f2cd034bffed3f303", default-features = false, features = ["metadata"]} [features] From f0606da9adc8032cc92c06c0661b385742459fc8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 22:47:05 +0100 Subject: [PATCH 233/760] time: split queue driver too, don't reexport drivers. --- embassy-executor/Cargo.toml | 9 ++-- embassy-executor/src/raw/mod.rs | 27 +++++----- embassy-executor/src/raw/timer_queue.rs | 12 ++--- embassy-time-driver/CHANGELOG.md | 51 ------------------- embassy-time-queue-driver/Cargo.toml | 25 +++++++++ embassy-time-queue-driver/README.md | 8 +++ embassy-time-queue-driver/build.rs | 1 + .../src/lib.rs | 42 +++++++-------- embassy-time/Cargo.toml | 1 + embassy-time/src/driver_mock.rs | 4 +- embassy-time/src/driver_std.rs | 5 +- embassy-time/src/driver_wasm.rs | 5 +- embassy-time/src/instant.rs | 6 ++- embassy-time/src/lib.rs | 5 +- embassy-time/src/queue_generic.rs | 10 ++-- embassy-time/src/timer.rs | 16 ++---- examples/std/src/bin/serial.rs | 1 + 17 files changed, 100 insertions(+), 128 deletions(-) delete mode 100644 embassy-time-driver/CHANGELOG.md create mode 100644 embassy-time-queue-driver/Cargo.toml create mode 100644 embassy-time-queue-driver/README.md create mode 100644 embassy-time-queue-driver/build.rs rename embassy-time/src/queue.rs => embassy-time-queue-driver/src/lib.rs (51%) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index c71452398..da3c9a4fc 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -33,7 +33,8 @@ log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" } -embassy-time = { version = "0.2", path = "../embassy-time", optional = true} +embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } +embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" document-features = "0.2.7" @@ -63,8 +64,8 @@ nightly = ["embassy-executor-macros/nightly"] # See: https://github.com/embassy-rs/embassy/pull/1263 turbowakers = [] -## Use timers from `embassy-time` -integrated-timers = ["dep:embassy-time"] +## Use the executor-integrated `embassy-time` timer queue. +integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"] #! ### Architecture _arch = [] # some arch was picked @@ -177,4 +178,4 @@ task-arena-size-1048576 = [] # END AUTOGENERATED CONFIG FEATURES -#! \ No newline at end of file +#! diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index b16a1c7c3..3f00be4a8 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -30,9 +30,7 @@ use core::ptr::NonNull; use core::task::{Context, Poll}; #[cfg(feature = "integrated-timers")] -use embassy_time::driver::{self, AlarmHandle}; -#[cfg(feature = "integrated-timers")] -use embassy_time::Instant; +use embassy_time_driver::{self, AlarmHandle}; #[cfg(feature = "rtos-trace")] use rtos_trace::trace; @@ -50,7 +48,7 @@ pub(crate) struct TaskHeader { poll_fn: SyncUnsafeCell>, #[cfg(feature = "integrated-timers")] - pub(crate) expires_at: SyncUnsafeCell, + pub(crate) expires_at: SyncUnsafeCell, #[cfg(feature = "integrated-timers")] pub(crate) timer_queue_item: timer_queue::TimerQueueItem, } @@ -123,7 +121,7 @@ impl TaskStorage { poll_fn: SyncUnsafeCell::new(None), #[cfg(feature = "integrated-timers")] - expires_at: SyncUnsafeCell::new(Instant::from_ticks(0)), + expires_at: SyncUnsafeCell::new(0), #[cfg(feature = "integrated-timers")] timer_queue_item: timer_queue::TimerQueueItem::new(), }, @@ -164,7 +162,7 @@ impl TaskStorage { this.raw.state.despawn(); #[cfg(feature = "integrated-timers")] - this.raw.expires_at.set(Instant::MAX); + this.raw.expires_at.set(u64::MAX); } Poll::Pending => {} } @@ -328,7 +326,7 @@ pub(crate) struct SyncExecutor { impl SyncExecutor { pub(crate) fn new(pender: Pender) -> Self { #[cfg(feature = "integrated-timers")] - let alarm = unsafe { unwrap!(driver::allocate_alarm()) }; + let alarm = unsafe { unwrap!(embassy_time_driver::allocate_alarm()) }; Self { run_queue: RunQueue::new(), @@ -377,18 +375,19 @@ impl SyncExecutor { /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. pub(crate) unsafe fn poll(&'static self) { #[cfg(feature = "integrated-timers")] - driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); + embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); #[allow(clippy::never_loop)] loop { #[cfg(feature = "integrated-timers")] - self.timer_queue.dequeue_expired(Instant::now(), wake_task_no_pend); + self.timer_queue + .dequeue_expired(embassy_time_driver::now(), wake_task_no_pend); self.run_queue.dequeue_all(|p| { let task = p.header(); #[cfg(feature = "integrated-timers")] - task.expires_at.set(Instant::MAX); + task.expires_at.set(u64::MAX); if !task.state.run_dequeue() { // If task is not running, ignore it. This can happen in the following scenario: @@ -418,7 +417,7 @@ impl SyncExecutor { // If this is already in the past, set_alarm might return false // In that case do another poll loop iteration. let next_expiration = self.timer_queue.next_expiration(); - if driver::set_alarm(self.alarm, next_expiration.as_ticks()) { + if embassy_time_driver::set_alarm(self.alarm, next_expiration) { break; } } @@ -568,8 +567,8 @@ pub fn wake_task_no_pend(task: TaskRef) { struct TimerQueue; #[cfg(feature = "integrated-timers")] -impl embassy_time::queue::TimerQueue for TimerQueue { - fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) { +impl embassy_time_queue_driver::TimerQueue for TimerQueue { + fn schedule_wake(&'static self, at: u64, waker: &core::task::Waker) { let task = waker::task_from_waker(waker); let task = task.header(); unsafe { @@ -580,7 +579,7 @@ impl embassy_time::queue::TimerQueue for TimerQueue { } #[cfg(feature = "integrated-timers")] -embassy_time::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); +embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); #[cfg(feature = "rtos-trace")] impl rtos_trace::RtosTraceOSCallbacks for Executor { diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index 59a3b43f5..94a5f340b 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -1,7 +1,5 @@ use core::cmp::min; -use embassy_time::Instant; - use super::TaskRef; use crate::raw::util::SyncUnsafeCell; @@ -30,7 +28,7 @@ impl TimerQueue { pub(crate) unsafe fn update(&self, p: TaskRef) { let task = p.header(); - if task.expires_at.get() != Instant::MAX { + if task.expires_at.get() != u64::MAX { if task.state.timer_enqueue() { task.timer_queue_item.next.set(self.head.get()); self.head.set(Some(p)); @@ -38,18 +36,18 @@ impl TimerQueue { } } - pub(crate) unsafe fn next_expiration(&self) -> Instant { - let mut res = Instant::MAX; + pub(crate) unsafe fn next_expiration(&self) -> u64 { + let mut res = u64::MAX; self.retain(|p| { let task = p.header(); let expires = task.expires_at.get(); res = min(res, expires); - expires != Instant::MAX + expires != u64::MAX }); res } - pub(crate) unsafe fn dequeue_expired(&self, now: Instant, on_task: impl Fn(TaskRef)) { + pub(crate) unsafe fn dequeue_expired(&self, now: u64, on_task: impl Fn(TaskRef)) { self.retain(|p| { let task = p.header(); if task.expires_at.get() <= now { diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md deleted file mode 100644 index d8c0c7d08..000000000 --- a/embassy-time-driver/CHANGELOG.md +++ /dev/null @@ -1,51 +0,0 @@ -# Changelog - -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). - -## 0.2.0 - 2023-12-04 - -- Added tick rates in multiples of 10 kHz -- Remove nightly and unstable-traits features in preparation for 1.75. -- Update heapless to 0.8. - -## 0.1.5 - 2023-10-16 - -- Added `links` key to Cargo.toml, to prevent multiple copies of this crate in the same binary. - Needed because different copies might get different tick rates, causing - wrong delays if the time driver is using one copy and user code is using another. - This is especially common when mixing crates from crates.io and git. - -## 0.1.4 - 2023-10-12 - -- Added more tick rates - -## 0.1.3 - 2023-08-28 - -- Update `embedded-hal-async` to `1.0.0-rc.2` -- Update `embedded-hal v1` to `1.0.0-rc.2` - -## 0.1.2 - 2023-07-05 - -- Update `embedded-hal-async` to `0.2.0-alpha.2`. -- Update `embedded-hal v1` to `1.0.0-alpha.11`. (Note: v0.2 support is kept unchanged). - -## 0.1.1 - 2023-04-13 - -- Update `embedded-hal-async` to `0.2.0-alpha.1` (uses `async fn` in traits). -- Update `embedded-hal v1` to `1.0.0-alpha.10`. (Note: v0.2 support is kept unchanged). -- Remove dep on `embassy-sync`. -- Fix reentrancy issues in the `std` time driver (#1177) -- Add `Duration::from_hz()`. -- impl `From` conversions to/from `core::time::Duration`. -- Add `#[must_use]` to all futures. -- Add inherent `async fn tick()` to `Ticker`, so you can use it directly without the `Stream` trait. -- Add more tick rates. -- impl `Default` for `Signal` -- Remove unnecessary uses of `atomic-polyfill` - -## 0.1.0 - 2022-08-26 - -- First release diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml new file mode 100644 index 000000000..85ee1da1b --- /dev/null +++ b/embassy-time-queue-driver/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "embassy-time-queue-driver" +version = "0.1.0" +edition = "2021" +description = "Timer queue driver trait for embassy-time" +repository = "https://github.com/embassy-rs/embassy" +readme = "README.md" +license = "MIT OR Apache-2.0" +categories = [ + "embedded", + "no-std", + "concurrency", + "asynchronous", +] + +# Prevent multiple copies of this crate in the same binary. +# Needed because different copies might get different tick rates, causing +# wrong delays if the time driver is using one copy and user code is using another. +# This is especially common when mixing crates from crates.io and git. +links = "embassy-time-queue" + +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-driver/src/" +target = "x86_64-unknown-linux-gnu" diff --git a/embassy-time-queue-driver/README.md b/embassy-time-queue-driver/README.md new file mode 100644 index 000000000..8852b0358 --- /dev/null +++ b/embassy-time-queue-driver/README.md @@ -0,0 +1,8 @@ +# embassy-time-queue-driver + +This crate contains the driver trait used by the [`embassy-time`](https://crates.io/crates/embassy-time) timer queue. + +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 +another in `embassy-executor` enabled by the `integrated-timers` feature. diff --git a/embassy-time-queue-driver/build.rs b/embassy-time-queue-driver/build.rs new file mode 100644 index 000000000..f328e4d9d --- /dev/null +++ b/embassy-time-queue-driver/build.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/embassy-time/src/queue.rs b/embassy-time-queue-driver/src/lib.rs similarity index 51% rename from embassy-time/src/queue.rs rename to embassy-time-queue-driver/src/lib.rs index d65197c54..50736e8c7 100644 --- a/embassy-time/src/queue.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -1,20 +1,14 @@ -//! Timer queue implementation -//! -//! This module defines the interface a timer queue needs to implement to power the `embassy_time` module. -//! -//! # Implementing a timer queue +#![no_std] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] + +//! ## Implementing a timer queue //! //! - Define a struct `MyTimerQueue` //! - Implement [`TimerQueue`] for it //! - Register it as the global timer queue with [`timer_queue_impl`](crate::timer_queue_impl). //! -//! # Linkage details -//! -//! Check the documentation of the [`driver`](crate::driver) module for more information. -//! -//! Similarly to driver, if there is none or multiple timer queues in the crate tree, linking will fail. -//! -//! # Example +//! ## Example //! //! ``` //! use core::task::Waker; @@ -25,23 +19,29 @@ //! struct MyTimerQueue{}; // not public! //! //! impl TimerQueue for MyTimerQueue { -//! fn schedule_wake(&'static self, at: Instant, waker: &Waker) { +//! fn schedule_wake(&'static self, at: u64, waker: &Waker) { //! todo!() //! } //! } -//! ``` -//! ```ignore -//! embassy_time::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); +//! +//! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); //! ``` use core::task::Waker; -use crate::Instant; - /// Timer queue pub trait TimerQueue { /// Schedules a waker in the queue to be awoken at moment `at`. /// If this moment is in the past, the waker might be awoken immediately. - fn schedule_wake(&'static self, at: Instant, waker: &Waker); + fn schedule_wake(&'static self, at: u64, waker: &Waker); +} + +extern "Rust" { + fn _embassy_time_schedule_wake(at: u64, waker: &Waker); +} + +/// Schedule the given waker to be woken at `at`. +pub fn schedule_wake(at: u64, waker: &Waker) { + unsafe { _embassy_time_schedule_wake(at, waker) } } /// Set the TimerQueue implementation. @@ -53,8 +53,8 @@ macro_rules! timer_queue_impl { static $name: $t = $val; #[no_mangle] - fn _embassy_time_schedule_wake(at: $crate::Instant, waker: &core::task::Waker) { - <$t as $crate::queue::TimerQueue>::schedule_wake(&$name, at, waker); + fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) { + <$t as $crate::TimerQueue>::schedule_wake(&$name, at, waker); } }; } diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 729a2bd4f..f27de8ab4 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -398,6 +398,7 @@ tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"] [dependencies] embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } +embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver" } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index 7abc2bd70..8587f9172 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -1,8 +1,8 @@ use core::cell::RefCell; use critical_section::Mutex as CsMutex; +use embassy_time_driver::{AlarmHandle, Driver}; -use crate::driver::{AlarmHandle, Driver}; use crate::{Duration, Instant}; /// A mock driver that can be manually advanced. @@ -28,7 +28,7 @@ use crate::{Duration, Instant}; /// ``` pub struct MockDriver(CsMutex>); -crate::driver::time_driver_impl!(static DRIVER: MockDriver = MockDriver::new()); +embassy_time_driver::time_driver_impl!(static DRIVER: MockDriver = MockDriver::new()); impl MockDriver { /// Creates a new mock driver. diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index 3b5524f9e..d182f8331 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs @@ -6,8 +6,7 @@ use std::time::{Duration as StdDuration, Instant as StdInstant}; use std::{mem, ptr, thread}; use critical_section::Mutex as CsMutex; - -use crate::driver::{AlarmHandle, Driver}; +use embassy_time_driver::{AlarmHandle, Driver}; const ALARM_COUNT: usize = 4; @@ -45,7 +44,7 @@ struct TimeDriver { } const ALARM_NEW: AlarmState = AlarmState::new(); -crate::driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { +embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { alarm_count: AtomicU8::new(0), once: Once::new(), diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs index d75856c26..ad884f060 100644 --- a/embassy-time/src/driver_wasm.rs +++ b/embassy-time/src/driver_wasm.rs @@ -4,11 +4,10 @@ use std::mem::MaybeUninit; use std::ptr; use std::sync::{Mutex, Once}; +use embassy_time_driver::{AlarmHandle, Driver}; use wasm_bindgen::prelude::*; use wasm_timer::Instant as StdInstant; -use crate::driver::{AlarmHandle, Driver}; - const ALARM_COUNT: usize = 4; struct AlarmState { @@ -42,7 +41,7 @@ struct TimeDriver { } const ALARM_NEW: AlarmState = AlarmState::new(); -crate::driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { +embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { alarm_count: AtomicU8::new(0), once: Once::new(), alarms: UninitCell::uninit(), diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index 5571cdd15..909f1b173 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -1,7 +1,7 @@ use core::fmt; use core::ops::{Add, AddAssign, Sub, SubAssign}; -use super::{driver, Duration, GCD_1K, GCD_1M, TICK_HZ}; +use super::{Duration, GCD_1K, GCD_1M, TICK_HZ}; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -18,7 +18,9 @@ impl Instant { /// Returns an Instant representing the current time. pub fn now() -> Instant { - Instant { ticks: driver::now() } + Instant { + ticks: embassy_time_driver::now(), + } } /// Create an Instant from a tick count since system boot. diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index 3f8c09f1a..d27eb92f6 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -10,12 +10,9 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; -pub use embassy_time_driver as driver; - mod delay; mod duration; mod instant; -pub mod queue; mod timer; #[cfg(feature = "mock-driver")] @@ -32,8 +29,8 @@ mod driver_wasm; mod queue_generic; pub use delay::{block_for, Delay}; -pub use driver::TICK_HZ; pub use duration::Duration; +pub use embassy_time_driver::TICK_HZ; pub use instant::Instant; pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs index 829368ffc..cf7a986d5 100644 --- a/embassy-time/src/queue_generic.rs +++ b/embassy-time/src/queue_generic.rs @@ -3,10 +3,10 @@ use core::cmp::{min, Ordering}; use core::task::Waker; use critical_section::Mutex; +use embassy_time_driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle}; +use embassy_time_queue_driver::TimerQueue; use heapless::Vec; -use crate::driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle}; -use crate::queue::TimerQueue; use crate::Instant; #[cfg(feature = "generic-queue-8")] @@ -167,12 +167,12 @@ impl Queue { } impl TimerQueue for Queue { - fn schedule_wake(&'static self, at: Instant, waker: &Waker) { - Queue::schedule_wake(self, at, waker); + fn schedule_wake(&'static self, at: u64, waker: &Waker) { + Queue::schedule_wake(self, Instant::from_ticks(at), waker); } } -crate::timer_queue_impl!(static QUEUE: Queue = Queue::new()); +embassy_time_queue_driver::timer_queue_impl!(static QUEUE: Queue = Queue::new()); #[cfg(test)] #[cfg(feature = "mock-driver")] diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 2705ba03f..565a65cb8 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -1,6 +1,6 @@ use core::future::{poll_fn, Future}; use core::pin::Pin; -use core::task::{Context, Poll, Waker}; +use core::task::{Context, Poll}; use futures_util::future::{select, Either}; use futures_util::stream::FusedStream; @@ -116,7 +116,7 @@ impl Future for Timer { if self.yielded_once && self.expires_at <= Instant::now() { Poll::Ready(()) } else { - schedule_wake(self.expires_at, cx.waker()); + embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); self.yielded_once = true; Poll::Pending } @@ -185,7 +185,7 @@ impl Ticker { self.expires_at += dur; Poll::Ready(()) } else { - schedule_wake(self.expires_at, cx.waker()); + embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); Poll::Pending } }) @@ -202,7 +202,7 @@ impl Stream for Ticker { self.expires_at += dur; Poll::Ready(Some(())) } else { - schedule_wake(self.expires_at, cx.waker()); + embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); Poll::Pending } } @@ -214,11 +214,3 @@ impl FusedStream for Ticker { false } } - -extern "Rust" { - fn _embassy_time_schedule_wake(at: Instant, waker: &Waker); -} - -fn schedule_wake(at: Instant, waker: &Waker) { - unsafe { _embassy_time_schedule_wake(at, waker) } -} diff --git a/examples/std/src/bin/serial.rs b/examples/std/src/bin/serial.rs index 435089aad..10c85511d 100644 --- a/examples/std/src/bin/serial.rs +++ b/examples/std/src/bin/serial.rs @@ -3,6 +3,7 @@ mod serial_port; use async_io::Async; use embassy_executor::Executor; +use embassy_time as _; use embedded_io_async::Read; use log::*; use nix::sys::termios; From 22197320ff5dcef6cdc692a4c556ea9eae270074 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 22:57:29 +0100 Subject: [PATCH 234/760] bump embassy-time 0.3, embassy-executor 0.5, embassy-net 0.4. --- cyw43/Cargo.toml | 2 +- docs/modules/ROOT/examples/basic/Cargo.toml | 4 ++-- .../ROOT/examples/layer-by-layer/blinky-async/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- embassy-executor/CHANGELOG.md | 4 ++++ embassy-executor/Cargo.toml | 2 +- embassy-net-adin1110/Cargo.toml | 2 +- embassy-net-enc28j60/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- embassy-net/CHANGELOG.md | 4 ++++ embassy-net/Cargo.toml | 4 ++-- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 4 ++-- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 4 ++-- embassy-time-driver/Cargo.toml | 2 +- embassy-time/CHANGELOG.md | 6 ++++++ embassy-time/Cargo.toml | 4 ++-- embassy-usb-dfu/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 4 ++-- examples/boot/application/rp/Cargo.toml | 4 ++-- examples/boot/application/stm32f3/Cargo.toml | 4 ++-- examples/boot/application/stm32f7/Cargo.toml | 4 ++-- examples/boot/application/stm32h7/Cargo.toml | 4 ++-- examples/boot/application/stm32l0/Cargo.toml | 4 ++-- examples/boot/application/stm32l1/Cargo.toml | 4 ++-- examples/boot/application/stm32l4/Cargo.toml | 4 ++-- examples/boot/application/stm32wb-dfu/Cargo.toml | 4 ++-- examples/boot/application/stm32wl/Cargo.toml | 4 ++-- examples/nrf-rtos-trace/Cargo.toml | 4 ++-- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 6 +++--- examples/nrf5340/Cargo.toml | 6 +++--- examples/nrf9160/Cargo.toml | 4 ++-- examples/rp/Cargo.toml | 6 +++--- examples/std/Cargo.toml | 6 +++--- examples/stm32c0/Cargo.toml | 4 ++-- examples/stm32f0/Cargo.toml | 4 ++-- examples/stm32f1/Cargo.toml | 4 ++-- examples/stm32f2/Cargo.toml | 4 ++-- examples/stm32f3/Cargo.toml | 4 ++-- examples/stm32f334/Cargo.toml | 4 ++-- examples/stm32f4/Cargo.toml | 6 +++--- examples/stm32f7/Cargo.toml | 6 +++--- examples/stm32g0/Cargo.toml | 4 ++-- examples/stm32g4/Cargo.toml | 4 ++-- examples/stm32h5/Cargo.toml | 6 +++--- examples/stm32h7/Cargo.toml | 6 +++--- examples/stm32l0/Cargo.toml | 4 ++-- examples/stm32l1/Cargo.toml | 4 ++-- examples/stm32l4/Cargo.toml | 6 +++--- examples/stm32l5/Cargo.toml | 6 +++--- examples/stm32u5/Cargo.toml | 4 ++-- examples/stm32wb/Cargo.toml | 6 +++--- examples/stm32wba/Cargo.toml | 6 +++--- examples/stm32wl/Cargo.toml | 4 ++-- examples/wasm/Cargo.toml | 4 ++-- tests/nrf/Cargo.toml | 6 +++--- tests/perf-client/Cargo.toml | 4 ++-- tests/riscv32/Cargo.toml | 4 ++-- tests/rp/Cargo.toml | 6 +++--- tests/stm32/Cargo.toml | 6 +++--- 64 files changed, 137 insertions(+), 123 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 1042f21bc..ac3122d41 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -11,7 +11,7 @@ log = ["dep:log"] firmware-logs = [] [dependencies] -embassy-time = { version = "0.2", path = "../embassy-time"} +embassy-time = { version = "0.3.0", path = "../embassy-time"} embassy-sync = { version = "0.5.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} diff --git a/docs/modules/ROOT/examples/basic/Cargo.toml b/docs/modules/ROOT/examples/basic/Cargo.toml index 8f6e05fae..2c282145d 100644 --- a/docs/modules/ROOT/examples/basic/Cargo.toml +++ b/docs/modules/ROOT/examples/basic/Cargo.toml @@ -6,8 +6,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.4.0", path = "../../../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.2.0", path = "../../../../../embassy-time", features = ["defmt"] } +embassy-executor = { version = "0.5.0", path = "../../../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.3.0", path = "../../../../../embassy-time", features = ["defmt"] } embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } defmt = "0.3" diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml index 2d47dccf4..64f7e8403 100644 --- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" cortex-m = "0.7" cortex-m-rt = "0.7" embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } -embassy-executor = { version = "0.4.0", features = ["arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.5.0", features = ["arch-cortex-m", "executor-thread"] } defmt = "0.3.0" defmt-rtt = "0.3.0" diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index dacb27747..ceb14445c 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.1.0", path = "../embassy-boot" } -embassy-time = { version = "0.2.0", path = "../embassy-time" } +embassy-time = { version = "0.3.0", path = "../embassy-time" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 42382f834..4c3d677be 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -19,7 +19,7 @@ default = ["time"] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } -embassy-time = { version = "0.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", ] } diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 5c6749230..77c64fd8e 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.5.0 - 2024-01-11 + +- Updated to `embassy-time-driver 0.1`, `embassy-time-queue-driver 0.1`, compatible with `embassy-time v0.3` and higher. + ## 0.4.0 - 2023-12-05 - Removed `arch-xtensa`. Use the executor provided by the HAL crate (`esp-hal`, `esp32s3-hal`, etc...) instead. diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index da3c9a4fc..2ef3f5294 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor" -version = "0.4.0" +version = "0.5.0" edition = "2021" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index ad7fd819e..9b298beb9 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -16,7 +16,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.2", path = "../embassy-time" } +embassy-time = { version = "0.3.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index 6d18f708e..9cfb30e3f 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.2", path = "../embassy-time" } +embassy-time = { version = "0.3.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 1b022de40..ff7c43023 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-time = { version = "0.2", path = "../embassy-time" } +embassy-time = { version = "0.3.0", path = "../embassy-time" } embassy-sync = { version = "0.5.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 6ed308596..8157bf115 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/embassy-rs/embassy" embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.2", path = "../embassy-time" } +embassy-time = { version = "0.3.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md index cc763b74c..56e245b92 100644 --- a/embassy-net/CHANGELOG.md +++ b/embassy-net/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.4 - 2024-01-11 + +- Update to `embassy-time` v0.3. + ## 0.3 - 2024-01-04 - Added `ReadReady` and `WriteReady` impls on `TcpSocket`. diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 864956616..ffa4a64b6 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net" -version = "0.3.0" +version = "0.4.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Async TCP/IP network stack for embedded systems" @@ -69,7 +69,7 @@ smoltcp = { version = "0.11.0", default-features = false, features = [ ] } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.2", path = "../embassy-time" } +embassy-time = { version = "0.3.0", path = "../embassy-time" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embedded-io-async = { version = "0.6.1" } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index f62059eb1..0be514e79 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -111,7 +111,7 @@ _nrf52832_anomaly_109 = [] [dependencies] embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } -embassy-time = { version = "0.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index b324eab82..2cc62e314 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -68,7 +68,7 @@ boot2-w25x10cl = [] [dependencies] embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } -embassy-time = { version = "0.2", path = "../embassy-time" } +embassy-time = { version = "0.3.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } @@ -103,5 +103,5 @@ rp2040-boot2 = "0.3" document-features = "0.2.7" [dev-dependencies] -embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } +embassy-executor = { version = "0.5.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 1780688cd..1f699141f 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -13,7 +13,7 @@ features = ["stm32wb55rg"] [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } -embassy-time = { version = "0.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 452b0a84f..171b1d477 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -33,14 +33,14 @@ flavors = [ [dependencies] embassy-sync = { version = "0.5.0", path = "../embassy-sync" } -embassy-time = { version = "0.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } -embassy-executor = { version = "0.4.0", path = "../embassy-executor", optional = true } +embassy-executor = { version = "0.5.0", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index 2ed250d4d..c6c23f698 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml @@ -388,4 +388,4 @@ wasm-timer = { version = "0.2.5", optional = true } [dev-dependencies] serial_test = "0.9" critical-section = { version = "1.1", features = ["std"] } -embassy-executor = { version = "0.4.0", path = "../embassy-executor" } +embassy-executor = { version = "0.5.0", path = "../embassy-executor" } diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index d8c0c7d08..df093949f 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -5,6 +5,12 @@ 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). +## 0.3.0 - 2024-01-11 + +- Update `embedded-hal-async` to `1.0.0` +- Update `embedded-hal v1` to `1.0.0` +- Split the time driver to a separate `embassy-time-driver` crate. + ## 0.2.0 - 2023-12-04 - Added tick rates in multiples of 10 kHz diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index f27de8ab4..6b1c7cc58 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-time" -version = "0.2.0" +version = "0.3.0" edition = "2021" description = "Instant and Duration for embedded no-std systems, with async timer support" repository = "https://github.com/embassy-rs/embassy" @@ -422,4 +422,4 @@ wasm-timer = { version = "0.2.5", optional = true } [dev-dependencies] serial_test = "0.9" critical-section = { version = "1.1", features = ["std"] } -embassy-executor = { version = "0.4.0", path = "../embassy-executor" } +embassy-executor = { version = "0.5.0", path = "../embassy-executor" } diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 2d8895123..6087bcd7d 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -21,7 +21,7 @@ embassy-boot = { version = "0.1.1", path = "../embassy-boot" } # embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } -embassy-time = { version = "0.2.0", path = "../embassy-time" } +embassy-time = { version = "0.3.0", path = "../embassy-time" } embassy-usb = { version = "0.1.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 7b62d9a20..2534cad69 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot-nrf", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index ccaa9f8ef..56362cb7e 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index f4bc285bf..4a4d091f6 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32" } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 575220ade..00e283cf4 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 12c34565a..4af9357e8 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 9f705dc26..20e6a71e8 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 7ba5f143b..b4b33fa4a 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 08cb87e0b..92cdeb450 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 58bba66d7..80fd08bb6 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 7ce560de2..b2a744d0d 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index bfbec028a..17210994b 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -16,8 +16,8 @@ log = [ [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time" } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time" } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index f5d49f0a1..d91f58d0e 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -9,7 +9,7 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 933e8d59e..abb995be6 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index fc225eee6..56b9c8018 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 107b294d5..af2385960 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 07f2ae1c7..a3714289f 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +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.3", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "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" } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 969c3d36a..f05565e84 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "std", ] } -embassy-net = { version = "0.3", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["log", "std", ] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 0fd3939c6..7a3e03b75 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +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" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 9fdc4798a..71b0eb683 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -15,8 +15,8 @@ defmt = "0.3" defmt-rtt = "0.4" panic-probe = "0.3" embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index c933a4368..df5d32f70 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +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"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index eaaadeec5..4cbf1dc84 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +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" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index d5ab0b25a..64bb2e560 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index b29a08e7c..3e5a7cc8c 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 838bb5291..cd46fc85b 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,10 +8,10 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 4b22069a0..941ba38cd 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0" # Change stm32f767zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 7ad36952f..6ce3418e5 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +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"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 987f23b3a..895ad3e7c 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +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"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.6.0" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index a636c0a33..c9f08d24e 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 041408b9a..d9ea2626d 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 739aa6cb1..dd9097c9b 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +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" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 071d6a502..c0b35b716 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +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"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } defmt = "0.3" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index e434f3bd9..d42e69578 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,12 +8,12 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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", ] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index ce71cc310..0c6beb72c 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,10 +8,10 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.6.0" diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 5a8a3eaac..03294339d 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32u585ai to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 8dce89abf..94a5141f5 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,9 +9,9 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 48455b760..47279a012 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 20ffe6099..4cb55930b 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "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"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } defmt = "0.3" diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 305ebd526..3d2300b59 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -9,8 +9,8 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "wasm", ] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" wasm-bindgen = "0.2" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 8ef51fcdb..84ca99f1f 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -9,11 +9,11 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt", ] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } embedded-hal-async = { version = "1.0" } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 9eecd535c..4390a6da1 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", ] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3.0" diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index a7b389150..38fb2deec 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } -embassy-time = { version = "0.2", path = "../../embassy-time" } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } riscv-rt = "0.11" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 6be50a2f2..46e1e9a5f 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1.1" embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", ] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index c4ce42922..bf85f05d2 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -49,12 +49,12 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] teleprobe-meta = "1" embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } +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", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } -embassy-net = { version = "0.3", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } perf-client = { path = "../perf-client" } defmt = "0.3.0" From 53049943639d4493a49b0de408c653a0124ca61e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 23:16:28 +0100 Subject: [PATCH 235/760] Add docs.rs metadata to all crates. --- cyw43/Cargo.toml | 3 +++ embassy-embedded-hal/Cargo.toml | 3 +++ embassy-net-adin1110/Cargo.toml | 3 +++ embassy-net-enc28j60/Cargo.toml | 4 ++++ embassy-net-esp-hosted/Cargo.toml | 3 +++ embassy-net-ppp/Cargo.toml | 3 +++ embassy-net-wiznet/Cargo.toml | 3 +++ embassy-nrf/Cargo.toml | 3 +++ embassy-rp/Cargo.toml | 3 +++ embassy-stm32-wpan/Cargo.toml | 3 +++ embassy-stm32/Cargo.toml | 3 +++ embassy-usb-driver/Cargo.toml | 3 +++ embassy-usb/Cargo.toml | 3 +++ 13 files changed, 40 insertions(+) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index ac3122d41..20bb039a9 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -31,3 +31,6 @@ src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" target = "thumbv6m-none-eabi" features = ["defmt", "firmware-logs"] + +[package.metadata.docs.rs] +features = ["defmt", "firmware-logs"] diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 4c3d677be..c525f13fc 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -11,6 +11,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-embed features = ["std"] target = "x86_64-unknown-linux-gnu" +[package.metadata.docs.rs] +features = ["std"] + [features] std = [] time = ["dep:embassy-time"] diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 9b298beb9..e007e48cd 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -37,3 +37,6 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VE src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/" target = "thumbv7em-none-eabi" features = ["defmt"] + +[package.metadata.docs.rs] +features = ["defmt"] diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index 9cfb30e3f..92d18e38f 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -21,3 +21,7 @@ log = { version = "0.4.14", optional = true } src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/" target = "thumbv7em-none-eabi" +features = ["defmt"] + +[package.metadata.docs.rs] +features = ["defmt"] diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index ff7c43023..7d268a8bb 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -27,3 +27,6 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-esp-hosted-v$ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-esp-hosted/src/" target = "thumbv7em-none-eabi" features = ["defmt"] + +[package.metadata.docs.rs] +features = ["defmt"] diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 33e05227d..1ec8410c8 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -26,3 +26,6 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-ppp/src/" target = "thumbv7em-none-eabi" features = ["defmt"] + +[package.metadata.docs.rs] +features = ["defmt"] diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 8157bf115..4c1447508 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -21,3 +21,6 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERS src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/" target = "thumbv7em-none-eabi" features = ["defmt"] + +[package.metadata.docs.rs] +features = ["defmt"] diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 0be514e79..712cfb56f 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -15,6 +15,9 @@ flavors = [ { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" }, ] +[package.metadata.docs.rs] +features = ["nrf52840", "time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"] + [features] default = ["rt"] ## Cortex-M runtime (enabled by default) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 2cc62e314..16d55182a 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -12,6 +12,9 @@ flavors = [ { name = "rp2040", target = "thumbv6m-none-eabi" }, ] +[package.metadata.docs.rs] +features = ["defmt", "unstable-pac", "time-driver"] + [features] default = [ "rt" ] ## Enable the RP runtime. diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 1f699141f..143eea019 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -10,6 +10,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32 target = "thumbv7em-none-eabihf" features = ["stm32wb55rg"] +[package.metadata.docs.rs] +features = ["stm32wb55rg"] + [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 171b1d477..98292af79 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -31,6 +31,9 @@ flavors = [ { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" }, ] +[package.metadata.docs.rs] +features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h755zi-cm7"] + [dependencies] embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index d658f9ec7..460cb306a 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml @@ -12,5 +12,8 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-d features = ["defmt"] target = "thumbv7em-none-eabi" +[package.metadata.docs.rs] +features = ["defmt"] + [dependencies] defmt = { version = "0.3", optional = true } diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index e6e6b1954..029754e73 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -10,6 +10,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb/s features = ["defmt", "usbd-hid"] target = "thumbv7em-none-eabi" +[package.metadata.docs.rs] +features = ["defmt", "usbd-hid"] + [features] defmt = ["dep:defmt", "embassy-usb-driver/defmt"] usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"] From 9f6517e408f3a4b0a3fb00387a99deade55d6528 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 23:43:17 +0100 Subject: [PATCH 236/760] stm32,nrf: add warning on docs.rs directing the user to docs.embassy.dev. --- embassy-nrf/Cargo.toml | 1 + embassy-nrf/src/lib.rs | 4 ++++ embassy-stm32/Cargo.toml | 1 + embassy-stm32/src/lib.rs | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 712cfb56f..39b4cc598 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -17,6 +17,7 @@ flavors = [ [package.metadata.docs.rs] features = ["nrf52840", "time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"] +rustdoc-args = ["--cfg", "docsrs"] [features] default = ["rt"] diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 1510b7265..d9c92a76d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -1,5 +1,9 @@ #![no_std] #![allow(async_fn_in_trait)] +#![cfg_attr( + docsrs, + doc = "

You might want to browse the `embassy-nrf` documentation on the Embassy website instead.

The documentation here on `docs.rs` is built for a single chip only (nRF52840 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.

\n\n" +)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 98292af79..3b9f07e49 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -33,6 +33,7 @@ flavors = [ [package.metadata.docs.rs] features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h755zi-cm7"] +rustdoc-args = ["--cfg", "docsrs"] [dependencies] embassy-sync = { version = "0.5.0", path = "../embassy-sync" } diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 18871e83b..a465fccd8 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -1,5 +1,9 @@ #![cfg_attr(not(test), no_std)] #![allow(async_fn_in_trait)] +#![cfg_attr( + docsrs, + doc = "

You might want to browse the `embassy-stm32` documentation on the Embassy website instead.

The documentation here on `docs.rs` is built for a single chip only (STM32H755 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.

\n\n" +)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] From 17851c7ed0b7ef0081e46b31bd30e6169fa3a611 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 11 Jan 2024 23:54:15 +0100 Subject: [PATCH 237/760] time-driver: remove unused deps. --- embassy-time-driver/Cargo.toml | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index c6c23f698..e252c354a 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml @@ -366,26 +366,4 @@ tick-hz-5_242_880_000 = [] #! [dependencies] -defmt = { version = "0.3", optional = true } -log = { version = "0.4.14", optional = true } - -embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } -embedded-hal-1 = { package = "embedded-hal", version = "1.0" } -embedded-hal-async = { version = "1.0" } - -futures-util = { version = "0.3.17", default-features = false } -critical-section = "1.1" -cfg-if = "1.0.0" -heapless = "0.8" - document-features = "0.2.7" - -# WASM dependencies -wasm-bindgen = { version = "0.2.81", optional = true } -js-sys = { version = "0.3", optional = true } -wasm-timer = { version = "0.2.5", optional = true } - -[dev-dependencies] -serial_test = "0.9" -critical-section = { version = "1.1", features = ["std"] } -embassy-executor = { version = "0.5.0", path = "../embassy-executor" } From cb93823b4b0eb97ae92a6d2104dd0b9e00456c79 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Jan 2024 00:00:19 +0100 Subject: [PATCH 238/760] net-wiznet: too many keywords. --- embassy-net-wiznet/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 4c1447508..c703d8bc6 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -2,7 +2,7 @@ name = "embassy-net-wiznet" version = "0.1.0" description = "embassy-net driver for WIZnet SPI Ethernet chips" -keywords = ["embedded", "wiznet", "embassy-net", "embedded-hal-async", "ethernet", "async"] +keywords = ["embedded", "embassy-net", "embedded-hal-async", "ethernet", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" From 6fb38849e73aacabd9b6a603fb9b0768195c36b7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Jan 2024 00:01:31 +0100 Subject: [PATCH 239/760] net-tuntap: too many keywords. --- embassy-net-tuntap/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml index 7e2c7bfd5..d58680481 100644 --- a/embassy-net-tuntap/Cargo.toml +++ b/embassy-net-tuntap/Cargo.toml @@ -2,8 +2,8 @@ name = "embassy-net-tuntap" version = "0.1.0" description = "embassy-net driver for Linux TUN/TAP interfaces." -keywords = ["embedded", "tuntap", "embassy-net", "embedded-hal-async", "ethernet", "async"] -categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +keywords = ["embedded", "tuntap", "embassy-net", "ethernet", "async"] +categories = ["embedded", "hardware-support", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" From 583f6d9cc55627906ab39a4b6c741d543f3704c7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Jan 2024 00:14:10 +0100 Subject: [PATCH 240/760] net-ppp: add repo, docs link. --- .github/ci/doc.sh | 1 + embassy-net-ppp/Cargo.toml | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index aaccb8a67..d65bd484f 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -37,6 +37,7 @@ docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/g docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup docserver-builder -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup +docserver-builder -i ./embassy-net-ppp -o webroot/crates/embassy-net-ppp/git.zup docserver-builder -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 1ec8410c8..59e9c084e 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -2,10 +2,12 @@ name = "embassy-net-ppp" version = "0.1.0" description = "embassy-net driver for PPP over Serial" -keywords = ["embedded", "ppp", "embassy-net", "embedded-hal-async", "ethernet", "async"] +keywords = ["embedded", "ppp", "embassy-net", "embedded-hal-async", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-ppp" [features] defmt = ["dep:defmt", "ppproto/defmt"] From 6a1c415a4c731f06e5ebf6932bd53168d89152c9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Jan 2024 00:32:47 +0100 Subject: [PATCH 241/760] Complete cargo.tomls more. --- .github/ci/doc.sh | 17 +++++++++++------ cyw43-pio/Cargo.toml | 6 ++++++ cyw43/Cargo.toml | 6 ++++++ embassy-boot-nrf/Cargo.toml | 1 + embassy-boot-rp/Cargo.toml | 1 + embassy-boot-stm32/Cargo.toml | 1 + embassy-boot/Cargo.toml | 1 + embassy-embedded-hal/Cargo.toml | 9 ++++++++- embassy-executor-macros/Cargo.toml | 3 ++- embassy-executor/Cargo.toml | 1 + embassy-futures/Cargo.toml | 1 + embassy-net-adin1110/Cargo.toml | 3 ++- embassy-net-driver-channel/Cargo.toml | 1 + embassy-net-driver/Cargo.toml | 1 + embassy-net-enc28j60/Cargo.toml | 4 +++- embassy-net-esp-hosted/Cargo.toml | 4 +++- embassy-net-tuntap/Cargo.toml | 1 + embassy-net-wiznet/Cargo.toml | 1 + embassy-net/Cargo.toml | 1 + embassy-nrf/Cargo.toml | 5 +++++ embassy-rp/Cargo.toml | 5 +++++ embassy-stm32/Cargo.toml | 5 +++++ embassy-sync/Cargo.toml | 1 + embassy-time-driver/Cargo.toml | 1 + embassy-time-queue-driver/Cargo.toml | 1 + embassy-time/Cargo.toml | 1 + embassy-usb-dfu/Cargo.toml | 1 + embassy-usb-driver/Cargo.toml | 5 +++++ embassy-usb/Cargo.toml | 5 +++++ 29 files changed, 82 insertions(+), 11 deletions(-) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index d65bd484f..70833f934 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -23,24 +23,29 @@ docserver-builder -i ./embassy-boot-stm32 -o webroot/crates/embassy-boot-stm32/g docserver-builder -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup -docserver-builder -i ./embassy-net -o webroot/crates/embassy-net/git.zup -docserver-builder -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup -docserver-builder -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup +docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup +docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup +docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static + docserver-builder -i ./embassy-time -o webroot/crates/embassy-time/git.zup docserver-builder -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup +docserver-builder -i ./embassy-time-queue-driver -o webroot/crates/embassy-time-queue-driver/git.zup + docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup -docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup -docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup + +docserver-builder -i ./embassy-net -o webroot/crates/embassy-net/git.zup +docserver-builder -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup +docserver-builder -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup docserver-builder -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup docserver-builder -i ./embassy-net-ppp -o webroot/crates/embassy-net-ppp/git.zup +docserver-builder -i ./embassy-net-tuntap -o webroot/crates/embassy-net-tuntap/git.zup docserver-builder -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup -docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static docserver-builder -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup export KUBECONFIG=/ci/secrets/kubeconfig.yml diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 14c07178f..b14ad7349 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -2,6 +2,12 @@ name = "cyw43-pio" version = "0.1.0" edition = "2021" +description = "RP2040 PIO SPI implementation for cyw43" +keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/cyw43-pio" [features] # If disabled, SPI runs at 31.25MHz diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 20bb039a9..3b4aada00 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -2,6 +2,12 @@ name = "cyw43" version = "0.1.0" edition = "2021" +description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." +keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/cyw43" [features] defmt = ["dep:defmt"] diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 7fc53648a..9e3385066 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" description = "Bootloader lib for nRF chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-boot-nrf" categories = [ "embedded", "no-std", diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index ceb14445c..080a50777 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" description = "Bootloader lib for RP2040 chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-boot-rp" categories = [ "embedded", "no-std", diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index f4e31bae8..4849fa02c 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" description = "Bootloader lib for STM32 chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-boot-stm32" categories = [ "embedded", "no-std", diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index a70849018..801d3daa6 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.1" description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-boot" categories = [ "embedded", "no-std", diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index c525f13fc..e89179740 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -3,7 +3,14 @@ name = "embassy-embedded-hal" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" - +description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy." +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-embedded-hal" +categories = [ + "embedded", + "no-std", + "asynchronous", +] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-embedded-hal-v$VERSION/embassy-embedded-hal/src/" diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml index 6ea7ddb71..57335e1e1 100644 --- a/embassy-executor-macros/Cargo.toml +++ b/embassy-executor-macros/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "macros for creating the entry point and tasks for embassy-executor" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-executor-macros" categories = [ "embedded", "no-std", @@ -21,4 +22,4 @@ proc-macro2 = "1.0.29" proc-macro = true [features] -nightly = [] \ No newline at end of file +nightly = [] diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 2ef3f5294..b6b156c9f 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-executor" categories = [ "embedded", "no-std", diff --git a/embassy-futures/Cargo.toml b/embassy-futures/Cargo.toml index ee1f4c9af..47cefa56f 100644 --- a/embassy-futures/Cargo.toml +++ b/embassy-futures/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.1" edition = "2021" description = "no-std, no-alloc utilities for working with futures" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-futures" readme = "README.md" license = "MIT OR Apache-2.0" categories = [ diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index e007e48cd..5cc399cdc 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -2,11 +2,12 @@ name = "embassy-net-adin1110" version = "0.2.0" description = "embassy-net driver for the ADIN1110 ethernet chip" -keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"] +keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-adin1110" [dependencies] heapless = "0.8" diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index 58d3d2316..c1ad11482 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack." repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-driver-channel" categories = [ "embedded", "no-std", diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml index 9cd6a2eaa..97e8a0db3 100644 --- a/embassy-net-driver/Cargo.toml +++ b/embassy-net-driver/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "Driver trait for the `embassy-net` async TCP/IP network stack." repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-driver" categories = [ "embedded", "no-std", diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index 92d18e38f..ab594a2f4 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -2,10 +2,12 @@ name = "embassy-net-enc28j60" version = "0.1.0" description = "embassy-net driver for the ENC28J60 ethernet chip" -keywords = ["embedded", "enc28j60", "embassy-net", "embedded-hal-async", "ethernet", "async"] +keywords = ["embedded", "enc28j60", "embassy-net", "embedded-hal-async", "ethernet"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-enc28j60" [dependencies] embedded-hal = { version = "1.0" } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 7d268a8bb..dfca8bec6 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -3,9 +3,11 @@ name = "embassy-net-esp-hosted" version = "0.1.0" edition = "2021" description = "embassy-net driver for ESP-Hosted" -keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi", "async"] +keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-esp-hosted" [dependencies] defmt = { version = "0.3", optional = true } diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml index d58680481..1044151ae 100644 --- a/embassy-net-tuntap/Cargo.toml +++ b/embassy-net-tuntap/Cargo.toml @@ -7,6 +7,7 @@ categories = ["embedded", "hardware-support", "network-programming", "async"] license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-tuntap" [dependencies] embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index c703d8bc6..b52aecc70 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -7,6 +7,7 @@ categories = ["embedded", "hardware-support", "no-std", "network-programming", " license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-wiznet" [dependencies] embedded-hal = { version = "1.0" } diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index ffa4a64b6..44bd2e8f3 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "Async TCP/IP network stack for embedded systems" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net" categories = [ "embedded", "no-std", diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 39b4cc598..f79da9d77 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -3,6 +3,11 @@ name = "embassy-nrf" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" +description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" +keywords = ["embedded", "async", "nordic", "nrf", "embedded-hal"] +categories = ["embedded", "hardware-support", "no-std", "async"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-nrf" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-nrf-v$VERSION/embassy-nrf/src/" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 16d55182a..503d4bddc 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -3,6 +3,11 @@ name = "embassy-rp" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" +description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller" +keywords = ["embedded", "async", "raspberry-pi", "rp2040", "embedded-hal"] +categories = ["embedded", "hardware-support", "no-std", "async"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-rp" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/embassy-rp/src/" diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3b9f07e49..ac672788f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -3,6 +3,11 @@ name = "embassy-stm32" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" +description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers" +keywords = ["embedded", "async", "stm32", "hal", "embedded-hal"] +categories = ["embedded", "hardware-support", "no-std", "async"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-stm32" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 38b0e5d30..85673026c 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -4,6 +4,7 @@ version = "0.5.0" edition = "2021" description = "no-std, no-alloc synchronization primitives with async support" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-sync" readme = "README.md" license = "MIT OR Apache-2.0" categories = [ diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index e252c354a..d9f2e97df 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" description = "Driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-time-driver" readme = "README.md" license = "MIT OR Apache-2.0" categories = [ diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml index 85ee1da1b..9ce9d79bb 100644 --- a/embassy-time-queue-driver/Cargo.toml +++ b/embassy-time-queue-driver/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" description = "Timer queue driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-time-queue-driver" readme = "README.md" license = "MIT OR Apache-2.0" categories = [ diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 6b1c7cc58..6b0a0f22d 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -4,6 +4,7 @@ version = "0.3.0" edition = "2021" description = "Instant and Duration for embedded no-std systems, with async timer support" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-time" readme = "README.md" license = "MIT OR Apache-2.0" categories = [ diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 6087bcd7d..b0eb917e6 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" description = "An implementation of the USB DFU 1.1 protocol, using embassy-boot" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-usb-dfu" categories = [ "embedded", "no-std", diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index 460cb306a..6d36106cd 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml @@ -3,6 +3,11 @@ name = "embassy-usb-driver" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" +description = "Driver trait for `embassy-usb`, an async USB device stack for embedded devices." +keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] +categories = ["embedded", "hardware-support", "no-std", "async"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-usb-driver" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 029754e73..be810b510 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -3,6 +3,11 @@ name = "embassy-usb" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" +description = "Async USB device stack for embedded devices in Rust." +keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] +categories = ["embedded", "hardware-support", "no-std", "async"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-usb" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-v$VERSION/embassy-usb/src/" From 4c23f197b3225e8165f07ddf66ab54f774c4212f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Jan 2024 00:35:01 +0100 Subject: [PATCH 242/760] Fix invalid "async" crates.io category. --- cyw43-pio/Cargo.toml | 2 +- cyw43/Cargo.toml | 2 +- embassy-hal-internal/Cargo.toml | 10 +++++++++- embassy-net-adin1110/Cargo.toml | 2 +- embassy-net-enc28j60/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-ppp/Cargo.toml | 2 +- embassy-net-tuntap/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-usb-driver/Cargo.toml | 2 +- embassy-usb/Cargo.toml | 2 +- 14 files changed, 22 insertions(+), 14 deletions(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index b14ad7349..157046b18 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" description = "RP2040 PIO SPI implementation for cyw43" keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] -categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/cyw43-pio" diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 3b4aada00..c857f7378 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] -categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/cyw43" diff --git a/embassy-hal-internal/Cargo.toml b/embassy-hal-internal/Cargo.toml index 42e03199c..c5013f365 100644 --- a/embassy-hal-internal/Cargo.toml +++ b/embassy-hal-internal/Cargo.toml @@ -3,6 +3,14 @@ name = "embassy-hal-internal" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" +description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY." +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-hal-internal" +categories = [ + "embedded", + "no-std", + "asynchronous", +] [features] @@ -26,4 +34,4 @@ log = { version = "0.4.14", optional = true } num-traits = { version = "0.2.14", default-features = false } cortex-m = { version = "0.7.6", optional = true } -critical-section = { version = "1", optional = true } \ No newline at end of file +critical-section = { version = "1", optional = true } diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 5cc399cdc..97579a467 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -3,7 +3,7 @@ name = "embassy-net-adin1110" version = "0.2.0" description = "embassy-net driver for the ADIN1110 ethernet chip" keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet"] -categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index ab594a2f4..23bd3da7e 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -3,7 +3,7 @@ name = "embassy-net-enc28j60" version = "0.1.0" description = "embassy-net driver for the ENC28J60 ethernet chip" keywords = ["embedded", "enc28j60", "embassy-net", "embedded-hal-async", "ethernet"] -categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index dfca8bec6..dda65dbf9 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" description = "embassy-net driver for ESP-Hosted" keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi"] -categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-esp-hosted" diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 59e9c084e..c4bea202f 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -3,7 +3,7 @@ name = "embassy-net-ppp" version = "0.1.0" description = "embassy-net driver for PPP over Serial" keywords = ["embedded", "ppp", "embassy-net", "embedded-hal-async", "async"] -categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml index 1044151ae..5d38fb013 100644 --- a/embassy-net-tuntap/Cargo.toml +++ b/embassy-net-tuntap/Cargo.toml @@ -3,7 +3,7 @@ name = "embassy-net-tuntap" version = "0.1.0" description = "embassy-net driver for Linux TUN/TAP interfaces." keywords = ["embedded", "tuntap", "embassy-net", "ethernet", "async"] -categories = ["embedded", "hardware-support", "network-programming", "async"] +categories = ["embedded", "hardware-support", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index b52aecc70..f87bf2bd0 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -3,7 +3,7 @@ name = "embassy-net-wiznet" version = "0.1.0" description = "embassy-net driver for WIZnet SPI Ethernet chips" keywords = ["embedded", "embassy-net", "embedded-hal-async", "ethernet", "async"] -categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2021" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index f79da9d77..10f268b51 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" keywords = ["embedded", "async", "nordic", "nrf", "embedded-hal"] -categories = ["embedded", "hardware-support", "no-std", "async"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-nrf" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 503d4bddc..ffed4c770 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller" keywords = ["embedded", "async", "raspberry-pi", "rp2040", "embedded-hal"] -categories = ["embedded", "hardware-support", "no-std", "async"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-rp" diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ac672788f..f1539229f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers" keywords = ["embedded", "async", "stm32", "hal", "embedded-hal"] -categories = ["embedded", "hardware-support", "no-std", "async"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-stm32" diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index 6d36106cd..837878621 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "Driver trait for `embassy-usb`, an async USB device stack for embedded devices." keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] -categories = ["embedded", "hardware-support", "no-std", "async"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-usb-driver" diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index be810b510..1b31b6145 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" description = "Async USB device stack for embedded devices in Rust." keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] -categories = ["embedded", "hardware-support", "no-std", "async"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-usb" From a36c8eb84311faba67c13c56da40a7c4db2fe15c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Jan 2024 00:53:46 +0100 Subject: [PATCH 243/760] boot: bump crates to 0.2 --- embassy-boot-nrf/Cargo.toml | 4 ++-- embassy-boot-rp/Cargo.toml | 4 ++-- embassy-boot-stm32/Cargo.toml | 4 ++-- embassy-boot/Cargo.toml | 2 +- embassy-usb-dfu/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 4 ++-- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 9e3385066..c056dc66a 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-nrf" -version = "0.1.0" +version = "0.2.0" description = "Bootloader lib for nRF chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" @@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false } -embassy-boot = { version = "0.1.0", path = "../embassy-boot" } +embassy-boot = { version = "0.2.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 080a50777..305bc5995 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-rp" -version = "0.1.0" +version = "0.2.0" description = "Bootloader lib for RP2040 chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" @@ -26,7 +26,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false } -embassy-boot = { version = "0.1.0", path = "../embassy-boot" } +embassy-boot = { version = "0.2.0", path = "../embassy-boot" } embassy-time = { version = "0.3.0", path = "../embassy-time" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index 4849fa02c..6f8fbe355 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-stm32" -version = "0.1.0" +version = "0.2.0" description = "Bootloader lib for STM32 chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" @@ -27,7 +27,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false } -embassy-boot = { version = "0.1.0", path = "../embassy-boot" } +embassy-boot = { version = "0.2.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 801d3daa6..242caa229 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot" -version = "0.1.1" +version = "0.2.0" description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index b0eb917e6..1ca5fea42 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -18,7 +18,7 @@ categories = [ bitflags = "2.4.1" cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } defmt = { version = "0.3.5", optional = true } -embassy-boot = { version = "0.1.1", path = "../embassy-boot" } +embassy-boot = { version = "0.2.0", path = "../embassy-boot" } # embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 2534cad69..86f6676cb 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -9,8 +9,8 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } -embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot", features = [] } -embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot-nrf", features = [] } +embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } +embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 56362cb7e..70741a0ce 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } -embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot-rp", features = [] } +embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = "0.3" diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 4a4d091f6..1cb143820 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32" } +embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 00e283cf4..c4ae461a5 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 4af9357e8..995487cdd 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 20e6a71e8..b2abc005c 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index b4b33fa4a..7203e6350 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 92cdeb450..ec134f394 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 80fd08bb6..0bdf94331 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index b2a744d0d..e38e9f3af 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } From e5a51a1ad59cbac83315a9a25c4773ac84eb6819 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Jan 2024 01:10:16 +0100 Subject: [PATCH 244/760] net-tuntap: fix docs target. --- embassy-net-tuntap/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml index 5d38fb013..2cd0c0f7e 100644 --- a/embassy-net-tuntap/Cargo.toml +++ b/embassy-net-tuntap/Cargo.toml @@ -18,4 +18,4 @@ libc = "0.2.101" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-tuntap-v$VERSION/embassy-net-tuntap/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-tuntap/src/" -target = "thumbv7em-none-eabi" +target = "x86_64-unknown-linux-gnu" From 08126d181a494e80bdd0e495f157445e15cfeb23 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 12 Jan 2024 07:01:43 +0100 Subject: [PATCH 245/760] fix: use released version for stm32wb-hci --- embassy-stm32-wpan/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 143eea019..ef85ecac8 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -29,7 +29,7 @@ aligned = "0.4.1" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } -stm32wb-hci = { git = "https://github.com/Dirbaio/stm32wb-hci", rev = "0aff47e009c30c5fc5d520672625173d75f7505c", optional = true } +stm32wb-hci = { version = "0.17.0", optional = true } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } bitflags = { version = "2.3.3", optional = true } From 883b923fafc41a23c2ae7a3d26b93992e2726523 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 12 Jan 2024 08:33:37 +0100 Subject: [PATCH 246/760] fix: update after api change --- examples/stm32wb/src/bin/eddystone_beacon.rs | 8 +++---- examples/stm32wb/src/bin/gatt_server.rs | 25 ++++++++++---------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs index cf9a5aa28..d3b3c15ca 100644 --- a/examples/stm32wb/src/bin/eddystone_beacon.rs +++ b/examples/stm32wb/src/bin/eddystone_beacon.rs @@ -11,11 +11,9 @@ use embassy_stm32::rcc::WPAN_DEFAULT; use embassy_stm32_wpan::hci::host::uart::UartHci; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; use embassy_stm32_wpan::hci::types::AdvertisingType; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{ - AdvertisingDataType, DiscoverableParameters, GapCommands, Role, -}; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; +use embassy_stm32_wpan::hci::vendor::command::gap::{AdvertisingDataType, DiscoverableParameters, GapCommands, Role}; +use embassy_stm32_wpan::hci::vendor::command::gatt::GattCommands; +use embassy_stm32_wpan::hci::vendor::command::hal::{ConfigData, HalCommands, PowerLevel}; use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::TlMbox; diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index 5ce620350..0dfe0ed09 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs @@ -12,17 +12,17 @@ use embassy_stm32_wpan::hci::event::command::{CommandComplete, ReturnParameters} use embassy_stm32_wpan::hci::host::uart::{Packet, UartHci}; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; use embassy_stm32_wpan::hci::types::AdvertisingType; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{ +use embassy_stm32_wpan::hci::vendor::command::gap::{ AddressType, AuthenticationRequirements, DiscoverableParameters, GapCommands, IoCapability, LocalName, Pin, Role, SecureConnectionSupport, }; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::{ +use embassy_stm32_wpan::hci::vendor::command::gatt::{ AddCharacteristicParameters, AddServiceParameters, CharacteristicEvent, CharacteristicPermission, CharacteristicProperty, EncryptionKeySize, GattCommands, ServiceType, UpdateCharacteristicValueParameters, Uuid, WriteResponseParameters, }; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; -use embassy_stm32_wpan::hci::vendor::stm32wb::event::{self, AttributeHandle, Stm32Wb5xEvent}; +use embassy_stm32_wpan::hci::vendor::command::hal::{ConfigData, HalCommands, PowerLevel}; +use embassy_stm32_wpan::hci::vendor::event::{self, command::VendorReturnParameters, AttributeHandle, VendorEvent}; use embassy_stm32_wpan::hci::{BdAddr, Event}; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::sub::ble::Ble; @@ -190,11 +190,11 @@ async fn main(_spawner: Spawner) { mbox.ble_subsystem.set_discoverable(&discovery_params).await.unwrap(); } Event::Vendor(vendor_event) => match vendor_event { - Stm32Wb5xEvent::AttReadPermitRequest(read_req) => { + VendorEvent::AttReadPermitRequest(read_req) => { defmt::info!("read request received {}, allowing", read_req); mbox.ble_subsystem.allow_read(read_req.conn_handle).await } - Stm32Wb5xEvent::AttWritePermitRequest(write_req) => { + VendorEvent::AttWritePermitRequest(write_req) => { defmt::info!("write request received {}, allowing", write_req); mbox.ble_subsystem .write_response(&WriteResponseParameters { @@ -206,7 +206,7 @@ async fn main(_spawner: Spawner) { .await .unwrap() } - Stm32Wb5xEvent::GattAttributeModified(attribute) => { + VendorEvent::GattAttributeModified(attribute) => { defmt::info!("{}", ble_context); if attribute.attr_handle.0 == ble_context.chars.notify.0 + 2 { if attribute.data()[0] == 0x01 { @@ -333,7 +333,7 @@ async fn gatt_add_service(ble_subsystem: &mut Ble, uuid: Uuid) -> Result Date: Fri, 12 Jan 2024 09:17:26 +0100 Subject: [PATCH 247/760] docs: add readme --- embassy-stm32-wpan/Cargo.toml | 5 +++++ embassy-stm32-wpan/src/lib.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index ef85ecac8..4f53a400a 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -3,6 +3,11 @@ name = "embassy-stm32-wpan" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" +description = "Async STM32 WPAN stack for embedded devices in Rust." +keywords = ["embedded", "async", "stm32", "ble", "wpan"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-stm32-wpan" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src/" diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index a5dbb7420..f9560d235 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -1,5 +1,7 @@ #![no_std] #![allow(async_fn_in_trait)] +#![doc = include_str!("../README.md")] +// #![warn(missing_docs)] // This must go FIRST so that all the other modules see its macros. mod fmt; From a40186f3cb96feab245f5682311bb72e24b67e83 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 12 Jan 2024 09:21:51 +0100 Subject: [PATCH 248/760] fix: add missing file --- embassy-stm32-wpan/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 embassy-stm32-wpan/README.md diff --git a/embassy-stm32-wpan/README.md b/embassy-stm32-wpan/README.md new file mode 100644 index 000000000..b1a2cec55 --- /dev/null +++ b/embassy-stm32-wpan/README.md @@ -0,0 +1,13 @@ +# embassy-stm32-wpan + +Async WPAN (short range wireless) on STM32WB families. + +## Features + +- Rust interface to the WPAN stack running on the STM32WB co-processor . +- Controller trait implementation for the [stm32wb-hci](https://crates.io/crates/stm32wb-hci) crate. +- Embassy-net driver implementation for 802.15.4 MAC. + +## Examples + +See the [stm32wb examples](https://github.com/embassy-rs/embassy/tree/main/examples/stm32wb). From f23182a71009a2655fdeba1ea98b9e1db9dd15cc Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 12 Jan 2024 09:22:16 +0100 Subject: [PATCH 249/760] fix: rustfmt --- examples/stm32wb/src/bin/gatt_server.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index 0dfe0ed09..3b50d6c31 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs @@ -22,7 +22,8 @@ use embassy_stm32_wpan::hci::vendor::command::gatt::{ WriteResponseParameters, }; use embassy_stm32_wpan::hci::vendor::command::hal::{ConfigData, HalCommands, PowerLevel}; -use embassy_stm32_wpan::hci::vendor::event::{self, command::VendorReturnParameters, AttributeHandle, VendorEvent}; +use embassy_stm32_wpan::hci::vendor::event::command::VendorReturnParameters; +use embassy_stm32_wpan::hci::vendor::event::{self, AttributeHandle, VendorEvent}; use embassy_stm32_wpan::hci::{BdAddr, Event}; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::sub::ble::Ble; From 7728c95584bb049b64507c458ba47455d4633396 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 12 Jan 2024 09:28:54 +0100 Subject: [PATCH 250/760] fix changed import paths --- tests/stm32/src/bin/wpan_ble.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/stm32/src/bin/wpan_ble.rs b/tests/stm32/src/bin/wpan_ble.rs index ff838471b..82a540d45 100644 --- a/tests/stm32/src/bin/wpan_ble.rs +++ b/tests/stm32/src/bin/wpan_ble.rs @@ -15,11 +15,9 @@ use embassy_stm32::rcc::WPAN_DEFAULT; use embassy_stm32_wpan::hci::host::uart::UartHci; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; use embassy_stm32_wpan::hci::types::AdvertisingType; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{ - AdvertisingDataType, DiscoverableParameters, GapCommands, Role, -}; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands; -use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; +use embassy_stm32_wpan::hci::vendor::command::gap::{AdvertisingDataType, DiscoverableParameters, GapCommands, Role}; +use embassy_stm32_wpan::hci::vendor::command::gatt::GattCommands; +use embassy_stm32_wpan::hci::vendor::command::hal::{ConfigData, HalCommands, PowerLevel}; use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::sub::mm; From 850fe7251afd61aca188d08cf15841a6c6a5d3a7 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sat, 13 Jan 2024 09:01:11 +1100 Subject: [PATCH 251/760] Add cyw43 package versions to rp-examples Cargo.toml --- examples/rp/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index a3714289f..e1092dba4 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -16,8 +16,8 @@ embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defm 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" } -cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } -cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } +cyw43 = { version = "0.1.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } +cyw43-pio = { version = "0.1.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } defmt = "0.3" defmt-rtt = "0.4" From d2d9175a1dce7c52173dfac74711287dc799e81b Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Sat, 13 Jan 2024 02:14:56 +0100 Subject: [PATCH 252/760] Added manual ISR FAQ --- docs/modules/ROOT/pages/faq.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index fd355827b..b33623053 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -159,3 +159,7 @@ Note that the git revision should match any other embassy patches or git depende When you aren't using the `nightly` feature of `embassy-executor`, the executor uses a bump allocator, which may require configuration. Check out link:https://docs.embassy.dev/embassy-executor/git/cortex-m/index.html#task-arena[Task Arena Documentation] for more details. + +== Can I use manual ISRs alongside Embassy? + +Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task” flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project]. \ No newline at end of file From bb755963025f55cc04aaabab1e0073b2edfa5bb6 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 14 Jan 2024 11:08:18 +1100 Subject: [PATCH 253/760] End all feature doc comments with a full stop --- embassy-rp/Cargo.toml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index ffed4c770..edb152a89 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -25,10 +25,10 @@ default = [ "rt" ] ## Enable the RP runtime. rt = [ "rp-pac/rt" ] -## Enable defmt +## Enable defmt. defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] -## critical section that is safe for multicore use +## critical section that is safe for multicore use. critical-section-impl = ["critical-section/restore-state-u8"] ## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. @@ -37,14 +37,14 @@ critical-section-impl = ["critical-section/restore-state-u8"] ## There are no plans to make this stable. unstable-pac = [] -## Enable the timer for use with `embassy-time` with a 1MHz tick rate +## Enable the timer for use with `embassy-time` with a 1MHz tick rate. time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000"] -## Enable ROM function cache +## Enable ROM function cache. rom-func-cache = [] -## Enable intrinsics +## Enable intrinsics. intrinsics = [] -## Enable ROM v2 intrinsics +## Enable ROM v2 intrinsics. rom-v2-intrinsics = [] ## Allow using QSPI pins as GPIO pins. This is mostly not what you want (because your flash lives there) @@ -58,19 +58,19 @@ run-from-ram = [] #! ### boot2 flash chip support #! If none of these are enabled, w25q080 is used by default (used on the pico) -## AT25SF128a +## AT25SF128a. boot2-at25sf128a = [] -## GD25Q64cs +## GD25Q64cs. boot2-gd25q64cs = [] -## generic-03h +## generic-03h. boot2-generic-03h = [] -## IS25LP080 +## IS25LP080. boot2-is25lp080 = [] -## ram-memcpy +## ram-memcpy. boot2-ram-memcpy = [] -## W25Q080 +## W25Q080. boot2-w25q080 = [] -## W25X10cl +## W25X10cl. boot2-w25x10cl = [] [dependencies] From 4770325bb7b4beca1b2b108674ce5dfbcf17a49f Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 14 Jan 2024 13:21:50 +1100 Subject: [PATCH 254/760] Additional features docs for embassy-rp --- embassy-rp/Cargo.toml | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index edb152a89..794f1109c 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -22,17 +22,17 @@ features = ["defmt", "unstable-pac", "time-driver"] [features] default = [ "rt" ] -## Enable the RP runtime. +## Enable the rt feature of [`rp-pac`](https://docs.rs/crates/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. rt = [ "rp-pac/rt" ] -## Enable defmt. +## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] -## critical section that is safe for multicore use. +## Configure the critical section crate to use an implementation that is safe for multicore use on rp2040. critical-section-impl = ["critical-section/restore-state-u8"] ## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. -## This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. +## This is unstable because semver-minor (non-breaking) releases of `embassy-rp` may major-bump (breaking) the PAC version. ## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. ## There are no plans to make this stable. unstable-pac = [] @@ -40,15 +40,18 @@ unstable-pac = [] ## Enable the timer for use with `embassy-time` with a 1MHz tick rate. time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000"] -## Enable ROM function cache. +## Enable ROM function cache. This will store the address of a ROM function when first used, improving performance of subsequent calls. rom-func-cache = [] -## Enable intrinsics. +## Enable implementations of some compiler intrinsics using functions in the rp2040 Mask ROM. +## These should be as fast or faster than the implementations in compiler-builtins. They also save code space and reduce memory contention. +## Compiler intrinsics are used automatically, you do not need to change your code to get performance improvements from this feature. intrinsics = [] -## Enable ROM v2 intrinsics. +## Enable intrinsics based on extra ROM functions added in the v2 version of the rp2040 Mask ROM. +## This version added a lot more floating point operations - many f64 functions and a few f32 functions were added in ROM v2. rom-v2-intrinsics = [] -## Allow using QSPI pins as GPIO pins. This is mostly not what you want (because your flash lives there) -## and would add both code and memory overhead when enabled needlessly. +## Allow using QSPI pins as GPIO pins. This is mostly not what you want (because your flash is attached via QSPI pins) +## and adds code and memory overhead when this feature is enabled. qspi-as-gpio = [] ## Indicate code is running from RAM. @@ -57,20 +60,24 @@ qspi-as-gpio = [] run-from-ram = [] #! ### boot2 flash chip support -#! If none of these are enabled, w25q080 is used by default (used on the pico) -## AT25SF128a. +#! RP2040's internal bootloader is only able to run code from the first 256 bytes of flash. +#! A 2nd stage bootloader (boot2) is required to run larger programs from external flash. +#! Select from existing boot2 implementations via the following features. If none are selected, +#! boot2-w25q080 will be used (w25q080 is the flash chip used on the pico). +#! Each implementation uses flash commands and timings specific to a QSPI flash chip family for better performance. +## Use boot2 with support for Renesas/Dialog AT25SF128a SPI flash. boot2-at25sf128a = [] -## GD25Q64cs. +## Use boot2 with support for Gigadevice GD25Q64C SPI flash. boot2-gd25q64cs = [] -## generic-03h. +## Use boot2 that only uses generic flash commands - these are supported by all SPI flash, but are slower. boot2-generic-03h = [] -## IS25LP080. +## Use boot2 with support for ISSI IS25LP080 SPI flash. boot2-is25lp080 = [] -## ram-memcpy. +## Use boot2 that copies the entire program to RAM before booting. This uses generic flash commands to perform the copy. boot2-ram-memcpy = [] -## W25Q080. +## Use boot2 with support for Winbond W25Q080 SPI flash. boot2-w25q080 = [] -## W25X10cl. +## Use boot2 with support for Winbond W25X10CL SPI flash. boot2-w25x10cl = [] [dependencies] From 929ebd568ac24af0ab8b9105aea9981bdeefef0a Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 14 Jan 2024 21:30:53 +0000 Subject: [PATCH 255/760] embassy-executor-macros v0.4.1 --- embassy-executor-macros/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml index 57335e1e1..2953e7ccc 100644 --- a/embassy-executor-macros/Cargo.toml +++ b/embassy-executor-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor-macros" -version = "0.4.0" +version = "0.4.1" edition = "2021" license = "MIT OR Apache-2.0" description = "macros for creating the entry point and tasks for embassy-executor" From 018c48cf1ce54effe73f2287cb78fabbdede215c Mon Sep 17 00:00:00 2001 From: shufps Date: Sun, 14 Jan 2024 22:43:22 +0100 Subject: [PATCH 256/760] changes to get usb working on a L1. Adds a usb_serial example too --- embassy-stm32/src/usb/usb.rs | 6 ++++++ examples/stm32l1/Cargo.toml | 1 + 2 files changed, 7 insertions(+) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 04b1b35e8..364076739 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -286,7 +286,10 @@ impl<'d, T: Instance> Driver<'d, T> { #[cfg(not(usb_v4))] regs.btable().write(|w| w.set_btable(0)); + #[cfg(not(stm32l1))] dp.set_as_af(dp.af_num(), AFType::OutputPushPull); + + #[cfg(not(stm32l1))] dm.set_as_af(dm.af_num(), AFType::OutputPushPull); // Initialize the bus so that it signals that power is available @@ -444,6 +447,9 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { #[cfg(any(usb_v3, usb_v4))] regs.bcdr().write(|w| w.set_dppu(true)); + #[cfg(stm32l1)] + crate::pac::SYSCFG.pmc().modify(|w| w.set_usb_pu(true)); + trace!("enabled"); let mut ep_types = [EpType::BULK; EP_COUNT - 1]; diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index c0b35b716..322c41262 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -9,6 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de 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"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" From ec4cffe28c314b8cb69998fe0b5ddafbf4e092e8 Mon Sep 17 00:00:00 2001 From: shufps Date: Sun, 14 Jan 2024 22:46:20 +0100 Subject: [PATCH 257/760] usb-serial with HSI --- examples/stm32l1/src/bin/usb_serial.rs | 103 +++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 examples/stm32l1/src/bin/usb_serial.rs diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs new file mode 100644 index 000000000..7b1e84cbc --- /dev/null +++ b/examples/stm32l1/src/bin/usb_serial.rs @@ -0,0 +1,103 @@ +#![no_std] +#![no_main] + +use defmt::{panic, *}; +use embassy_executor::Spawner; +use embassy_stm32::usb::{self, Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::Builder; +use futures::future::join; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USB_LP => usb::InterruptHandler; + +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = embassy_stm32::Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz + div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3) + }); + config.rcc.mux = ClockSrc::PLL1_R; + } + + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); + + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-Serial Example"); + config.serial_number = Some("123456"); + + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + + let mut usb = builder.build(); + + let usb_fut = usb.run(); + + let echo_fut = async { + loop { + class.wait_connection().await; + info!("Connected"); + let _ = echo(&mut class).await; + info!("Disconnected"); + } + }; + + join(usb_fut, echo_fut).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + info!("data: {:x}", data); + class.write_packet(data).await?; + } +} From d6a31dd55c47370ee1984fd83bc9c5c0e7f9cbb9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 14 Jan 2024 23:02:19 +0100 Subject: [PATCH 258/760] Release embassy-usb-logger v0.1.0 --- embassy-usb-logger/Cargo.toml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index c8b06fb06..cb23fed1b 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -2,6 +2,12 @@ name = "embassy-usb-logger" version = "0.1.0" edition = "2021" +license = "MIT OR Apache-2.0" +description = "`log` implementation for USB serial using `embassy-usb`." +keywords = ["embedded", "log", "usb", "hal", "serial"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-usb-logger" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-logger-v$VERSION/embassy-usb/src/" @@ -12,7 +18,4 @@ target = "thumbv7em-none-eabi" embassy-usb = { version = "0.1.0", path = "../embassy-usb" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -futures = { version = "0.3", default-features = false } -static_cell = { version = "2" } -usbd-hid = "0.6.0" log = "0.4" From 583555bc8ae58f615bff000277220d043eeb9827 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 14 Jan 2024 23:20:51 +0100 Subject: [PATCH 259/760] Suppress "unused" warnings. --- embassy-stm32/src/usb/usb.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 364076739..f39915906 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -13,7 +13,6 @@ use embassy_usb_driver::{ }; use super::{DmPin, DpPin, Instance}; -use crate::gpio::sealed::AFType; use crate::interrupt::typelevel::Interrupt; use crate::pac::usb::regs; use crate::pac::usb::vals::{EpType, Stat}; @@ -287,10 +286,12 @@ impl<'d, T: Instance> Driver<'d, T> { regs.btable().write(|w| w.set_btable(0)); #[cfg(not(stm32l1))] - dp.set_as_af(dp.af_num(), AFType::OutputPushPull); - - #[cfg(not(stm32l1))] - dm.set_as_af(dm.af_num(), AFType::OutputPushPull); + { + dp.set_as_af(dp.af_num(), crate::gpio::sealed::AFType::OutputPushPull); + dm.set_as_af(dm.af_num(), crate::gpio::sealed::AFType::OutputPushPull); + } + #[cfg(stm32l1)] + let _ = (dp, dm); // suppress "unused" warnings. // Initialize the bus so that it signals that power is available BUS_WAKER.wake(); From 4e2361c024187d2ddba8596b05f013ad8a52a28c Mon Sep 17 00:00:00 2001 From: shufps Date: Sun, 14 Jan 2024 22:31:19 +0100 Subject: [PATCH 260/760] adds timer-driver for tim21 and tim22 (on L0) --- embassy-stm32/Cargo.toml | 4 ++++ embassy-stm32/build.rs | 6 ++++++ embassy-stm32/src/time_driver.rs | 24 ++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index f1539229f..1280f372e 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -139,6 +139,10 @@ time-driver-tim11 = ["_time-driver"] time-driver-tim12 = ["_time-driver"] ## Use TIM15 as time driver time-driver-tim15 = ["_time-driver"] +## Use TIM21 as time driver +time-driver-tim22 = ["_time-driver"] +## Use TIM22 as time driver +time-driver-tim22 = ["_time-driver"] #! ## Analog Switch Pins (Pxy_C) on STM32H7 series diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ef152acd1..948ce3aff 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -191,6 +191,8 @@ fn main() { Some("tim11") => "TIM11", Some("tim12") => "TIM12", Some("tim15") => "TIM15", + Some("tim21") => "TIM21", + Some("tim22") => "TIM22", Some("any") => { if singletons.contains(&"TIM2".to_string()) { "TIM2" @@ -208,6 +210,10 @@ fn main() { "TIM12" } else if singletons.contains(&"TIM15".to_string()) { "TIM15" + } else if singletons.contains(&"TIM21".to_string()) { + "TIM21" + } else if singletons.contains(&"TIM22".to_string()) { + "TIM22" } else { panic!("time-driver-any requested, but the chip doesn't have TIM2, TIM3, TIM4, TIM5, TIM9, TIM11, TIM12 or TIM15.") } diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 0dbadce0c..d613394ef 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -28,10 +28,10 @@ use crate::{interrupt, peripherals}; // available after reserving CC1 for regular time keeping. For example, TIM2 has four CC registers: // CC1, CC2, CC3, and CC4, so it can provide ALARM_COUNT = 3. -#[cfg(not(any(time_driver_tim12, time_driver_tim15)))] +#[cfg(not(any(time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22)))] const ALARM_COUNT: usize = 3; -#[cfg(any(time_driver_tim12, time_driver_tim15))] +#[cfg(any(time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] const ALARM_COUNT: usize = 1; #[cfg(time_driver_tim2)] @@ -50,6 +50,10 @@ type T = peripherals::TIM11; type T = peripherals::TIM12; #[cfg(time_driver_tim15)] type T = peripherals::TIM15; +#[cfg(time_driver_tim21)] +type T = peripherals::TIM21; +#[cfg(time_driver_tim22)] +type T = peripherals::TIM22; foreach_interrupt! { (TIM2, timer, $block:ident, UP, $irq:ident) => { @@ -116,6 +120,22 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; + (TIM21, timer, $block:ident, UP, $irq:ident) => { + #[cfg(time_driver_tim21)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; + (TIM22, timer, $block:ident, UP, $irq:ident) => { + #[cfg(time_driver_tim22)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; } // Clock timekeeping works with something we call "periods", which are time intervals From 2b649136644eb49b8c22c3b1ddb98bcd6d043b3f Mon Sep 17 00:00:00 2001 From: shufps Date: Sun, 14 Jan 2024 22:48:50 +0100 Subject: [PATCH 261/760] fixed tim21 --- embassy-stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 1280f372e..865970dfb 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -140,7 +140,7 @@ time-driver-tim12 = ["_time-driver"] ## Use TIM15 as time driver time-driver-tim15 = ["_time-driver"] ## Use TIM21 as time driver -time-driver-tim22 = ["_time-driver"] +time-driver-tim21 = ["_time-driver"] ## Use TIM22 as time driver time-driver-tim22 = ["_time-driver"] From e969b88e5ae1aa439b47f7b55e740d6ca78b9a0a Mon Sep 17 00:00:00 2001 From: shufps Date: Mon, 15 Jan 2024 11:23:41 +0100 Subject: [PATCH 262/760] fixed trailing white spaces --- embassy-stm32/src/time_driver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index d613394ef..320b29ddb 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -127,7 +127,7 @@ foreach_interrupt! { fn $irq() { DRIVER.on_interrupt() } - }; + }; (TIM22, timer, $block:ident, UP, $irq:ident) => { #[cfg(time_driver_tim22)] #[cfg(feature = "rt")] @@ -135,7 +135,7 @@ foreach_interrupt! { fn $irq() { DRIVER.on_interrupt() } - }; + }; } // Clock timekeeping works with something we call "periods", which are time intervals From b825f76c285cc7dae518f67506f0cc0fdc6d540a Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 16 Jan 2024 20:00:39 -0800 Subject: [PATCH 263/760] add extra info to stable arena usage --- docs/modules/ROOT/pages/faq.adoc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index b33623053..147f119b0 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -158,8 +158,25 @@ Note that the git revision should match any other embassy patches or git depende When you aren't using the `nightly` feature of `embassy-executor`, the executor uses a bump allocator, which may require configuration. +Something like this error will occur at **compile time** if the task arena is *too large* for the target's RAM: + +[source,plain] +---- +rust-lld: error: section '.bss' will not fit in region 'RAM': overflowed by _ bytes +rust-lld: error: section '.uninit' will not fit in region 'RAM': overflowed by _ bytes +---- + +And this message will appear at **runtime** if the task arena is *too small* for the tasks running: + +[source,plain] +---- +ERROR panicked at 'embassy-executor: task arena is full. You must increase the arena size, see the documentation for details: https://docs.embassy.dev/embassy-executor/' +---- + +NOTE: If all tasks are spawned at startup, this panic will occur immediately. + Check out link:https://docs.embassy.dev/embassy-executor/git/cortex-m/index.html#task-arena[Task Arena Documentation] for more details. == Can I use manual ISRs alongside Embassy? -Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task” flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project]. \ No newline at end of file +Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task” flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project]. From 3c2a954d1b393644e7a8db7cc6460e739ad2109d Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 17 Jan 2024 16:09:59 +0100 Subject: [PATCH 264/760] Pin dep to work around regression --- embassy-stm32-wpan/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 4f53a400a..fe6b968ef 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -34,7 +34,9 @@ aligned = "0.4.1" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } -stm32wb-hci = { version = "0.17.0", optional = true } +# NOTE: pinned to avoid regression: +# https://github.com/OueslatiGhaith/stm32wb-hci/issues/8 +stm32wb-hci = { version = "=0.17.0", optional = true } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } bitflags = { version = "2.3.3", optional = true } From c1760a8a073fd1d22ec4252a7809e09a341e114f Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 17 Jan 2024 17:51:44 +0100 Subject: [PATCH 265/760] Revert "stm32-wpan: Pin dep to work around regression" --- embassy-stm32-wpan/Cargo.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index fe6b968ef..4f53a400a 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -34,9 +34,7 @@ aligned = "0.4.1" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } -# NOTE: pinned to avoid regression: -# https://github.com/OueslatiGhaith/stm32wb-hci/issues/8 -stm32wb-hci = { version = "=0.17.0", optional = true } +stm32wb-hci = { version = "0.17.0", optional = true } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } bitflags = { version = "2.3.3", optional = true } From 9fd49fb9d675f858691491a57ab50dd049168def Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 19 Dec 2023 00:11:35 +0100 Subject: [PATCH 266/760] Add a basic "read to break" function --- embassy-rp/src/uart/mod.rs | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 99fce0fc9..3488d6c73 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -443,6 +443,90 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { } unreachable!("unrecognized rx error"); } + + pub async fn read_to_break<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], Error> { + // clear error flags before we drain the fifo. errors that have accumulated + // in the flags will also be present in the fifo. + T::dma_state().rx_errs.store(0, Ordering::Relaxed); + T::regs().uarticr().write(|w| { + w.set_oeic(true); + w.set_beic(true); + w.set_peic(true); + w.set_feic(true); + }); + + // then drain the fifo. we need to read at most 32 bytes. errors that apply + // to fifo bytes will be reported directly. + let sbuffer = match { + let limit = buffer.len().min(32); + self.drain_fifo(&mut buffer[0..limit]) + } { + Ok(len) if len < buffer.len() => &mut buffer[len..], + Ok(_) => return Ok(buffer), + Err(e) => return Err(e), + }; + + // start a dma transfer. if errors have happened in the interim some error + // interrupt flags will have been raised, and those will be picked up immediately + // by the interrupt handler. + let mut ch = self.rx_dma.as_mut().unwrap(); + T::regs().uartimsc().write_set(|w| { + w.set_oeim(true); + w.set_beim(true); + w.set_peim(true); + w.set_feim(true); + }); + T::regs().uartdmacr().write_set(|reg| { + reg.set_rxdmae(true); + reg.set_dmaonerr(true); + }); + let transfer = unsafe { + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ) + }; + + // wait for either the transfer to complete or an error to happen. + let transfer_result = select( + transfer, + poll_fn(|cx| { + T::dma_state().rx_err_waker.register(cx.waker()); + match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { + 0 => Poll::Pending, + e => Poll::Ready(Uartris(e as u32)), + } + }), + ) + .await; + + let errors = match transfer_result { + Either::First(()) => return Ok(buffer), + Either::Second(e) => e, + }; + + if errors.0 == 0 { + return Ok(buffer); + } else if errors.oeris() { + return Err(Error::Overrun); + } else if errors.beris() { + // Begin "James is a chicken" region - I'm not certain if there is ever + // a case where the write addr WOULDN'T exist between the start and end. + // This assert checks that and hasn't fired (yet). + let sval = buffer.as_ptr() as usize; + let eval = sval + buffer.len(); + // Note: the `write_addr()` is where the NEXT write would be, BUT we also + // received one extra byte that represents the line break. + let val = ch.regs().write_addr().read() as usize - 1; + assert!((val >= sval) && (val <= eval)); + let taken = val - sval; + return Ok(&mut buffer[..taken]); + } else if errors.peris() { + return Err(Error::Parity); + } else if errors.feris() { + return Err(Error::Framing); + } + unreachable!("unrecognized rx error"); + } } impl<'d, T: Instance> Uart<'d, T, Blocking> { @@ -743,6 +827,10 @@ impl<'d, T: Instance> Uart<'d, T, Async> { pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.read(buffer).await } + + pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a mut [u8], Error> { + self.rx.read_to_break(buf).await + } } impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read for UartRx<'d, T, M> { From 24fc12667dc3b929d4fef633cdf0c1ada9765484 Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 20 Dec 2023 14:14:14 +0100 Subject: [PATCH 267/760] Update with more docs and less panics --- embassy-rp/src/uart/mod.rs | 118 +++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 23 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 3488d6c73..a89cb5932 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -116,6 +116,10 @@ pub enum Error { Parity, /// Triggered when the received character didn't have a valid stop bit. Framing, + /// There was an issue when calculating the number of transferred items + /// in an aborted DMA transaction. This is likely an error in the + /// driver implementation, please open an embassy issue. + Calculation, } /// Internal DMA state of UART RX. @@ -275,13 +279,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { /// Read from UART RX blocking execution until done. pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { while buffer.len() > 0 { - let received = self.drain_fifo(buffer)?; + let received = self.drain_fifo(buffer).map_err(|(_i, e)| e)?; buffer = &mut buffer[received..]; } Ok(()) } - fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result { + fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result { let r = T::regs(); for (i, b) in buffer.iter_mut().enumerate() { if r.uartfr().read().rxfe() { @@ -291,13 +295,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { let dr = r.uartdr().read(); if dr.oe() { - return Err(Error::Overrun); + return Err((i, Error::Overrun)); } else if dr.be() { - return Err(Error::Break); + return Err((i, Error::Break)); } else if dr.pe() { - return Err(Error::Parity); + return Err((i, Error::Parity)); } else if dr.fe() { - return Err(Error::Framing); + return Err((i, Error::Framing)); } else { *b = dr.data(); } @@ -389,7 +393,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { } { Ok(len) if len < buffer.len() => &mut buffer[len..], Ok(_) => return Ok(()), - Err(e) => return Err(e), + Err((_i, e)) => return Err(e), }; // start a dma transfer. if errors have happened in the interim some error @@ -425,14 +429,33 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { ) .await; + let mut did_finish = false; let errors = match transfer_result { - Either::First(()) => return Ok(()), - Either::Second(e) => e, + Either::First(()) => { + // We're here because the DMA finished, BUT if an error occurred on the LAST + // byte, then we may still need to grab the error state! + did_finish = true; + Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) + } + Either::Second(e) => { + // We're here because we errored, which means this is the error that + // was problematic. + e + } }; + // If we got no error, just return at this point if errors.0 == 0 { return Ok(()); - } else if errors.oeris() { + } + + // If we DID get an error, and DID finish, we'll have one error byte left in the FIFO. + // Pop it since we are reporting the error on THIS transaction. + if did_finish { + let _ = T::regs().uartdr().read(); + } + + if errors.oeris() { return Err(Error::Overrun); } else if errors.beris() { return Err(Error::Break); @@ -444,6 +467,14 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { unreachable!("unrecognized rx error"); } + /// Read from the UART, until one of the following occurs: + /// + /// * We read `buffer.len()` bytes without a line break + /// * returns `Ok(buffer)` + /// * We read `n` bytes then a line break occurs + /// * returns `Ok(&mut buffer[..n])` + /// * We encounter some error OTHER than a line break + /// * returns `Err(Error)` pub async fn read_to_break<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], Error> { // clear error flags before we drain the fifo. errors that have accumulated // in the flags will also be present in the fifo. @@ -461,9 +492,14 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { let limit = buffer.len().min(32); self.drain_fifo(&mut buffer[0..limit]) } { + // Drained fifo, still some room left! Ok(len) if len < buffer.len() => &mut buffer[len..], + // Drained (some/all of the fifo), no room left Ok(_) => return Ok(buffer), - Err(e) => return Err(e), + // We got a break WHILE draining the FIFO, return what we did get before the break + Err((i, Error::Break)) => return Ok(&mut buffer[..i]), + // Some other error, just return the error + Err((_i, e)) => return Err(e), }; // start a dma transfer. if errors have happened in the interim some error @@ -499,27 +535,62 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { ) .await; + let mut did_finish = false; + + // Figure out our error state let errors = match transfer_result { - Either::First(()) => return Ok(buffer), - Either::Second(e) => e, + Either::First(()) => { + // We're here because the DMA finished, BUT if an error occurred on the LAST + // byte, then we may still need to grab the error state! + did_finish = true; + Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) + } + Either::Second(e) => { + // We're here because we errored, which means this is the error that + // was problematic. + e + } }; if errors.0 == 0 { + // No errors? That means we filled the buffer without a line break. return Ok(buffer); - } else if errors.oeris() { - return Err(Error::Overrun); } else if errors.beris() { - // Begin "James is a chicken" region - I'm not certain if there is ever - // a case where the write addr WOULDN'T exist between the start and end. - // This assert checks that and hasn't fired (yet). + // We got a Line Break! By this point, we've finished/aborted the DMA + // transaction, which means that we need to figure out where it left off + // by looking at the write_addr. + // + // First, we do a sanity check to make sure the write value is within the + // range of DMA we just did. let sval = buffer.as_ptr() as usize; let eval = sval + buffer.len(); - // Note: the `write_addr()` is where the NEXT write would be, BUT we also - // received one extra byte that represents the line break. - let val = ch.regs().write_addr().read() as usize - 1; - assert!((val >= sval) && (val <= eval)); - let taken = val - sval; + + // Note: the `write_addr()` is where the NEXT write would be. + let mut last_written = ch.regs().write_addr().read() as usize; + + // Did we finish the whole DMA transfer? + if !did_finish { + // No, we did not! We stopped because we got a line break. That means the + // DMA transferred one "garbage byte" from the FIFO that held an error. + last_written -= 1; + } else { + // We did finish and got a "late break", where the interrupt error fired AFTER + // we got the last byte. Pop that from the FIFO so we don't trip on it next time. + let dr = T::regs().uartdr().read(); + if !dr.be() { + // Got an error after DMA but no error in the FIFO? + return Err(Error::Calculation); + } + } + + // If we DON'T end up inside the range, something has gone really wrong. + if (last_written < sval) || (last_written > eval) { + return Err(Error::Calculation); + } + let taken = last_written - sval; return Ok(&mut buffer[..taken]); + } else if errors.oeris() { + return Err(Error::Overrun); } else if errors.peris() { return Err(Error::Parity); } else if errors.feris() { @@ -930,6 +1001,7 @@ impl embedded_hal_nb::serial::Error for Error { Self::Break => embedded_hal_nb::serial::ErrorKind::Other, Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, + Self::Calculation => embedded_hal_nb::serial::ErrorKind::Other, } } } From fe172109be8644b1e0d86735f4bd267ef7180c36 Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 20 Dec 2023 14:17:24 +0100 Subject: [PATCH 268/760] A little more cleanup --- embassy-rp/src/uart/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index a89cb5932..998f7ccac 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -278,13 +278,16 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { /// Read from UART RX blocking execution until done. pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { - while buffer.len() > 0 { + while !buffer.is_empty() { let received = self.drain_fifo(buffer).map_err(|(_i, e)| e)?; buffer = &mut buffer[received..]; } Ok(()) } + /// Returns Ok(len) if no errors occurred. Returns Err((len, err)) if an error was + /// encountered. in both cases, `len` is the number of *good* bytes copied into + /// `buffer`. fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result { let r = T::regs(); for (i, b) in buffer.iter_mut().enumerate() { From 94290981c359cfc4bb2355055a8a5d1497cf09aa Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 20 Dec 2023 17:06:57 +0100 Subject: [PATCH 269/760] Debugging RSR --- embassy-rp/src/uart/mod.rs | 128 +++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 48 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 998f7ccac..61d3af5de 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -116,10 +116,16 @@ pub enum Error { Parity, /// Triggered when the received character didn't have a valid stop bit. Framing, - /// There was an issue when calculating the number of transferred items - /// in an aborted DMA transaction. This is likely an error in the - /// driver implementation, please open an embassy issue. - Calculation, +} + +/// Read To Break error +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum ReadToBreakError { + /// Read this many bytes, but never received a line break. + MissingBreak(usize), + Other(Error), } /// Internal DMA state of UART RX. @@ -432,12 +438,10 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { ) .await; - let mut did_finish = false; let errors = match transfer_result { Either::First(()) => { // We're here because the DMA finished, BUT if an error occurred on the LAST // byte, then we may still need to grab the error state! - did_finish = true; Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) } Either::Second(e) => { @@ -452,12 +456,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { return Ok(()); } - // If we DID get an error, and DID finish, we'll have one error byte left in the FIFO. - // Pop it since we are reporting the error on THIS transaction. - if did_finish { - let _ = T::regs().uartdr().read(); - } - + // If we DID get an error, we need to figure out which one it was. if errors.oeris() { return Err(Error::Overrun); } else if errors.beris() { @@ -470,15 +469,27 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { unreachable!("unrecognized rx error"); } - /// Read from the UART, until one of the following occurs: + /// Read from the UART, waiting for a line break. + /// + /// We read until one of the following occurs: /// /// * We read `buffer.len()` bytes without a line break - /// * returns `Ok(buffer)` + /// * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))` /// * We read `n` bytes then a line break occurs - /// * returns `Ok(&mut buffer[..n])` + /// * returns `Ok(n)` /// * We encounter some error OTHER than a line break - /// * returns `Err(Error)` - pub async fn read_to_break<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], Error> { + /// * returns `Err(ReadToBreakError::Other(error))` + /// + /// **NOTE**: you MUST provide a buffer one byte larger than your largest expected + /// message to reliably detect the framing on one single call to `read_to_break()`. + /// + /// * If you expect a message of 20 bytes + line break, and provide a 20-byte buffer: + /// * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))` + /// * The next call to `read_to_break()` will immediately return `Ok(0)`, from the "stale" line break + /// * If you expect a message of 20 bytes + line break, and provide a 21-byte buffer: + /// * The first call to `read_to_break()` will return `Ok(20)`. + /// * The next call to `read_to_break()` will work as expected + pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result { // clear error flags before we drain the fifo. errors that have accumulated // in the flags will also be present in the fifo. T::dma_state().rx_errs.store(0, Ordering::Relaxed); @@ -498,11 +509,11 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // Drained fifo, still some room left! Ok(len) if len < buffer.len() => &mut buffer[len..], // Drained (some/all of the fifo), no room left - Ok(_) => return Ok(buffer), + Ok(len) => return Err(ReadToBreakError::MissingBreak(len)), // We got a break WHILE draining the FIFO, return what we did get before the break - Err((i, Error::Break)) => return Ok(&mut buffer[..i]), + Err((i, Error::Break)) => return Ok(i), // Some other error, just return the error - Err((_i, e)) => return Err(e), + Err((_i, e)) => return Err(ReadToBreakError::Other(e)), }; // start a dma transfer. if errors have happened in the interim some error @@ -538,14 +549,11 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { ) .await; - let mut did_finish = false; - // Figure out our error state let errors = match transfer_result { Either::First(()) => { // We're here because the DMA finished, BUT if an error occurred on the LAST // byte, then we may still need to grab the error state! - did_finish = true; Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) } Either::Second(e) => { @@ -557,7 +565,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { if errors.0 == 0 { // No errors? That means we filled the buffer without a line break. - return Ok(buffer); + // For THIS function, that's a problem. + return Err(ReadToBreakError::MissingBreak(buffer.len())); } else if errors.beris() { // We got a Line Break! By this point, we've finished/aborted the DMA // transaction, which means that we need to figure out where it left off @@ -568,36 +577,60 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { let sval = buffer.as_ptr() as usize; let eval = sval + buffer.len(); - // Note: the `write_addr()` is where the NEXT write would be. - let mut last_written = ch.regs().write_addr().read() as usize; + // Note: the `write_addr()` is where the NEXT write would be, but we ALSO + // got a line break, so take an offset of 1 + let mut next_addr = ch.regs().write_addr().read() as usize; - // Did we finish the whole DMA transfer? - if !did_finish { - // No, we did not! We stopped because we got a line break. That means the - // DMA transferred one "garbage byte" from the FIFO that held an error. - last_written -= 1; - } else { - // We did finish and got a "late break", where the interrupt error fired AFTER - // we got the last byte. Pop that from the FIFO so we don't trip on it next time. - let dr = T::regs().uartdr().read(); - if !dr.be() { - // Got an error after DMA but no error in the FIFO? - return Err(Error::Calculation); + // If we DON'T end up inside the range, something has gone really wrong. + if (next_addr < sval) || (next_addr > eval) { + unreachable!("UART DMA reported invalid `write_addr`"); + } + + // If we finished the full DMA, AND the FIFO is not-empty, AND that + // byte reports a break error, THAT byte caused the error, and not data + // in the DMA transfer! Otherwise: our DMA grabbed one "bad" byte. + // + // Note: even though we COULD detect this and return `Ok(buffer.len())`, + // we DON'T, as that is racy: if we read the error state AFTER the data + // was transferred but BEFORE the line break interrupt fired, we'd return + // `MissingBreak`. Ignoring the fact that there's a line break in the FIFO + // means callers consistently see the same error regardless of + let regs = T::regs(); + let is_end = next_addr == eval; + let not_empty = !regs.uartfr().read().rxfe(); + let is_break = regs.uartrsr().read().be(); + let last_good = is_end && not_empty && is_break; + + defmt::println!("next: {=usize}, sval: {=usize}, eval: {=usize}", next_addr, sval, eval); + defmt::println!("lg: {=bool}, is_end: {=bool}, not_empty: {=bool}, is_break: {=bool}", last_good, is_end, not_empty, is_break); + + if is_end && not_empty && !is_break { + let val = regs.uartdr().read(); + let tb = regs.uartrsr().read().be(); + let te = regs.uartfr().read().rxfe(); + defmt::println!("THEN: {=bool}, {=bool}", tb, te); + if val.be() { + panic!("Oh what the hell"); } } - // If we DON'T end up inside the range, something has gone really wrong. - if (last_written < sval) || (last_written > eval) { - return Err(Error::Calculation); + if !last_good { + defmt::println!("Last not good!"); + // The last is NOT good (it's the line-break `0x00`), so elide it + next_addr -= 1; + } else { + defmt::println!("last good!"); } - let taken = last_written - sval; - return Ok(&mut buffer[..taken]); + + defmt::println!("->{=usize}", next_addr - sval); + + return Ok(next_addr - sval); } else if errors.oeris() { - return Err(Error::Overrun); + return Err(ReadToBreakError::Other(Error::Overrun)); } else if errors.peris() { - return Err(Error::Parity); + return Err(ReadToBreakError::Other(Error::Parity)); } else if errors.feris() { - return Err(Error::Framing); + return Err(ReadToBreakError::Other(Error::Framing)); } unreachable!("unrecognized rx error"); } @@ -902,7 +935,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> { self.rx.read(buffer).await } - pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a mut [u8], Error> { + pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result { self.rx.read_to_break(buf).await } } @@ -1004,7 +1037,6 @@ impl embedded_hal_nb::serial::Error for Error { Self::Break => embedded_hal_nb::serial::ErrorKind::Other, Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, - Self::Calculation => embedded_hal_nb::serial::ErrorKind::Other, } } } From 1ce96f79fb356b29b882a3571415f347e48e89c9 Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 20 Dec 2023 17:27:58 +0100 Subject: [PATCH 270/760] Fun Learning about the RP2040 UART impl! --- embassy-rp/src/uart/mod.rs | 77 +++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 61d3af5de..a9ae6c3f4 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -577,54 +577,55 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { let sval = buffer.as_ptr() as usize; let eval = sval + buffer.len(); - // Note: the `write_addr()` is where the NEXT write would be, but we ALSO - // got a line break, so take an offset of 1 - let mut next_addr = ch.regs().write_addr().read() as usize; + // This is the address where the DMA would write to next + let next_addr = ch.regs().write_addr().read() as usize; // If we DON'T end up inside the range, something has gone really wrong. + // Note that it's okay that `eval` is one past the end of the slice, as + // this is where the write pointer will end up at the end of a full + // transfer. if (next_addr < sval) || (next_addr > eval) { unreachable!("UART DMA reported invalid `write_addr`"); } - // If we finished the full DMA, AND the FIFO is not-empty, AND that - // byte reports a break error, THAT byte caused the error, and not data - // in the DMA transfer! Otherwise: our DMA grabbed one "bad" byte. - // - // Note: even though we COULD detect this and return `Ok(buffer.len())`, - // we DON'T, as that is racy: if we read the error state AFTER the data - // was transferred but BEFORE the line break interrupt fired, we'd return - // `MissingBreak`. Ignoring the fact that there's a line break in the FIFO - // means callers consistently see the same error regardless of let regs = T::regs(); - let is_end = next_addr == eval; - let not_empty = !regs.uartfr().read().rxfe(); - let is_break = regs.uartrsr().read().be(); - let last_good = is_end && not_empty && is_break; + let all_full = next_addr == eval; - defmt::println!("next: {=usize}, sval: {=usize}, eval: {=usize}", next_addr, sval, eval); - defmt::println!("lg: {=bool}, is_end: {=bool}, not_empty: {=bool}, is_break: {=bool}", last_good, is_end, not_empty, is_break); + // NOTE: This is off label usage of RSR! See the issue below for + // why I am not checking if there is an "extra" FIFO byte, and why + // I am checking RSR directly (it seems to report the status of the LAST + // POPPED value, rather than the NEXT TO POP value like the datasheet + // suggests!) + // + // issue: https://github.com/raspberrypi/pico-feedback/issues/367 + let last_was_break = regs.uartrsr().read().be(); - if is_end && not_empty && !is_break { - let val = regs.uartdr().read(); - let tb = regs.uartrsr().read().be(); - let te = regs.uartfr().read().rxfe(); - defmt::println!("THEN: {=bool}, {=bool}", tb, te); - if val.be() { - panic!("Oh what the hell"); + return match (all_full, last_was_break) { + (true, true) | (false, _) => { + // We got less than the full amount + a break, or the full amount + // and the last byte was a break. Subtract the break off. + Ok((next_addr - 1) - sval) } - } - - if !last_good { - defmt::println!("Last not good!"); - // The last is NOT good (it's the line-break `0x00`), so elide it - next_addr -= 1; - } else { - defmt::println!("last good!"); - } - - defmt::println!("->{=usize}", next_addr - sval); - - return Ok(next_addr - sval); + (true, false) => { + // We finished the whole DMA, and the last DMA'd byte was NOT a break + // character. This is an error. + // + // NOTE: we COULD potentially return Ok(buffer.len()) here, since we + // know a line break occured at SOME POINT after the DMA completed. + // + // However, we have no way of knowing if there was extra data BEFORE + // that line break, so instead return an Err to signal to the caller + // that there are "leftovers", and they'll catch the actual line break + // on the next call. + // + // Doing it like this also avoids racyness: now whether you finished + // the full read BEFORE the line break occurred or AFTER the line break + // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes + // getting `Ok(buffer.len())` if you were "late enough" to observe the + // line break. + Err(ReadToBreakError::MissingBreak(buffer.len())) + } + }; } else if errors.oeris() { return Err(ReadToBreakError::Other(Error::Overrun)); } else if errors.peris() { From 5e08bb8bc3a7e0e308cbada03c9c363cdf5223b9 Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 19 Jan 2024 15:46:36 +0100 Subject: [PATCH 271/760] A rebase ate my doc comment! --- embassy-rp/src/uart/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index a9ae6c3f4..9f5ba4e8a 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -125,6 +125,7 @@ pub enum Error { pub enum ReadToBreakError { /// Read this many bytes, but never received a line break. MissingBreak(usize), + /// Other, standard issue with the serial request Other(Error), } @@ -936,6 +937,9 @@ impl<'d, T: Instance> Uart<'d, T, Async> { self.rx.read(buffer).await } + /// Read until the buffer is full or a line break occurs. + /// + /// See [`UartRx::read_to_break()`] for more details pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result { self.rx.read_to_break(buf).await } From 5e158757b9922bff178541f8a50a3e87be8c1c2d Mon Sep 17 00:00:00 2001 From: "Christopher N. Hesse" Date: Mon, 15 Jan 2024 12:05:55 +0100 Subject: [PATCH 272/760] Add more fields to the BssInfo packet struct Taken from the Infineon WHD repository: https://github.com/Infineon/wifi-host-driver/blob/04ee318cc96bffa7d69a1e076c008e2364453f82/WiFi_Host_Driver/inc/whd_types.h#L814 Signed-off-by: Christopher N. Hesse --- cyw43/src/structs.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs index 5ea62d95b..ae7ef6038 100644 --- a/cyw43/src/structs.rs +++ b/cyw43/src/structs.rs @@ -491,6 +491,44 @@ pub struct BssInfo { pub ssid_len: u8, /// SSID. pub ssid: [u8; 32], + reserved1: [u8; 1], + /// Number of rates in the rates field. + pub rateset_count: u32, + /// Rates in 500kpbs units. + pub rates: [u8; 16], + /// Channel specification. + pub chanspec: u16, + /// Announcement traffic indication message. + pub atim_window: u16, + /// Delivery traffic indication message. + pub dtim_period: u8, + reserved2: [u8; 1], + /// Receive signal strength (in dbM). + pub rssi: i16, + /// Received noise (in dbM). + pub phy_noise: i8, + /// 802.11n capability. + pub n_cap: u8, + reserved3: [u8; 2], + /// 802.11n BSS capabilities. + pub nbss_cap: u32, + /// 802.11n control channel number. + pub ctl_ch: u8, + reserved4: [u8; 3], + reserved32: [u32; 1], + /// Flags. + pub flags: u8, + /// VHT capability. + pub vht_cap: u8, + reserved5: [u8; 2], + /// 802.11n BSS required MCS. + pub basic_mcs: [u8; 16], + /// Information Elements (IE) offset. + pub ie_offset: u16, + /// Length of Information Elements (IE) in bytes. + pub ie_length: u32, + /// Average signal-to-noise (SNR) ratio during frame reception. + pub snr: i16, // there will be more stuff here } impl_bytes!(BssInfo); From 527005324889cc7ebc532e459c7de447336634cc Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Fri, 19 Jan 2024 18:31:14 +0100 Subject: [PATCH 273/760] Fix a typo --- embassy-usb/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-usb/README.md b/embassy-usb/README.md index 7411fcf52..d2adae4f5 100644 --- a/embassy-usb/README.md +++ b/embassy-usb/README.md @@ -9,7 +9,7 @@ Async USB device stack for embedded devices in Rust. - Suspend/resume, remote wakeup. - USB composite devices. - Ergonomic descriptor builder. -- Ready-to-use implementations for a few USB classes (note you can still implement any class yourself oustide the crate). +- Ready-to-use implementations for a few USB classes (note you can still implement any class yourself outside the crate). - Serial ports (CDC ACM) - Ethernet (CDC NCM) - Human Interface Devices (HID) From ace3280b644295549fbc516a7da36407b8b32135 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 28 Nov 2023 17:10:20 +0100 Subject: [PATCH 274/760] stm32/tests: enable f446 hil. --- ci.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/ci.sh b/ci.sh index a1d0c8c26..c7c1755a0 100755 --- a/ci.sh +++ b/ci.sh @@ -222,9 +222,6 @@ rm out/tests/rpi-pico/i2c rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble -# not in CI yet. -rm -rf out/tests/stm32f446re - # unstable, I think it's running out of RAM? rm out/tests/stm32f207zg/eth From d781e231cd8491e1985bf78374ba13038eb64081 Mon Sep 17 00:00:00 2001 From: Harry Brooke Date: Wed, 6 Dec 2023 10:49:28 +0000 Subject: [PATCH 275/760] make usart::State private --- embassy-stm32/src/usart/buffered.rs | 34 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 962547bd7..f8e0bfda5 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -82,23 +82,25 @@ impl interrupt::typelevel::Handler for Interrupt } } -/// Buffered UART State -pub struct State { - rx_waker: AtomicWaker, - rx_buf: RingBuffer, +pub(crate) use sealed::State; +pub(crate) mod sealed { + use super::*; + pub struct State { + pub(crate) rx_waker: AtomicWaker, + pub(crate) rx_buf: RingBuffer, + pub(crate) tx_waker: AtomicWaker, + pub(crate) tx_buf: RingBuffer, + } - tx_waker: AtomicWaker, - tx_buf: RingBuffer, -} - -impl State { - /// Create new state - pub const fn new() -> Self { - Self { - rx_buf: RingBuffer::new(), - tx_buf: RingBuffer::new(), - rx_waker: AtomicWaker::new(), - tx_waker: AtomicWaker::new(), + impl State { + /// Create new state + pub const fn new() -> Self { + Self { + rx_buf: RingBuffer::new(), + tx_buf: RingBuffer::new(), + rx_waker: AtomicWaker::new(), + tx_waker: AtomicWaker::new(), + } } } } From ea0ca181943fb4022c5569bc65de191499d7ac5f Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Sat, 30 Dec 2023 16:54:00 +0100 Subject: [PATCH 276/760] ci.sh: add low-power feature for stm32l5 --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index c7c1755a0..3322c60d1 100755 --- a/ci.sh +++ b/ci.sh @@ -120,7 +120,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,low-power,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32wl54jc-cm0p,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wle5jb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,defmt,exti,time-driver-any,time \ From 6ca43030db125bd440c8e7383a4fc9c93bea7a4e Mon Sep 17 00:00:00 2001 From: umgefahren <55623006+umgefahren@users.noreply.github.com> Date: Fri, 19 Jan 2024 23:49:49 +0100 Subject: [PATCH 277/760] feat: Extended the Scan API --- cyw43/Cargo.toml | 4 +- cyw43/src/control.rs | 93 ++++++++++++++++++++++++++++---- cyw43/src/events.rs | 4 +- examples/rp/src/bin/wifi_scan.rs | 2 +- 4 files changed, 89 insertions(+), 14 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index c857f7378..64c38ea7a 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/cyw43" [features] -defmt = ["dep:defmt"] +defmt = ["dep:defmt", "heapless/defmt-03"] log = ["dep:log"] # Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`. @@ -32,6 +32,8 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa embedded-hal-1 = { package = "embedded-hal", version = "1.0" } num_enum = { version = "0.5.7", default-features = false } +heapless = "0.8.0" + [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 311fcb08c..26d50d311 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -3,7 +3,7 @@ use core::iter::zip; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::{HardwareAddress, LinkState}; -use embassy_time::Timer; +use embassy_time::{Duration, Timer}; use crate::consts::*; use crate::events::{Event, EventSubscriber, Events}; @@ -35,6 +35,45 @@ pub struct Control<'a> { ioctl_state: &'a IoctlState, } +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ScanType { + Active { + /// Period of time to wait on each channel when active scanning. + dwell_time: Option, + }, + Passive { + /// Period of time to wait on each channel when passive scanning. + dwell_time: Option, + }, +} + +#[derive(Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ScanOptions { + pub ssid: Option>, + /// If set to `None`, all APs will be returned. If set to `Some`, only APs + /// with the specified BSSID will be returned. + pub bssid: Option<[u8; 6]>, + /// Number of probes to send on each channel. + pub nprobes: Option, + /// Time to spend waiting on the home channel. + pub home_time: Option, + pub scan_type: ScanType, +} + +impl Default for ScanOptions { + fn default() -> Self { + Self { + ssid: None, + bssid: None, + nprobes: None, + home_time: None, + scan_type: ScanType::Passive { dwell_time: None }, + } + } +} + impl<'a> Control<'a> { pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { Self { @@ -471,22 +510,56 @@ impl<'a> Control<'a> { /// # Note /// Device events are currently implemented using a bounded queue. /// To not miss any events, you should make sure to always await the stream. - pub async fn scan(&mut self) -> Scanner<'_> { + pub async fn scan(&mut self, scan_opts: ScanOptions) -> Scanner<'_> { + const SCANTYPE_ACTIVE: u8 = 0; const SCANTYPE_PASSIVE: u8 = 1; + let mut active_time = !0; + let mut passive_time = !0; + + let scan_type = match scan_opts.scan_type { + ScanType::Active { dwell_time: None } => SCANTYPE_ACTIVE, + ScanType::Active { + dwell_time: Some(dwell_time), + } => { + active_time = dwell_time.as_millis() as u32; + if active_time == !0 { + active_time = !0 - 1; + } + SCANTYPE_ACTIVE + } + ScanType::Passive { dwell_time: None } => SCANTYPE_PASSIVE, + ScanType::Passive { + dwell_time: Some(dwell_time), + } => { + passive_time = dwell_time.as_millis() as u32; + if passive_time == !0 { + passive_time = !0 - 1; + } + SCANTYPE_PASSIVE + } + }; + let scan_params = ScanParams { version: 1, action: 1, sync_id: 1, - ssid_len: 0, - ssid: [0; 32], - bssid: [0xff; 6], + ssid_len: scan_opts.ssid.as_ref().map(|e| e.as_bytes().len() as u32).unwrap_or(0), + ssid: scan_opts + .ssid + .map(|e| { + let mut ssid = [0; 32]; + ssid[..e.as_bytes().len()].copy_from_slice(e.as_bytes()); + ssid + }) + .unwrap_or([0; 32]), + bssid: scan_opts.bssid.unwrap_or([0xff; 6]), bss_type: 2, - scan_type: SCANTYPE_PASSIVE, - nprobes: !0, - active_time: !0, - passive_time: !0, - home_time: !0, + scan_type, + nprobes: scan_opts.nprobes.unwrap_or(!0).into(), + active_time, + passive_time, + home_time: scan_opts.home_time.map(|e| e.as_millis() as u32).unwrap_or(!0), channel_num: 0, channel_list: [0; 1], }; diff --git a/cyw43/src/events.rs b/cyw43/src/events.rs index a94c49a0c..44bfa98e9 100644 --- a/cyw43/src/events.rs +++ b/cyw43/src/events.rs @@ -311,13 +311,13 @@ pub struct Status { pub status: u32, } -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] pub enum Payload { None, BssInfo(BssInfo), } -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] pub struct Message { pub header: Status, diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 45bb5b76c..e678209dd 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -65,7 +65,7 @@ async fn main(spawner: Spawner) { .set_power_management(cyw43::PowerManagementMode::PowerSave) .await; - let mut scanner = control.scan().await; + let mut scanner = control.scan(Default::default()).await; while let Some(bss) = scanner.next().await { if let Ok(ssid_str) = str::from_utf8(&bss.ssid) { info!("scanned {} == {:x}", ssid_str, bss.bssid); From 24968629ec810b844b819e8f84baab2a9349ed2f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 20 Jan 2024 00:10:35 +0100 Subject: [PATCH 278/760] cyw43: Unify dwell time. --- cyw43/Cargo.toml | 2 +- cyw43/src/control.rs | 48 ++++++++++++++++++++------------------------ 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 64c38ea7a..f279739e4 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/cyw43" [features] -defmt = ["dep:defmt", "heapless/defmt-03"] +defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt"] log = ["dep:log"] # Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`. diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 26d50d311..135b8c245 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -38,14 +38,8 @@ pub struct Control<'a> { #[derive(Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ScanType { - Active { - /// Period of time to wait on each channel when active scanning. - dwell_time: Option, - }, - Passive { - /// Period of time to wait on each channel when passive scanning. - dwell_time: Option, - }, + Active, + Passive, } #[derive(Clone)] @@ -59,7 +53,10 @@ pub struct ScanOptions { pub nprobes: Option, /// Time to spend waiting on the home channel. pub home_time: Option, + /// Scan type: active or passive. pub scan_type: ScanType, + /// Period of time to wait on each channel when passive scanning. + pub dwell_time: Option, } impl Default for ScanOptions { @@ -69,7 +66,8 @@ impl Default for ScanOptions { bssid: None, nprobes: None, home_time: None, - scan_type: ScanType::Passive { dwell_time: None }, + scan_type: ScanType::Passive, + dwell_time: None, } } } @@ -514,28 +512,26 @@ impl<'a> Control<'a> { const SCANTYPE_ACTIVE: u8 = 0; const SCANTYPE_PASSIVE: u8 = 1; + let dwell_time = match scan_opts.dwell_time { + None => !0, + Some(t) => { + let mut t = t.as_millis() as u32; + if t == !0 { + t = !0 - 1; + } + t + } + }; + let mut active_time = !0; let mut passive_time = !0; - let scan_type = match scan_opts.scan_type { - ScanType::Active { dwell_time: None } => SCANTYPE_ACTIVE, - ScanType::Active { - dwell_time: Some(dwell_time), - } => { - active_time = dwell_time.as_millis() as u32; - if active_time == !0 { - active_time = !0 - 1; - } + ScanType::Active => { + active_time = dwell_time; SCANTYPE_ACTIVE } - ScanType::Passive { dwell_time: None } => SCANTYPE_PASSIVE, - ScanType::Passive { - dwell_time: Some(dwell_time), - } => { - passive_time = dwell_time.as_millis() as u32; - if passive_time == !0 { - passive_time = !0 - 1; - } + ScanType::Passive => { + passive_time = dwell_time; SCANTYPE_PASSIVE } }; From ec47e931acbc4a4b1a9f0781e9317f1e680427eb Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Mon, 8 Jan 2024 17:33:11 +0200 Subject: [PATCH 279/760] stm32: fix buffered uart flush usart_v4 uses internal FIFO and therefore actually all bytes are not yet sent out although state.tx_buf.is_empty() --- embassy-stm32/src/usart/buffered.rs | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index f8e0bfda5..e050f8e0f 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -1,5 +1,6 @@ use core::future::poll_fn; use core::slice; +use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; @@ -61,6 +62,18 @@ impl interrupt::typelevel::Handler for Interrupt state.rx_waker.wake(); } + // With `usart_v4` hardware FIFO is enabled, making `state.tx_buf` + // insufficient to determine if all bytes are sent out. + // Transmission complete (TC) interrupt here indicates that all bytes are pushed out from the FIFO. + #[cfg(usart_v4)] + if sr_val.tc() { + r.cr1().modify(|w| { + w.set_tcie(false); + }); + state.tx_done.store(true, Ordering::Release); + state.rx_waker.wake(); + } + // TX if sr(r).read().txe() { let mut tx_reader = state.tx_buf.reader(); @@ -69,6 +82,12 @@ impl interrupt::typelevel::Handler for Interrupt r.cr1().modify(|w| { w.set_txeie(true); }); + + #[cfg(usart_v4)] + r.cr1().modify(|w| { + w.set_tcie(true); + }); + tdr(r).write_volatile(buf[0].into()); tx_reader.pop_done(1); state.tx_waker.wake(); @@ -90,6 +109,7 @@ pub(crate) mod sealed { pub(crate) rx_buf: RingBuffer, pub(crate) tx_waker: AtomicWaker, pub(crate) tx_buf: RingBuffer, + pub(crate) tx_done: AtomicBool, } impl State { @@ -100,6 +120,7 @@ pub(crate) mod sealed { tx_buf: RingBuffer::new(), rx_waker: AtomicWaker::new(), tx_waker: AtomicWaker::new(), + tx_done: AtomicBool::new(true), } } } @@ -366,6 +387,8 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { async fn write(&self, buf: &[u8]) -> Result { poll_fn(move |cx| { let state = T::buffered_state(); + state.tx_done.store(false, Ordering::Release); + let empty = state.tx_buf.is_empty(); let mut tx_writer = unsafe { state.tx_buf.writer() }; @@ -391,6 +414,13 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { async fn flush(&self) -> Result<(), Error> { poll_fn(move |cx| { let state = T::buffered_state(); + + #[cfg(usart_v4)] + if !state.tx_done.load(Ordering::Acquire) { + state.tx_waker.register(cx.waker()); + return Poll::Pending; + } + #[cfg(not(usart_v4))] if !state.tx_buf.is_empty() { state.tx_waker.register(cx.waker()); return Poll::Pending; From 17d6e4eefeb9bdc9d7c3776afb815298be5b468c Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Tue, 9 Jan 2024 09:25:10 +0200 Subject: [PATCH 280/760] stm32 uart: do not wake after sending each byte usart_v4 uses TC interrupt to see if all bytes are sent out from the FIFO and waker is called from this interrupt. This minimises unnecessary wakeups during sending. --- embassy-stm32/src/usart/buffered.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index e050f8e0f..211091c38 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -62,8 +62,8 @@ impl interrupt::typelevel::Handler for Interrupt state.rx_waker.wake(); } - // With `usart_v4` hardware FIFO is enabled, making `state.tx_buf` - // insufficient to determine if all bytes are sent out. + // With `usart_v4` hardware FIFO is enabled, making `state.tx_buf` insufficient + // to determine if all bytes are sent out. // Transmission complete (TC) interrupt here indicates that all bytes are pushed out from the FIFO. #[cfg(usart_v4)] if sr_val.tc() { @@ -90,9 +90,12 @@ impl interrupt::typelevel::Handler for Interrupt tdr(r).write_volatile(buf[0].into()); tx_reader.pop_done(1); + + // Notice that in case of `usart_v4` waker is called when TC interrupt happens. + #[cfg(not(usart_v4))] state.tx_waker.wake(); } else { - // Disable interrupt until we have something to transmit again + // Disable interrupt until we have something to transmit again. r.cr1().modify(|w| { w.set_txeie(false); }); From c936d66934225db8ddd283d7da2d7a158686df71 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Tue, 9 Jan 2024 14:47:30 +0200 Subject: [PATCH 281/760] stm32 uart: fix `flush` for non usart_v4 variants Byte was written to TDR and right after that waker was called. This means `flush` would see that `tx_buf` is empty and can return Ready although actually hardware was still writing this last byte to the wire. With this change non `usart_v4 ` variants would also use TC interrupt to check when last byte was sent out. --- embassy-stm32/src/usart/buffered.rs | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 211091c38..52740c13e 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -62,10 +62,9 @@ impl interrupt::typelevel::Handler for Interrupt state.rx_waker.wake(); } - // With `usart_v4` hardware FIFO is enabled, making `state.tx_buf` insufficient - // to determine if all bytes are sent out. - // Transmission complete (TC) interrupt here indicates that all bytes are pushed out from the FIFO. - #[cfg(usart_v4)] + // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC) + // indicates that all bytes are pushed out from the FIFO. + // For other usart variants it shows that last byte from the buffer was just sent. if sr_val.tc() { r.cr1().modify(|w| { w.set_tcie(false); @@ -83,17 +82,15 @@ impl interrupt::typelevel::Handler for Interrupt w.set_txeie(true); }); - #[cfg(usart_v4)] - r.cr1().modify(|w| { - w.set_tcie(true); - }); + // Enable transmission complete interrupt when last byte is going to be sent out. + if buf.len() == 1 { + r.cr1().modify(|w| { + w.set_tcie(true); + }); + } tdr(r).write_volatile(buf[0].into()); tx_reader.pop_done(1); - - // Notice that in case of `usart_v4` waker is called when TC interrupt happens. - #[cfg(not(usart_v4))] - state.tx_waker.wake(); } else { // Disable interrupt until we have something to transmit again. r.cr1().modify(|w| { @@ -418,16 +415,10 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { poll_fn(move |cx| { let state = T::buffered_state(); - #[cfg(usart_v4)] if !state.tx_done.load(Ordering::Acquire) { state.tx_waker.register(cx.waker()); return Poll::Pending; } - #[cfg(not(usart_v4))] - if !state.tx_buf.is_empty() { - state.tx_waker.register(cx.waker()); - return Poll::Pending; - } Poll::Ready(Ok(())) }) From 534c53c901345f8af517b8991a4bcd99d290c11c Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Fri, 19 Jan 2024 19:58:00 +0200 Subject: [PATCH 282/760] stm32 uart: remove unwrap unwraps take more space because of panics --- embassy-stm32/src/usart/buffered.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 52740c13e..abc766bc7 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -47,8 +47,10 @@ impl interrupt::typelevel::Handler for Interrupt let mut rx_writer = state.rx_buf.writer(); let buf = rx_writer.push_slice(); if !buf.is_empty() { - buf[0] = dr.unwrap(); - rx_writer.push_done(1); + if let Some(byte) = dr { + buf[0] = byte; + rx_writer.push_done(1); + } } else { // FIXME: Should we disable any further RX interrupts when the buffer becomes full. } From ec2e3de0f493cd0cc116f5f67a814ae7c457d9b1 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Fri, 19 Jan 2024 20:28:29 +0200 Subject: [PATCH 283/760] stm32 uart: fix buffered flush for usart_v1, usart_v2 There is one caveat. For some reason with first send using usart_v1/usart_v2 TC flag appears right after first byte from buffer is written to DR. Consecutive transfers work as expected - TC flag appears when last byte is fully transferred to wire. --- embassy-stm32/src/usart/buffered.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index abc766bc7..c78752883 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -68,11 +68,16 @@ impl interrupt::typelevel::Handler for Interrupt // indicates that all bytes are pushed out from the FIFO. // For other usart variants it shows that last byte from the buffer was just sent. if sr_val.tc() { + // For others it is cleared above with `clear_interrupt_flags`. + #[cfg(any(usart_v1, usart_v2))] + sr(r).modify(|w| w.set_tc(false)); + r.cr1().modify(|w| { w.set_tcie(false); }); + state.tx_done.store(true, Ordering::Release); - state.rx_waker.wake(); + state.tx_waker.wake(); } // TX From 7696b1c0b8f409fdcd9e171b7e8a51c29661a2da Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 20 Jan 2024 01:47:56 +0100 Subject: [PATCH 284/760] tests/stm32: fix h7 wrong smps config. --- tests/stm32/src/common.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 313380b35..fefe72c86 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -394,6 +394,10 @@ pub fn config() -> Config { config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + #[cfg(any(feature = "stm32h755zi"))] + { + config.rcc.supply_config = SupplyConfig::DirectSMPS; + } } #[cfg(any(feature = "stm32h7a3zi"))] From 69d4b428412fb0252d2a7eb807f3439e999bccfb Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Sat, 20 Jan 2024 16:08:32 +0100 Subject: [PATCH 285/760] add pio_i2s example for RP2040 --- examples/rp/src/bin/pio_i2s.rs | 130 +++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 examples/rp/src/bin/pio_i2s.rs diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs new file mode 100644 index 000000000..66802c8b7 --- /dev/null +++ b/examples/rp/src/bin/pio_i2s.rs @@ -0,0 +1,130 @@ +//! This example shows generating audio and sending it to a connected i2s DAC using the PIO +//! module of the RP2040. +//! +//! Connect the i2s DAC as follows: +//! bclk : GPIO 18 +//! lrc : GPIO 19 +//! din : GPIO 20 +//! Then hold down the boot select button to trigger a rising triangle waveform. + +#![no_std] +#![no_main] + +use core::mem; + +use defmt_rtt as _; +use embassy_executor::Spawner; +use embassy_rp::{ + bind_interrupts, + peripherals::PIO0, + pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}, + Peripheral, +}; +use fixed::traits::ToFixed; +use panic_probe as _; +use static_cell::StaticCell; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +const SAMPLE_RATE: u32 = 48_000; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut p = embassy_rp::init(Default::default()); + + // Setup pio state machine for i2s output + let mut pio = Pio::new(p.PIO0, Irqs); + + #[rustfmt::skip] + let pio_program = pio_proc::pio_asm!( + ".side_set 2", + " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock + "left_data:", + " out pins, 1 side 0b00", + " jmp x-- left_data side 0b01", + " out pins 1 side 0b10", + " set x, 14 side 0b11", + "right_data:", + " out pins 1 side 0b10", + " jmp x-- right_data side 0b11", + " out pins 1 side 0b00", + ); + + let bit_clock_pin = p.PIN_18; + let left_right_clock_pin = p.PIN_19; + let data_pin = p.PIN_20; + + let data_pin = pio.common.make_pio_pin(data_pin); + let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin); + let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin); + + let cfg = { + let mut cfg = Config::default(); + cfg.use_program( + &pio.common.load_program(&pio_program.program), + &[&bit_clock_pin, &left_right_clock_pin], + ); + cfg.set_out_pins(&[&data_pin]); + const BIT_DEPTH: u32 = 16; + const CHANNELS: u32 = 2; + let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS; + cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); + cfg.shift_out = ShiftConfig { + threshold: 32, + direction: ShiftDirection::Left, + auto_fill: true, + }; + // join fifos to have twice the time to start the next dma transfer + cfg.fifo_join = FifoJoin::TxOnly; + cfg + }; + pio.sm0.set_config(&cfg); + pio.sm0.set_pin_dirs( + embassy_rp::pio::Direction::Out, + &[&data_pin, &left_right_clock_pin, &bit_clock_pin], + ); + + // create two audio buffers (back and front) which will take turns being + // filled with new audio data and being sent to the pio fifo using dma + const BUFFER_SIZE: usize = 960; + static DMA_BUFFER: StaticCell<[u32; BUFFER_SIZE * 2]> = StaticCell::new(); + let dma_buffer = DMA_BUFFER.init_with(|| [0u32; BUFFER_SIZE * 2]); + let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE); + + // start pio state machine + pio.sm0.set_enable(true); + let tx = pio.sm0.tx(); + let mut dma_ref = p.DMA_CH0.into_ref(); + + let mut fade_value: i32 = 0; + let mut phase: i32 = 0; + + loop { + // trigger transfer of front buffer data to the pio fifo + // but don't await the returned future, yet + let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer); + + // fade in audio when bootsel is pressed + let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; + + // fill back buffer with fresh audio samples before awaiting the dma future + for s in back_buffer.iter_mut() { + // exponential approach of fade_value => fade_target + fade_value += (fade_target - fade_value) >> 14; + // generate triangle wave with amplitude and frequency based on fade value + phase = (phase + (fade_value >> 22)) & 0xffff; + let triangle_sample = (phase as i16 as i32).abs() - 16384; + let sample = (triangle_sample * (fade_value >> 15)) >> 16; + // duplicate mono sample into lower and upper half of dma word + *s = (sample as u16 as u32) * 0x10001; + } + + // now await the dma future. once the dma finishes, the next buffer needs to be queued + // within DMA_DEPTH / SAMPLE_RATE = 8 / 48000 seconds = 166us + dma_future.await; + mem::swap(&mut back_buffer, &mut front_buffer); + } +} + From 7931fcfb3d3211b9c7e46b43cebe48c433893b15 Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Sat, 20 Jan 2024 16:35:09 +0100 Subject: [PATCH 286/760] fix wrong formatting due to not using nightly rustfmt --- examples/rp/src/bin/pio_i2s.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs index 66802c8b7..cf60e5b30 100644 --- a/examples/rp/src/bin/pio_i2s.rs +++ b/examples/rp/src/bin/pio_i2s.rs @@ -12,17 +12,13 @@ use core::mem; -use defmt_rtt as _; use embassy_executor::Spawner; -use embassy_rp::{ - bind_interrupts, - peripherals::PIO0, - pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}, - Peripheral, -}; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; +use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; -use panic_probe as _; use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; @@ -115,7 +111,7 @@ async fn main(_spawner: Spawner) { fade_value += (fade_target - fade_value) >> 14; // generate triangle wave with amplitude and frequency based on fade value phase = (phase + (fade_value >> 22)) & 0xffff; - let triangle_sample = (phase as i16 as i32).abs() - 16384; + let triangle_sample = (phase as i16 as i32).abs() - 16384; let sample = (triangle_sample * (fade_value >> 15)) >> 16; // duplicate mono sample into lower and upper half of dma word *s = (sample as u16 as u32) * 0x10001; @@ -127,4 +123,3 @@ async fn main(_spawner: Spawner) { mem::swap(&mut back_buffer, &mut front_buffer); } } - From 9f76dbb93b4ab5efc8a0d51b4507ab7eb144fcd9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Jan 2024 21:29:25 +0100 Subject: [PATCH 287/760] Remove nightly-only flags from cargo configs. --- examples/boot/.cargo/config.toml | 4 ++-- examples/boot/application/rp/.cargo/config.toml | 4 ++-- examples/boot/bootloader/nrf/.cargo/config.toml | 6 +++--- tests/rp/.cargo/config.toml | 2 +- tests/stm32/.cargo/config.toml | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/boot/.cargo/config.toml b/examples/boot/.cargo/config.toml index de3a814f7..be1b73e45 100644 --- a/examples/boot/.cargo/config.toml +++ b/examples/boot/.cargo/config.toml @@ -1,6 +1,6 @@ [unstable] -build-std = ["core"] -build-std-features = ["panic_immediate_abort"] +#build-std = ["core"] +#build-std-features = ["panic_immediate_abort"] [build] target = "thumbv7em-none-eabi" diff --git a/examples/boot/application/rp/.cargo/config.toml b/examples/boot/application/rp/.cargo/config.toml index cd8d1ef02..22ab3a5c1 100644 --- a/examples/boot/application/rp/.cargo/config.toml +++ b/examples/boot/application/rp/.cargo/config.toml @@ -1,6 +1,6 @@ [unstable] -build-std = ["core"] -build-std-features = ["panic_immediate_abort"] +#build-std = ["core"] +#build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] runner = "probe-rs run --chip RP2040" diff --git a/examples/boot/bootloader/nrf/.cargo/config.toml b/examples/boot/bootloader/nrf/.cargo/config.toml index c292846aa..58acd1a49 100644 --- a/examples/boot/bootloader/nrf/.cargo/config.toml +++ b/examples/boot/bootloader/nrf/.cargo/config.toml @@ -1,6 +1,6 @@ [unstable] -build-std = ["core"] -build-std-features = ["panic_immediate_abort"] +#build-std = ["core"] +#build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] #runner = "./fruitrunner" @@ -8,7 +8,7 @@ runner = "probe-rs run --chip nrf52840_xxAA" rustflags = [ # Code-size optimizations. - "-Z", "trap-unreachable=no", + #"-Z", "trap-unreachable=no", #"-C", "no-vectorize-loops", "-C", "force-frame-pointers=yes", ] diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml index 40b5d7000..de7bb0e56 100644 --- a/tests/rp/.cargo/config.toml +++ b/tests/rp/.cargo/config.toml @@ -10,7 +10,7 @@ runner = "teleprobe client run" rustflags = [ # Code-size optimizations. - "-Z", "trap-unreachable=no", + #"-Z", "trap-unreachable=no", "-C", "inline-threshold=5", "-C", "no-vectorize-loops", ] diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml index 2e3f055d4..8e32b4cee 100644 --- a/tests/stm32/.cargo/config.toml +++ b/tests/stm32/.cargo/config.toml @@ -1,6 +1,6 @@ [unstable] -build-std = ["core"] -build-std-features = ["panic_immediate_abort"] +#build-std = ["core"] +#build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] runner = "teleprobe client run" @@ -8,7 +8,7 @@ runner = "teleprobe client run" rustflags = [ # Code-size optimizations. - "-Z", "trap-unreachable=no", + #"-Z", "trap-unreachable=no", "-C", "inline-threshold=5", "-C", "no-vectorize-loops", ] @@ -20,4 +20,4 @@ target = "thumbv6m-none-eabi" #target = "thumbv8m.main-none-eabihf" [env] -DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,smoltcp=info" \ No newline at end of file +DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,smoltcp=info" From 3387ee7238f1c9c4eeccb732ba543cbe38ab7ccd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Jan 2024 20:12:36 +0100 Subject: [PATCH 288/760] stm32/gpio: remove generics. --- .../layer-by-layer/blinky-async/src/main.rs | 4 +- .../layer-by-layer/blinky-irq/src/main.rs | 13 +- embassy-stm32/src/exti.rs | 45 +++--- embassy-stm32/src/gpio.rs | 141 ++++++------------ .../boot/application/stm32f3/src/bin/a.rs | 5 +- .../boot/application/stm32f7/src/bin/a.rs | 5 +- .../boot/application/stm32h7/src/bin/a.rs | 5 +- .../boot/application/stm32l0/src/bin/a.rs | 5 +- .../boot/application/stm32l1/src/bin/a.rs | 5 +- .../boot/application/stm32l4/src/bin/a.rs | 5 +- .../boot/application/stm32wl/src/bin/a.rs | 5 +- examples/stm32c0/src/bin/button_exti.rs | 5 +- .../src/bin/button_controlled_blink.rs | 5 +- examples/stm32f0/src/bin/button_exti.rs | 5 +- examples/stm32f3/src/bin/button_events.rs | 28 ++-- examples/stm32f3/src/bin/button_exti.rs | 5 +- examples/stm32f4/src/bin/button_exti.rs | 5 +- examples/stm32f7/src/bin/button_exti.rs | 5 +- examples/stm32g0/src/bin/button_exti.rs | 5 +- examples/stm32g4/src/bin/button_exti.rs | 5 +- examples/stm32h5/src/bin/button_exti.rs | 5 +- examples/stm32h7/src/bin/button_exti.rs | 5 +- examples/stm32l0/src/bin/button_exti.rs | 5 +- examples/stm32l4/src/bin/button_exti.rs | 5 +- .../src/bin/spe_adin1110_http_server.rs | 13 +- examples/stm32l5/src/bin/button_exti.rs | 5 +- examples/stm32wb/src/bin/button_exti.rs | 5 +- examples/stm32wba/src/bin/button_exti.rs | 5 +- examples/stm32wl/src/bin/button_exti.rs | 5 +- 29 files changed, 144 insertions(+), 215 deletions(-) diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs index e6753be28..004602816 100644 --- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs +++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs @@ -3,14 +3,14 @@ use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); let mut led = Output::new(p.PB14, Level::Low, Speed::VeryHigh); - let mut button = ExtiInput::new(Input::new(p.PC13, Pull::Up), p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); loop { button.wait_for_any_edge().await; diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs index aecba0755..743c9d99b 100644 --- a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs +++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs @@ -6,13 +6,12 @@ use core::cell::RefCell; use cortex_m::interrupt::Mutex; use cortex_m::peripheral::NVIC; use cortex_m_rt::entry; -use embassy_stm32::gpio::{Input, Level, Output, Pin, Pull, Speed}; -use embassy_stm32::peripherals::{PB14, PC13}; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::{interrupt, pac}; use {defmt_rtt as _, panic_probe as _}; -static BUTTON: Mutex>>> = Mutex::new(RefCell::new(None)); -static LED: Mutex>>> = Mutex::new(RefCell::new(None)); +static BUTTON: Mutex>>> = Mutex::new(RefCell::new(None)); +static LED: Mutex>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { @@ -62,14 +61,14 @@ fn EXTI15_10() { const PORT: u8 = 2; const PIN: usize = 13; -fn check_interrupt(_pin: &mut Input<'static, P>) -> bool { +fn check_interrupt(_pin: &mut Input<'static>) -> bool { let exti = pac::EXTI; let pin = PIN; let lines = exti.pr(0).read(); lines.line(pin) } -fn clear_interrupt(_pin: &mut Input<'static, P>) { +fn clear_interrupt(_pin: &mut Input<'static>) { let exti = pac::EXTI; let pin = PIN; let mut lines = exti.pr(0).read(); @@ -77,7 +76,7 @@ fn clear_interrupt(_pin: &mut Input<'static, P>) { exti.pr(0).write_value(lines); } -fn enable_interrupt(_pin: &mut Input<'static, P>) { +fn enable_interrupt(_pin: &mut Input<'static>) { cortex_m::interrupt::free(|_| { let rcc = pac::RCC; rcc.apb2enr().modify(|w| w.set_syscfgen(true)); diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 2821435ef..bd10ba158 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -5,10 +5,10 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; -use embassy_hal_internal::impl_peripheral; +use embassy_hal_internal::{impl_peripheral, into_ref}; use embassy_sync::waitqueue::AtomicWaker; -use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin}; +use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; use crate::pac::exti::regs::Lines; use crate::pac::EXTI; use crate::{interrupt, pac, peripherals, Peripheral}; @@ -93,16 +93,27 @@ impl Iterator for BitIter { /// EXTI channel, which is a limited resource. /// /// Pins PA5, PB5, PC5... all use EXTI channel 5, so you can't use EXTI on, say, PA5 and PC5 at the same time. -pub struct ExtiInput<'d, T: GpioPin> { - pin: Input<'d, T>, +pub struct ExtiInput<'d> { + pin: Input<'d>, } -impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} +impl<'d> Unpin for ExtiInput<'d> {} -impl<'d, T: GpioPin> ExtiInput<'d, T> { +impl<'d> ExtiInput<'d> { /// Create an EXTI input. - pub fn new(pin: Input<'d, T>, _ch: impl Peripheral

+ 'd) -> Self { - Self { pin } + pub fn new( + pin: impl Peripheral

+ 'd, + ch: impl Peripheral

+ 'd, + pull: Pull, + ) -> Self { + into_ref!(pin, ch); + + // Needed if using AnyPin+AnyChannel. + assert_eq!(pin.pin(), ch.number()); + + Self { + pin: Input::new(pin, pull), + } } /// Get whether the pin is high. @@ -162,7 +173,7 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { } } -impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T> { +impl<'d> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d> { type Error = Infallible; fn is_high(&self) -> Result { @@ -174,11 +185,11 @@ impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T> } } -impl<'d, T: GpioPin> embedded_hal_1::digital::ErrorType for ExtiInput<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for ExtiInput<'d> { type Error = Infallible; } -impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for ExtiInput<'d> { fn is_high(&mut self) -> Result { Ok((*self).is_high()) } @@ -188,7 +199,7 @@ impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { } } -impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for ExtiInput<'d, T> { +impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { self.wait_for_high().await; Ok(()) @@ -326,7 +337,7 @@ pub(crate) mod sealed { /// EXTI channel trait. pub trait Channel: sealed::Channel + Sized { /// Get the EXTI channel number. - fn number(&self) -> usize; + fn number(&self) -> u8; /// Type-erase (degrade) this channel into an `AnyChannel`. /// @@ -350,8 +361,8 @@ pub struct AnyChannel { impl_peripheral!(AnyChannel); impl sealed::Channel for AnyChannel {} impl Channel for AnyChannel { - fn number(&self) -> usize { - self.number as usize + fn number(&self) -> u8 { + self.number } } @@ -359,8 +370,8 @@ macro_rules! impl_exti { ($type:ident, $number:expr) => { impl sealed::Channel for peripherals::$type {} impl Channel for peripherals::$type { - fn number(&self) -> usize { - $number as usize + fn number(&self) -> u8 { + $number } } }; diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 7eb70496f..1051a13c8 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -6,6 +6,7 @@ use core::convert::Infallible; use critical_section::CriticalSection; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; +use self::sealed::Pin as _; use crate::pac::gpio::{self, vals}; use crate::{pac, peripherals, Peripheral}; @@ -14,41 +15,21 @@ use crate::{pac, peripherals, Peripheral}; /// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output /// mode. -pub struct Flex<'d, T: Pin> { - pub(crate) pin: PeripheralRef<'d, T>, +pub struct Flex<'d> { + pub(crate) pin: PeripheralRef<'d, AnyPin>, } -impl<'d, T: Pin> Flex<'d, T> { +impl<'d> Flex<'d> { /// Wrap the pin in a `Flex`. /// /// The pin remains disconnected. The initial output level is unspecified, but can be changed /// before the pin is put into output mode. /// #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { + pub fn new(pin: impl Peripheral

+ 'd) -> Self { into_ref!(pin); // Pin will be in disconnected state. - Self { pin } - } - - /// Type-erase (degrade) this pin into an `AnyPin`. - /// - /// This converts pin singletons (`PA5`, `PB6`, ...), which - /// are all different types, into the same type. It is useful for - /// creating arrays of pins, or avoiding generics. - #[inline] - pub fn degrade(self) -> Flex<'d, AnyPin> { - // Safety: We are about to drop the other copy of this pin, so - // this clone is safe. - let pin = unsafe { self.pin.clone_unchecked() }; - - // We don't want to run the destructor here, because that would - // deconfigure the pin. - core::mem::forget(self); - - Flex { - pin: pin.map_into::(), - } + Self { pin: pin.map_into() } } /// Put the pin into input mode. @@ -218,7 +199,7 @@ impl<'d, T: Pin> Flex<'d, T> { } } -impl<'d, T: Pin> Drop for Flex<'d, T> { +impl<'d> Drop for Flex<'d> { #[inline] fn drop(&mut self) { critical_section::with(|_| { @@ -309,31 +290,19 @@ impl From for vals::Ospeedr { } /// GPIO input driver. -pub struct Input<'d, T: Pin> { - pub(crate) pin: Flex<'d, T>, +pub struct Input<'d> { + pub(crate) pin: Flex<'d>, } -impl<'d, T: Pin> Input<'d, T> { +impl<'d> Input<'d> { /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { let mut pin = Flex::new(pin); pin.set_as_input(pull); Self { pin } } - /// Type-erase (degrade) this pin into an `AnyPin`. - /// - /// This converts pin singletons (`PA5`, `PB6`, ...), which - /// are all different types, into the same type. It is useful for - /// creating arrays of pins, or avoiding generics. - #[inline] - pub fn degrade(self) -> Input<'d, AnyPin> { - Input { - pin: self.pin.degrade(), - } - } - /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -386,14 +355,14 @@ impl From for bool { /// Note that pins will **return to their floating state** when `Output` is dropped. /// If pins should retain their state indefinitely, either keep ownership of the /// `Output`, or pass it to [`core::mem::forget`]. -pub struct Output<'d, T: Pin> { - pub(crate) pin: Flex<'d, T>, +pub struct Output<'d> { + pub(crate) pin: Flex<'d>, } -impl<'d, T: Pin> Output<'d, T> { +impl<'d> Output<'d> { /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed) -> Self { + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed) -> Self { let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), @@ -403,18 +372,6 @@ impl<'d, T: Pin> Output<'d, T> { Self { pin } } - /// Type-erase (degrade) this pin into an `AnyPin`. - /// - /// This converts pin singletons (`PA5`, `PB6`, ...), which - /// are all different types, into the same type. It is useful for - /// creating arrays of pins, or avoiding generics. - #[inline] - pub fn degrade(self) -> Output<'d, AnyPin> { - Output { - pin: self.pin.degrade(), - } - } - /// Set the output as high. #[inline] pub fn set_high(&mut self) { @@ -463,14 +420,14 @@ impl<'d, T: Pin> Output<'d, T> { /// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped. /// If pins should retain their state indefinitely, either keep ownership of the /// `OutputOpenDrain`, or pass it to [`core::mem::forget`]. -pub struct OutputOpenDrain<'d, T: Pin> { - pub(crate) pin: Flex<'d, T>, +pub struct OutputOpenDrain<'d> { + pub(crate) pin: Flex<'d>, } -impl<'d, T: Pin> OutputOpenDrain<'d, T> { +impl<'d> OutputOpenDrain<'d> { /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { let mut pin = Flex::new(pin); match initial_output { @@ -482,18 +439,6 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { Self { pin } } - /// Type-erase (degrade) this pin into an `AnyPin`. - /// - /// This converts pin singletons (`PA5`, `PB6`, ...), which - /// are all different types, into the same type. It is useful for - /// creating arrays of pins, or avoiding generics. - #[inline] - pub fn degrade(self) -> Output<'d, AnyPin> { - Output { - pin: self.pin.degrade(), - } - } - /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -836,7 +781,7 @@ pub(crate) unsafe fn init(_cs: CriticalSection) { }); } -impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { +impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { type Error = Infallible; #[inline] @@ -850,7 +795,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { +impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> { type Error = Infallible; #[inline] @@ -866,7 +811,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { +impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> { #[inline] fn is_set_high(&self) -> Result { Ok(self.is_set_high()) @@ -879,7 +824,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> { +impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> { type Error = Infallible; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -888,7 +833,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> { type Error = Infallible; #[inline] @@ -904,7 +849,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d> { #[inline] fn is_set_high(&self) -> Result { Ok(self.is_set_high()) @@ -917,7 +862,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenD } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d> { type Error = Infallible; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -926,7 +871,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpe } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { +impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> { type Error = Infallible; #[inline] @@ -940,7 +885,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { +impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> { type Error = Infallible; #[inline] @@ -956,7 +901,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { +impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> { #[inline] fn is_set_high(&self) -> Result { Ok(self.is_set_high()) @@ -969,7 +914,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> } } -impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> { +impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> { type Error = Infallible; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -978,11 +923,11 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for Input<'d> { #[inline] fn is_high(&mut self) -> Result { Ok((*self).is_high()) @@ -994,11 +939,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { +impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> { #[inline] fn set_high(&mut self) -> Result<(), Self::Error> { Ok(self.set_high()) @@ -1010,7 +955,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { +impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> { #[inline] fn is_set_high(&mut self) -> Result { Ok((*self).is_set_high()) @@ -1023,11 +968,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d> { #[inline] fn is_high(&mut self) -> Result { Ok((*self).is_high()) @@ -1039,7 +984,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d> { #[inline] fn set_high(&mut self) -> Result<(), Self::Error> { Ok(self.set_high()) @@ -1051,7 +996,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d> { #[inline] fn is_set_high(&mut self) -> Result { Ok((*self).is_set_high()) @@ -1064,7 +1009,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain< } } -impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> { #[inline] fn is_high(&mut self) -> Result { Ok((*self).is_high()) @@ -1076,7 +1021,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> { #[inline] fn set_high(&mut self) -> Result<(), Self::Error> { Ok(self.set_high()) @@ -1088,11 +1033,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> { #[inline] fn is_set_high(&mut self) -> Result { Ok((*self).is_set_high()) diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs index 96ae5c47b..3f9ebe5c8 100644 --- a/examples/boot/application/stm32f3/src/bin/a.rs +++ b/examples/boot/application/stm32f3/src/bin/a.rs @@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::mutex::Mutex; use panic_reset as _; @@ -23,8 +23,7 @@ async fn main(_spawner: Spawner) { let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(BlockingAsync::new(flash)); - let button = Input::new(p.PC13, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); let mut led = Output::new(p.PA5, Level::Low, Speed::Low); led.set_high(); diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs index a6107386a..c57c29263 100644 --- a/examples/boot/application/stm32f7/src/bin/a.rs +++ b/examples/boot/application/stm32f7/src/bin/a.rs @@ -9,7 +9,7 @@ use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdater use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::blocking_mutex::Mutex; use embedded_storage::nor_flash::NorFlash; use panic_reset as _; @@ -25,8 +25,7 @@ async fn main(_spawner: Spawner) { let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(RefCell::new(flash)); - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); let mut led = Output::new(p.PB7, Level::Low, Speed::Low); led.set_high(); diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs index b73506cf3..a00d17408 100644 --- a/examples/boot/application/stm32h7/src/bin/a.rs +++ b/examples/boot/application/stm32h7/src/bin/a.rs @@ -9,7 +9,7 @@ use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdater use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::blocking_mutex::Mutex; use embedded_storage::nor_flash::NorFlash; use panic_reset as _; @@ -25,8 +25,7 @@ async fn main(_spawner: Spawner) { let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(RefCell::new(flash)); - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); let mut led = Output::new(p.PB14, Level::Low, Speed::Low); led.set_high(); diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs index 02f74bdef..dbec49d44 100644 --- a/examples/boot/application/stm32l0/src/bin/a.rs +++ b/examples/boot/application/stm32l0/src/bin/a.rs @@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::mutex::Mutex; use embassy_time::Timer; use panic_reset as _; @@ -24,8 +24,7 @@ async fn main(_spawner: Spawner) { let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(BlockingAsync::new(flash)); - let button = Input::new(p.PB2, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI2); + let mut button = ExtiInput::new(p.PB2, p.EXTI2, Pull::Up); let mut led = Output::new(p.PB5, Level::Low, Speed::Low); diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs index 02f74bdef..dbec49d44 100644 --- a/examples/boot/application/stm32l1/src/bin/a.rs +++ b/examples/boot/application/stm32l1/src/bin/a.rs @@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::mutex::Mutex; use embassy_time::Timer; use panic_reset as _; @@ -24,8 +24,7 @@ async fn main(_spawner: Spawner) { let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(BlockingAsync::new(flash)); - let button = Input::new(p.PB2, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI2); + let mut button = ExtiInput::new(p.PB2, p.EXTI2, Pull::Up); let mut led = Output::new(p.PB5, Level::Low, Speed::Low); diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs index 892446968..e946c3cdf 100644 --- a/examples/boot/application/stm32l4/src/bin/a.rs +++ b/examples/boot/application/stm32l4/src/bin/a.rs @@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::mutex::Mutex; use panic_reset as _; @@ -23,8 +23,7 @@ async fn main(_spawner: Spawner) { let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(BlockingAsync::new(flash)); - let button = Input::new(p.PC13, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); let mut led = Output::new(p.PB14, Level::Low, Speed::Low); led.set_high(); diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index d9665e6ee..b582d8b25 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs @@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::mutex::Mutex; use panic_reset as _; @@ -23,8 +23,7 @@ async fn main(_spawner: Spawner) { let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(BlockingAsync::new(flash)); - let button = Input::new(p.PA0, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI0); + let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); let mut led = Output::new(p.PB9, Level::Low, Speed::Low); led.set_high(); diff --git a/examples/stm32c0/src/bin/button_exti.rs b/examples/stm32c0/src/bin/button_exti.rs index 1e970fdd6..34a08bbc6 100644 --- a/examples/stm32c0/src/bin/button_exti.rs +++ b/examples/stm32c0/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); info!("Press the USER button..."); diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs index 360d153c3..4465483d9 100644 --- a/examples/stm32f0/src/bin/button_controlled_blink.rs +++ b/examples/stm32f0/src/bin/button_controlled_blink.rs @@ -8,7 +8,7 @@ use core::sync::atomic::{AtomicU32, Ordering}; use defmt::info; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed}; +use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Pull, Speed}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -36,8 +36,7 @@ async fn main(spawner: Spawner) { // Configure the button pin and obtain handler. // On the Nucleo F091RC there is a button connected to pin PC13. - let button = Input::new(p.PC13, Pull::None); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::None); // Create and initialize a delay variable to manage delay loop let mut del_var = 2000; diff --git a/examples/stm32f0/src/bin/button_exti.rs b/examples/stm32f0/src/bin/button_exti.rs index ce17c1a48..fd615a215 100644 --- a/examples/stm32f0/src/bin/button_exti.rs +++ b/examples/stm32f0/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -13,8 +13,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); // Configure the button pin and obtain handler. // On the Nucleo F091RC there is a button connected to pin PC13. - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); info!("Press the USER button..."); loop { diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs index 2f7da4ef5..f5ed5d2c9 100644 --- a/examples/stm32f3/src/bin/button_events.rs +++ b/examples/stm32f3/src/bin/button_events.rs @@ -12,21 +12,20 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed}; -use embassy_stm32::peripherals::PA0; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::Channel; use embassy_time::{with_timeout, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; struct Leds<'a> { - leds: [Output<'a, AnyPin>; 8], + leds: [Output<'a>; 8], direction: i8, current_led: usize, } impl<'a> Leds<'a> { - fn new(pins: [Output<'a, AnyPin>; 8]) -> Self { + fn new(pins: [Output<'a>; 8]) -> Self { Self { leds: pins, direction: 1, @@ -100,18 +99,17 @@ static CHANNEL: Channel = Channel::new(); #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let button = Input::new(p.PA0, Pull::Down); - let button = ExtiInput::new(button, p.EXTI0); + let button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Down); info!("Press the USER button..."); let leds = [ - Output::new(p.PE9.degrade(), Level::Low, Speed::Low), - Output::new(p.PE10.degrade(), Level::Low, Speed::Low), - Output::new(p.PE11.degrade(), Level::Low, Speed::Low), - Output::new(p.PE12.degrade(), Level::Low, Speed::Low), - Output::new(p.PE13.degrade(), Level::Low, Speed::Low), - Output::new(p.PE14.degrade(), Level::Low, Speed::Low), - Output::new(p.PE15.degrade(), Level::Low, Speed::Low), - Output::new(p.PE8.degrade(), Level::Low, Speed::Low), + Output::new(p.PE9, Level::Low, Speed::Low), + Output::new(p.PE10, Level::Low, Speed::Low), + Output::new(p.PE11, Level::Low, Speed::Low), + Output::new(p.PE12, Level::Low, Speed::Low), + Output::new(p.PE13, Level::Low, Speed::Low), + Output::new(p.PE14, Level::Low, Speed::Low), + Output::new(p.PE15, Level::Low, Speed::Low), + Output::new(p.PE8, Level::Low, Speed::Low), ]; let leds = Leds::new(leds); @@ -127,7 +125,7 @@ async fn led_blinker(mut leds: Leds<'static>) { } #[embassy_executor::task] -async fn button_waiter(mut button: ExtiInput<'static, PA0>) { +async fn button_waiter(mut button: ExtiInput<'static>) { const DOUBLE_CLICK_DELAY: u64 = 250; const HOLD_DELAY: u64 = 1000; diff --git a/examples/stm32f3/src/bin/button_exti.rs b/examples/stm32f3/src/bin/button_exti.rs index 86ff68492..a55530e0e 100644 --- a/examples/stm32f3/src/bin/button_exti.rs +++ b/examples/stm32f3/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PA0, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI0); + let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Down); info!("Press the USER button..."); diff --git a/examples/stm32f4/src/bin/button_exti.rs b/examples/stm32f4/src/bin/button_exti.rs index 67751187d..2a546dac5 100644 --- a/examples/stm32f4/src/bin/button_exti.rs +++ b/examples/stm32f4/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); info!("Press the USER button..."); diff --git a/examples/stm32f7/src/bin/button_exti.rs b/examples/stm32f7/src/bin/button_exti.rs index 67751187d..2a546dac5 100644 --- a/examples/stm32f7/src/bin/button_exti.rs +++ b/examples/stm32f7/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); info!("Press the USER button..."); diff --git a/examples/stm32g0/src/bin/button_exti.rs b/examples/stm32g0/src/bin/button_exti.rs index 1e970fdd6..34a08bbc6 100644 --- a/examples/stm32g0/src/bin/button_exti.rs +++ b/examples/stm32g0/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); info!("Press the USER button..."); diff --git a/examples/stm32g4/src/bin/button_exti.rs b/examples/stm32g4/src/bin/button_exti.rs index 67751187d..2a546dac5 100644 --- a/examples/stm32g4/src/bin/button_exti.rs +++ b/examples/stm32g4/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); info!("Press the USER button..."); diff --git a/examples/stm32h5/src/bin/button_exti.rs b/examples/stm32h5/src/bin/button_exti.rs index 67751187d..2a546dac5 100644 --- a/examples/stm32h5/src/bin/button_exti.rs +++ b/examples/stm32h5/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); info!("Press the USER button..."); diff --git a/examples/stm32h7/src/bin/button_exti.rs b/examples/stm32h7/src/bin/button_exti.rs index 67751187d..2a546dac5 100644 --- a/examples/stm32h7/src/bin/button_exti.rs +++ b/examples/stm32h7/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); info!("Press the USER button..."); diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs index f517fce04..4945da7ce 100644 --- a/examples/stm32l0/src/bin/button_exti.rs +++ b/examples/stm32l0/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; @@ -13,8 +13,7 @@ async fn main(_spawner: Spawner) { let config = Config::default(); let p = embassy_stm32::init(config); - let button = Input::new(p.PB2, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI2); + let mut button = ExtiInput::new(p.PB2, p.EXTI2, Pull::Up); info!("Press the USER button..."); diff --git a/examples/stm32l4/src/bin/button_exti.rs b/examples/stm32l4/src/bin/button_exti.rs index 1e970fdd6..34a08bbc6 100644 --- a/examples/stm32l4/src/bin/button_exti.rs +++ b/examples/stm32l4/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); info!("Press the USER button..."); diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 5b4cdfe5e..026a3a477 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -58,9 +58,9 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24); const HTTP_LISTEN_PORT: u16 = 80; pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; -pub type SpeSpiCs = ExclusiveDevice, Delay>; -pub type SpeInt = exti::ExtiInput<'static, peripherals::PB11>; -pub type SpeRst = Output<'static, peripherals::PC7>; +pub type SpeSpiCs = ExclusiveDevice, Delay>; +pub type SpeInt = exti::ExtiInput<'static>; +pub type SpeRst = Output<'static>; pub type Adin1110T = ADIN1110; pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; @@ -134,8 +134,7 @@ async fn main(spawner: Spawner) { let spe_cfg1 = Input::new(dp.PC9, Pull::None); let _spe_ts_capt = Output::new(dp.PC6, Level::Low, Speed::Low); - let spe_int = Input::new(dp.PB11, Pull::None); - let spe_int = exti::ExtiInput::new(spe_int, dp.EXTI11); + let spe_int = exti::ExtiInput::new(dp.PB11, dp.EXTI11, Pull::None); let spe_spi_cs_n = Output::new(dp.PB12, Level::High, Speed::High); let spe_spi_sclk = dp.PB13; @@ -298,7 +297,7 @@ async fn wait_for_config(stack: &'static Stack>) -> embassy_net: } #[embassy_executor::task] -async fn heartbeat_led(mut led: Output<'static, peripherals::PE6>) { +async fn heartbeat_led(mut led: Output<'static>) { let mut tmr = Ticker::every(Duration::from_hz(3)); loop { led.toggle(); @@ -308,7 +307,7 @@ async fn heartbeat_led(mut led: Output<'static, peripherals::PE6>) { // ADT7422 #[embassy_executor::task] -async fn temp_task(temp_dev_i2c: TempSensI2c, mut led: Output<'static, peripherals::PG15>) -> ! { +async fn temp_task(temp_dev_i2c: TempSensI2c, mut led: Output<'static>) -> ! { let mut tmr = Ticker::every(Duration::from_hz(1)); let mut temp_sens = ADT7422::new(temp_dev_i2c, 0x48).unwrap(); diff --git a/examples/stm32l5/src/bin/button_exti.rs b/examples/stm32l5/src/bin/button_exti.rs index 91d0ccc2e..e6639d22b 100644 --- a/examples/stm32l5/src/bin/button_exti.rs +++ b/examples/stm32l5/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); info!("Press the USER button..."); diff --git a/examples/stm32wb/src/bin/button_exti.rs b/examples/stm32wb/src/bin/button_exti.rs index d34dde3e9..2871fd55f 100644 --- a/examples/stm32wb/src/bin/button_exti.rs +++ b/examples/stm32wb/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC4, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI4); + let mut button = ExtiInput::new(p.PC4, p.EXTI4, Pull::Up); info!("Press the USER button..."); diff --git a/examples/stm32wba/src/bin/button_exti.rs b/examples/stm32wba/src/bin/button_exti.rs index 1e970fdd6..34a08bbc6 100644 --- a/examples/stm32wba/src/bin/button_exti.rs +++ b/examples/stm32wba/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PC13, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI13); + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); info!("Press the USER button..."); diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs index e6ad4b80b..27d5330bd 100644 --- a/examples/stm32wl/src/bin/button_exti.rs +++ b/examples/stm32wl/src/bin/button_exti.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::gpio::Pull; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let button = Input::new(p.PA0, Pull::Up); - let mut button = ExtiInput::new(button, p.EXTI0); + let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); info!("Press the USER button..."); From 2bc5e9523d4373002487614ecfef1e3f0858fd66 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Jan 2024 21:19:18 +0100 Subject: [PATCH 289/760] nrf/gpio: remove generics. --- docs/modules/ROOT/examples/basic/src/main.rs | 3 +- embassy-nrf/src/gpio.rs | 62 +++++++++---------- embassy-nrf/src/gpiote.rs | 53 +++++++++------- .../nrf52840/src/bin/ethernet_enc28j60.rs | 12 +--- examples/nrf52840/src/bin/gpiote_port.rs | 12 ++-- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 4 +- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 12 ++-- tests/nrf/src/bin/ethernet_enc28j60_perf.rs | 5 +- tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 12 ++-- 9 files changed, 86 insertions(+), 89 deletions(-) diff --git a/docs/modules/ROOT/examples/basic/src/main.rs b/docs/modules/ROOT/examples/basic/src/main.rs index 2a4ee5968..4412712c8 100644 --- a/docs/modules/ROOT/examples/basic/src/main.rs +++ b/docs/modules/ROOT/examples/basic/src/main.rs @@ -4,12 +4,11 @@ use defmt::*; use embassy_executor::Spawner; use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::peripherals::P0_13; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; // global logger #[embassy_executor::task] -async fn blinker(mut led: Output<'static, P0_13>, interval: Duration) { +async fn blinker(mut led: Output<'static>, interval: Duration) { loop { led.set_high(); Timer::after(interval).await; diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index eabf409dd..287811e61 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -36,14 +36,14 @@ pub enum Pull { } /// GPIO input driver. -pub struct Input<'d, T: Pin> { - pub(crate) pin: Flex<'d, T>, +pub struct Input<'d> { + pub(crate) pin: Flex<'d>, } -impl<'d, T: Pin> Input<'d, T> { +impl<'d> Input<'d> { /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { let mut pin = Flex::new(pin); pin.set_as_input(pull); @@ -122,14 +122,14 @@ pub enum OutputDrive { } /// GPIO output driver. -pub struct Output<'d, T: Pin> { - pub(crate) pin: Flex<'d, T>, +pub struct Output<'d> { + pub(crate) pin: Flex<'d>, } -impl<'d, T: Pin> Output<'d, T> { +impl<'d> Output<'d> { /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDriver] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, drive: OutputDrive) -> Self { + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, drive: OutputDrive) -> Self { let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), @@ -209,20 +209,20 @@ fn convert_pull(pull: Pull) -> PULL_A { /// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output /// mode. -pub struct Flex<'d, T: Pin> { - pub(crate) pin: PeripheralRef<'d, T>, +pub struct Flex<'d> { + pub(crate) pin: PeripheralRef<'d, AnyPin>, } -impl<'d, T: Pin> Flex<'d, T> { +impl<'d> Flex<'d> { /// Wrap the pin in a `Flex`. /// /// The pin remains disconnected. The initial output level is unspecified, but can be changed /// before the pin is put into output mode. #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { + pub fn new(pin: impl Peripheral

+ 'd) -> Self { into_ref!(pin); // Pin will be in disconnected state. - Self { pin } + Self { pin: pin.map_into() } } /// Put the pin into input mode. @@ -349,7 +349,7 @@ impl<'d, T: Pin> Flex<'d, T> { } } -impl<'d, T: Pin> Drop for Flex<'d, T> { +impl<'d> Drop for Flex<'d> { fn drop(&mut self) { self.pin.conf().reset(); } @@ -510,7 +510,7 @@ macro_rules! impl_pin { mod eh02 { use super::*; - impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { + impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { type Error = Infallible; fn is_high(&self) -> Result { @@ -522,7 +522,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { + impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> { type Error = Infallible; fn set_high(&mut self) -> Result<(), Self::Error> { @@ -534,7 +534,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { + impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> { fn is_set_high(&self) -> Result { Ok(self.is_set_high()) } @@ -544,7 +544,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> { + impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> { type Error = Infallible; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -556,7 +556,7 @@ mod eh02 { /// Implement [`embedded_hal_02::digital::v2::InputPin`] for [`Flex`]; /// /// If the pin is not in input mode the result is unspecified. - impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { + impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> { type Error = Infallible; fn is_high(&self) -> Result { @@ -568,7 +568,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { + impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> { type Error = Infallible; fn set_high(&mut self) -> Result<(), Self::Error> { @@ -580,7 +580,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { + impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> { fn is_set_high(&self) -> Result { Ok(self.is_set_high()) } @@ -590,7 +590,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> { + impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> { type Error = Infallible; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -600,11 +600,11 @@ mod eh02 { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for Input<'d> { fn is_high(&mut self) -> Result { Ok((*self).is_high()) } @@ -614,11 +614,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { +impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> { fn set_high(&mut self) -> Result<(), Self::Error> { Ok(self.set_high()) } @@ -628,7 +628,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { +impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> { fn is_set_high(&mut self) -> Result { Ok((*self).is_set_high()) } @@ -638,14 +638,14 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> { type Error = Infallible; } /// Implement [`InputPin`] for [`Flex`]; /// /// If the pin is not in input mode the result is unspecified. -impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> { fn is_high(&mut self) -> Result { Ok((*self).is_high()) } @@ -655,7 +655,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> { fn set_high(&mut self) -> Result<(), Self::Error> { Ok(self.set_high()) } @@ -665,7 +665,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> { fn is_set_high(&mut self) -> Result { Ok((*self).is_set_high()) } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 8020b8dc2..a459446a2 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -156,12 +156,12 @@ impl Iterator for BitIter { } /// GPIOTE channel driver in input mode -pub struct InputChannel<'d, C: Channel, T: GpioPin> { - ch: PeripheralRef<'d, C>, - pin: Input<'d, T>, +pub struct InputChannel<'d> { + ch: PeripheralRef<'d, AnyChannel>, + pin: Input<'d>, } -impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { +impl<'d> Drop for InputChannel<'d> { fn drop(&mut self) { let g = regs(); let num = self.ch.number(); @@ -170,9 +170,9 @@ impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { } } -impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { +impl<'d> InputChannel<'d> { /// Create a new GPIOTE input channel driver. - pub fn new(ch: impl Peripheral

+ 'd, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self { + pub fn new(ch: impl Peripheral

+ 'd, pin: Input<'d>, polarity: InputChannelPolarity) -> Self { into_ref!(ch); let g = regs(); @@ -195,7 +195,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { g.events_in[num].reset(); - InputChannel { ch, pin } + InputChannel { ch: ch.map_into(), pin } } /// Asynchronously wait for an event in this channel. @@ -227,12 +227,12 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { } /// GPIOTE channel driver in output mode -pub struct OutputChannel<'d, C: Channel, T: GpioPin> { - ch: PeripheralRef<'d, C>, - _pin: Output<'d, T>, +pub struct OutputChannel<'d> { + ch: PeripheralRef<'d, AnyChannel>, + _pin: Output<'d>, } -impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { +impl<'d> Drop for OutputChannel<'d> { fn drop(&mut self) { let g = regs(); let num = self.ch.number(); @@ -241,9 +241,9 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { } } -impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { +impl<'d> OutputChannel<'d> { /// Create a new GPIOTE output channel driver. - pub fn new(ch: impl Peripheral

+ 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { + pub fn new(ch: impl Peripheral

+ 'd, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self { into_ref!(ch); let g = regs(); let num = ch.number(); @@ -267,7 +267,10 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { unsafe { w.psel().bits(pin.pin.pin.pin()) } }); - OutputChannel { ch, _pin: pin } + OutputChannel { + ch: ch.map_into(), + _pin: pin, + } } /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle). @@ -348,7 +351,7 @@ impl<'a> Future for PortInputFuture<'a> { } } -impl<'d, T: GpioPin> Input<'d, T> { +impl<'d> Input<'d> { /// Wait until the pin is high. If it is already high, return immediately. pub async fn wait_for_high(&mut self) { self.pin.wait_for_high().await @@ -375,7 +378,7 @@ impl<'d, T: GpioPin> Input<'d, T> { } } -impl<'d, T: GpioPin> Flex<'d, T> { +impl<'d> Flex<'d> { /// Wait until the pin is high. If it is already high, return immediately. pub async fn wait_for_high(&mut self) { self.pin.conf().modify(|_, w| w.sense().high()); @@ -420,7 +423,7 @@ mod sealed { /// GPIOTE channel trait. /// /// Implemented by all GPIOTE channels. -pub trait Channel: sealed::Channel + Sized { +pub trait Channel: sealed::Channel + Into + Sized + 'static { /// Get the channel number. fn number(&self) -> usize; @@ -460,6 +463,12 @@ macro_rules! impl_channel { $number as usize } } + + impl From for AnyChannel { + fn from(val: peripherals::$type) -> Self { + Channel::degrade(val) + } + } }; } @@ -477,7 +486,7 @@ impl_channel!(GPIOTE_CH7, 7); mod eh02 { use super::*; - impl<'d, C: Channel, T: GpioPin> embedded_hal_02::digital::v2::InputPin for InputChannel<'d, C, T> { + impl<'d> embedded_hal_02::digital::v2::InputPin for InputChannel<'d> { type Error = Infallible; fn is_high(&self) -> Result { @@ -490,11 +499,11 @@ mod eh02 { } } -impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputChannel<'d, C, T> { +impl<'d> embedded_hal_1::digital::ErrorType for InputChannel<'d> { type Error = Infallible; } -impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChannel<'d, C, T> { +impl<'d> embedded_hal_1::digital::InputPin for InputChannel<'d> { fn is_high(&mut self) -> Result { Ok(self.pin.is_high()) } @@ -504,7 +513,7 @@ impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChan } } -impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> { +impl<'d> embedded_hal_async::digital::Wait for Input<'d> { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { Ok(self.wait_for_high().await) } @@ -526,7 +535,7 @@ impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> { } } -impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> { +impl<'d> embedded_hal_async::digital::Wait for Flex<'d> { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { Ok(self.wait_for_high().await) } diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index a8e64b38a..279f32edc 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -24,10 +24,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::task] async fn net_task( stack: &'static Stack< - Enc28j60< - ExclusiveDevice, Output<'static, peripherals::P0_15>, Delay>, - Output<'static, peripherals::P0_13>, - >, + Enc28j60, Output<'static>, Delay>, Output<'static>>, >, ) -> ! { stack.run().await @@ -71,12 +68,7 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); static STACK: StaticCell< - Stack< - Enc28j60< - ExclusiveDevice, Output<'static, peripherals::P0_15>, Delay>, - Output<'static, peripherals::P0_13>, - >, - >, + Stack, Output<'static>, Delay>, Output<'static>>>, > = StaticCell::new(); let stack = STACK.init(Stack::new( device, diff --git a/examples/nrf52840/src/bin/gpiote_port.rs b/examples/nrf52840/src/bin/gpiote_port.rs index c1afe2f20..0dddb1a97 100644 --- a/examples/nrf52840/src/bin/gpiote_port.rs +++ b/examples/nrf52840/src/bin/gpiote_port.rs @@ -3,11 +3,11 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; +use embassy_nrf::gpio::{Input, Pull}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task(pool_size = 4)] -async fn button_task(n: usize, mut pin: Input<'static, AnyPin>) { +async fn button_task(n: usize, mut pin: Input<'static>) { loop { pin.wait_for_low().await; info!("Button {:?} pressed!", n); @@ -21,10 +21,10 @@ async fn main(spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Starting!"); - let btn1 = Input::new(p.P0_11.degrade(), Pull::Up); - let btn2 = Input::new(p.P0_12.degrade(), Pull::Up); - let btn3 = Input::new(p.P0_24.degrade(), Pull::Up); - let btn4 = Input::new(p.P0_25.degrade(), Pull::Up); + let btn1 = Input::new(p.P0_11, Pull::Up); + let btn2 = Input::new(p.P0_12, Pull::Up); + let btn3 = Input::new(p.P0_24, Pull::Up); + let btn4 = Input::new(p.P0_25, Pull::Up); unwrap!(spawner.spawn(button_task(1, btn1))); unwrap!(spawner.spawn(button_task(2, btn2))); diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 45850b4a4..3e86590c4 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_futures::select::{select, Either}; -use embassy_nrf::gpio::{Input, Pin, Pull}; +use embassy_nrf::gpio::{Input, Pull}; use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; @@ -97,7 +97,7 @@ async fn main(_spawner: Spawner) { } }; - let mut button = Input::new(p.P0_11.degrade(), Pull::Up); + let mut button = Input::new(p.P0_11, Pull::Up); let (reader, mut writer) = hid.split(); diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index fc2086f75..00bd50081 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -5,7 +5,7 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Stack, StackResources}; -use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; use embassy_nrf::{bind_interrupts, peripherals}; @@ -27,9 +27,9 @@ bind_interrupts!(struct Irqs { async fn wifi_task( runner: hosted::Runner< 'static, - ExclusiveDevice, Output<'static, peripherals::P0_31>, Delay>, - Input<'static, AnyPin>, - Output<'static, peripherals::P1_05>, + ExclusiveDevice, Output<'static>, Delay>, + Input<'static>, + Output<'static>, >, ) -> ! { runner.run().await @@ -50,8 +50,8 @@ async fn main(spawner: Spawner) { let sck = p.P0_29; let mosi = p.P0_30; let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); - let handshake = Input::new(p.P1_01.degrade(), Pull::Up); - let ready = Input::new(p.P1_04.degrade(), Pull::None); + let handshake = Input::new(p.P1_01, Pull::Up); + let ready = Input::new(p.P1_04, Pull::None); let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); let mut config = spim::Config::default(); diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs index 7dc1941d7..33c2f4235 100644 --- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs @@ -21,10 +21,7 @@ bind_interrupts!(struct Irqs { RNG => embassy_nrf::rng::InterruptHandler; }); -type MyDriver = Enc28j60< - ExclusiveDevice, Output<'static, peripherals::P0_15>, Delay>, - Output<'static, peripherals::P0_13>, ->; +type MyDriver = Enc28j60, Output<'static>, Delay>, Output<'static>>; #[embassy_executor::task] async fn net_task(stack: &'static Stack) -> ! { diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index c96064f84..b83edddc4 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -6,7 +6,7 @@ teleprobe_meta::timeout!(120); use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_net::{Config, Stack, StackResources}; -use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; use embassy_nrf::{bind_interrupts, peripherals}; @@ -28,9 +28,9 @@ const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; async fn wifi_task( runner: hosted::Runner< 'static, - ExclusiveDevice, Output<'static, peripherals::P0_31>, Delay>, - Input<'static, AnyPin>, - Output<'static, peripherals::P1_05>, + ExclusiveDevice, Output<'static>, Delay>, + Input<'static>, + Output<'static>, >, ) -> ! { runner.run().await @@ -53,8 +53,8 @@ async fn main(spawner: Spawner) { let sck = p.P0_29; let mosi = p.P0_30; let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); - let handshake = Input::new(p.P1_01.degrade(), Pull::Up); - let ready = Input::new(p.P1_04.degrade(), Pull::None); + let handshake = Input::new(p.P1_01, Pull::Up); + let ready = Input::new(p.P1_04, Pull::None); let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); let mut config = spim::Config::default(); From ee0ebe3121e5d51240e671d8c5cc19ad878b9db9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Jan 2024 21:30:29 +0100 Subject: [PATCH 290/760] rp/gpio: remove generics. --- cyw43-pio/src/lib.rs | 14 +- embassy-rp/src/gpio.rs | 125 +++++++++--------- examples/rp/src/bin/blinky_two_tasks.rs | 2 +- .../rp/src/bin/ethernet_w5500_multisocket.rs | 8 +- .../rp/src/bin/ethernet_w5500_tcp_client.rs | 8 +- .../rp/src/bin/ethernet_w5500_tcp_server.rs | 8 +- examples/rp/src/bin/ethernet_w5500_udp.rs | 8 +- examples/rp/src/bin/multicore.rs | 3 +- examples/rp/src/bin/wifi_ap_tcp_server.rs | 6 +- examples/rp/src/bin/wifi_blinky.rs | 6 +- examples/rp/src/bin/wifi_scan.rs | 6 +- examples/rp/src/bin/wifi_tcp_server.rs | 6 +- tests/rp/src/bin/cyw43-perf.rs | 6 +- tests/rp/src/bin/ethernet_w5100s_perf.rs | 8 +- tests/rp/src/bin/uart.rs | 6 +- tests/rp/src/bin/uart_buffered.rs | 6 +- tests/rp/src/bin/uart_dma.rs | 6 +- 17 files changed, 109 insertions(+), 123 deletions(-) diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 5efab10e4..8c217b995 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -7,25 +7,24 @@ use core::slice; use cyw43::SpiBusCyw43; use embassy_rp::dma::Channel; -use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate}; +use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; use embassy_rp::pio::{instr, Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; use embassy_rp::{Peripheral, PeripheralRef}; use fixed::FixedU32; use pio_proc::pio_asm; /// SPI comms driven by PIO. -pub struct PioSpi<'d, CS: Pin, PIO: Instance, const SM: usize, DMA> { - cs: Output<'d, CS>, +pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA> { + cs: Output<'d>, sm: StateMachine<'d, PIO, SM>, irq: Irq<'d, PIO, 0>, dma: PeripheralRef<'d, DMA>, wrap_target: u8, } -impl<'d, CS, PIO, const SM: usize, DMA> PioSpi<'d, CS, PIO, SM, DMA> +impl<'d, PIO, const SM: usize, DMA> PioSpi<'d, PIO, SM, DMA> where DMA: Channel, - CS: Pin, PIO: Instance, { /// Create a new instance of PioSpi. @@ -33,7 +32,7 @@ where common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, irq: Irq<'d, PIO, 0>, - cs: Output<'d, CS>, + cs: Output<'d>, dio: DIO, clk: CLK, dma: impl Peripheral

+ 'd, @@ -206,9 +205,8 @@ where } } -impl<'d, CS, PIO, const SM: usize, DMA> SpiBusCyw43 for PioSpi<'d, CS, PIO, SM, DMA> +impl<'d, PIO, const SM: usize, DMA> SpiBusCyw43 for PioSpi<'d, PIO, SM, DMA> where - CS: Pin, PIO: Instance, DMA: Channel, { diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 7eb57bbe6..93b29bbf9 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -8,6 +8,7 @@ use core::task::{Context, Poll}; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +use self::sealed::Pin as _; use crate::interrupt::InterruptExt; use crate::pac::common::{Reg, RW}; use crate::pac::SIO; @@ -105,14 +106,14 @@ pub struct DormantWakeConfig { } /// GPIO input driver. -pub struct Input<'d, T: Pin> { - pin: Flex<'d, T>, +pub struct Input<'d> { + pin: Flex<'d>, } -impl<'d, T: Pin> Input<'d, T> { +impl<'d> Input<'d> { /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { let mut pin = Flex::new(pin); pin.set_as_input(); pin.set_pull(pull); @@ -175,7 +176,7 @@ impl<'d, T: Pin> Input<'d, T> { /// Configure dormant wake. #[inline] - pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake { + pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> { self.pin.dormant_wake(cfg) } } @@ -255,14 +256,12 @@ fn IO_IRQ_QSPI() { } #[must_use = "futures do nothing unless you `.await` or poll them"] -struct InputFuture<'a, T: Pin> { - pin: PeripheralRef<'a, T>, +struct InputFuture<'d> { + pin: PeripheralRef<'d, AnyPin>, } -impl<'d, T: Pin> InputFuture<'d, T> { - /// Create a new future wiating for input trigger. - pub fn new(pin: impl Peripheral

+ 'd, level: InterruptTrigger) -> Self { - into_ref!(pin); +impl<'d> InputFuture<'d> { + fn new(pin: PeripheralRef<'d, AnyPin>, level: InterruptTrigger) -> Self { let pin_group = (pin.pin() % 8) as usize; // first, clear the INTR register bits. without this INTR will still // contain reports of previous edges, causing the IRQ to fire early @@ -305,7 +304,7 @@ impl<'d, T: Pin> InputFuture<'d, T> { } } -impl<'d, T: Pin> Future for InputFuture<'d, T> { +impl<'d> Future for InputFuture<'d> { type Output = (); fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -344,14 +343,14 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> { } /// GPIO output driver. -pub struct Output<'d, T: Pin> { - pin: Flex<'d, T>, +pub struct Output<'d> { + pin: Flex<'d>, } -impl<'d, T: Pin> Output<'d, T> { +impl<'d> Output<'d> { /// Create GPIO output driver for a [Pin] with the provided [Level]. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), @@ -418,14 +417,14 @@ impl<'d, T: Pin> Output<'d, T> { } /// GPIO output open-drain. -pub struct OutputOpenDrain<'d, T: Pin> { - pin: Flex<'d, T>, +pub struct OutputOpenDrain<'d> { + pin: Flex<'d>, } -impl<'d, T: Pin> OutputOpenDrain<'d, T> { +impl<'d> OutputOpenDrain<'d> { /// Create GPIO output driver for a [Pin] in open drain mode with the provided [Level]. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { let mut pin = Flex::new(pin); pin.set_low(); match initial_output { @@ -548,17 +547,17 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { /// This pin can be either an input or output pin. The output level register bit will remain /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output /// mode. -pub struct Flex<'d, T: Pin> { - pin: PeripheralRef<'d, T>, +pub struct Flex<'d> { + pin: PeripheralRef<'d, AnyPin>, } -impl<'d, T: Pin> Flex<'d, T> { +impl<'d> Flex<'d> { /// Wrap the pin in a `Flex`. /// /// The pin remains disconnected. The initial output level is unspecified, but can be changed /// before the pin is put into output mode. #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { + pub fn new(pin: impl Peripheral

+ 'd) -> Self { into_ref!(pin); pin.pad_ctrl().write(|w| { @@ -569,7 +568,7 @@ impl<'d, T: Pin> Flex<'d, T> { w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _); }); - Self { pin } + Self { pin: pin.map_into() } } #[inline] @@ -716,36 +715,36 @@ impl<'d, T: Pin> Flex<'d, T> { /// Wait until the pin is high. If it is already high, return immediately. #[inline] pub async fn wait_for_high(&mut self) { - InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await; + InputFuture::new(self.pin.reborrow(), InterruptTrigger::LevelHigh).await; } /// Wait until the pin is low. If it is already low, return immediately. #[inline] pub async fn wait_for_low(&mut self) { - InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await; + InputFuture::new(self.pin.reborrow(), InterruptTrigger::LevelLow).await; } /// Wait for the pin to undergo a transition from low to high. #[inline] pub async fn wait_for_rising_edge(&mut self) { - InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await; + InputFuture::new(self.pin.reborrow(), InterruptTrigger::EdgeHigh).await; } /// Wait for the pin to undergo a transition from high to low. #[inline] pub async fn wait_for_falling_edge(&mut self) { - InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await; + InputFuture::new(self.pin.reborrow(), InterruptTrigger::EdgeLow).await; } /// Wait for the pin to undergo any transition, i.e low to high OR high to low. #[inline] pub async fn wait_for_any_edge(&mut self) { - InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await; + InputFuture::new(self.pin.reborrow(), InterruptTrigger::AnyEdge).await; } /// Configure dormant wake. #[inline] - pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake { + pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> { let idx = self.pin._pin() as usize; self.pin.io().intr(idx / 8).write(|w| { w.set_edge_high(idx % 8, cfg.edge_high); @@ -764,7 +763,7 @@ impl<'d, T: Pin> Flex<'d, T> { } } -impl<'d, T: Pin> Drop for Flex<'d, T> { +impl<'d> Drop for Flex<'d> { #[inline] fn drop(&mut self) { let idx = self.pin._pin() as usize; @@ -782,12 +781,12 @@ impl<'d, T: Pin> Drop for Flex<'d, T> { } /// Dormant wake driver. -pub struct DormantWake<'w, T: Pin> { - pin: PeripheralRef<'w, T>, +pub struct DormantWake<'w> { + pin: PeripheralRef<'w, AnyPin>, cfg: DormantWakeConfig, } -impl<'w, T: Pin> Drop for DormantWake<'w, T> { +impl<'w> Drop for DormantWake<'w> { fn drop(&mut self) { let idx = self.pin._pin() as usize; self.pin.io().intr(idx / 8).write(|w| { @@ -970,7 +969,7 @@ mod eh02 { use super::*; - impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { + impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { type Error = Infallible; fn is_high(&self) -> Result { @@ -982,7 +981,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { + impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> { type Error = Infallible; fn set_high(&mut self) -> Result<(), Self::Error> { @@ -994,7 +993,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { + impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> { fn is_set_high(&self) -> Result { Ok(self.is_set_high()) } @@ -1004,7 +1003,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> { + impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> { type Error = Infallible; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -1012,7 +1011,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d, T> { + impl<'d> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d> { type Error = Infallible; fn is_high(&self) -> Result { @@ -1024,7 +1023,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, T> { + impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> { type Error = Infallible; #[inline] @@ -1038,7 +1037,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { + impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d> { fn is_set_high(&self) -> Result { Ok(self.is_set_high()) } @@ -1048,7 +1047,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d, T> { + impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d> { type Error = Infallible; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -1056,7 +1055,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { + impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> { type Error = Infallible; fn is_high(&self) -> Result { @@ -1068,7 +1067,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { + impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> { type Error = Infallible; fn set_high(&mut self) -> Result<(), Self::Error> { @@ -1080,7 +1079,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { + impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> { fn is_set_high(&self) -> Result { Ok(self.is_set_high()) } @@ -1090,7 +1089,7 @@ mod eh02 { } } - impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> { + impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> { type Error = Infallible; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -1099,11 +1098,11 @@ mod eh02 { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for Input<'d> { fn is_high(&mut self) -> Result { Ok((*self).is_high()) } @@ -1113,11 +1112,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { +impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> { fn set_high(&mut self) -> Result<(), Self::Error> { Ok(self.set_high()) } @@ -1127,7 +1126,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { +impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> { fn is_set_high(&mut self) -> Result { Ok((*self).is_set_high()) } @@ -1137,11 +1136,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d> { fn set_high(&mut self) -> Result<(), Self::Error> { Ok(self.set_high()) } @@ -1151,7 +1150,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d> { fn is_set_high(&mut self) -> Result { Ok((*self).is_set_high()) } @@ -1161,7 +1160,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain< } } -impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d> { fn is_high(&mut self) -> Result { Ok((*self).is_high()) } @@ -1171,11 +1170,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> { type Error = Infallible; } -impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> { fn is_high(&mut self) -> Result { Ok((*self).is_high()) } @@ -1185,7 +1184,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> { fn set_high(&mut self) -> Result<(), Self::Error> { Ok(self.set_high()) } @@ -1195,7 +1194,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { +impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> { fn is_set_high(&mut self) -> Result { Ok((*self).is_set_high()) } @@ -1205,7 +1204,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> { +impl<'d> embedded_hal_async::digital::Wait for Flex<'d> { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { self.wait_for_high().await; Ok(()) @@ -1232,7 +1231,7 @@ impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> { } } -impl<'d, T: Pin> embedded_hal_async::digital::Wait for Input<'d, T> { +impl<'d> embedded_hal_async::digital::Wait for Input<'d> { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { self.wait_for_high().await; Ok(()) @@ -1259,7 +1258,7 @@ impl<'d, T: Pin> embedded_hal_async::digital::Wait for Input<'d, T> { } } -impl<'d, T: Pin> embedded_hal_async::digital::Wait for OutputOpenDrain<'d, T> { +impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { self.wait_for_high().await; Ok(()) diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs index a03f3a592..a57b513d6 100644 --- a/examples/rp/src/bin/blinky_two_tasks.rs +++ b/examples/rp/src/bin/blinky_two_tasks.rs @@ -14,7 +14,7 @@ use embassy_time::{Duration, Ticker}; use gpio::{AnyPin, Level, Output}; use {defmt_rtt as _, panic_probe as _}; -type LedType = Mutex>>; +type LedType = Mutex>>; static LED: LedType = Mutex::new(None); #[embassy_executor::main] diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index a16ea0007..bd52cadca 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -13,7 +13,7 @@ use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::*; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Level, Output, Pull}; -use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; +use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; @@ -27,9 +27,9 @@ async fn ethernet_task( runner: Runner< 'static, W5500, - ExclusiveDevice, Output<'static, PIN_17>, Delay>, - Input<'static, PIN_21>, - Output<'static, PIN_20>, + ExclusiveDevice, Output<'static>, Delay>, + Input<'static>, + Output<'static>, >, ) -> ! { runner.run().await diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 975b3d385..3e4fbd2e6 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -15,7 +15,7 @@ use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::*; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Level, Output, Pull}; -use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; +use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; @@ -29,9 +29,9 @@ async fn ethernet_task( runner: Runner< 'static, W5500, - ExclusiveDevice, Output<'static, PIN_17>, Delay>, - Input<'static, PIN_21>, - Output<'static, PIN_20>, + ExclusiveDevice, Output<'static>, Delay>, + Input<'static>, + Output<'static>, >, ) -> ! { runner.run().await diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 489af2c76..5532851f3 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -14,7 +14,7 @@ use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::*; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Level, Output, Pull}; -use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; +use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; @@ -28,9 +28,9 @@ async fn ethernet_task( runner: Runner< 'static, W5500, - ExclusiveDevice, Output<'static, PIN_17>, Delay>, - Input<'static, PIN_21>, - Output<'static, PIN_20>, + ExclusiveDevice, Output<'static>, Delay>, + Input<'static>, + Output<'static>, >, ) -> ! { runner.run().await diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 41bd7d077..adb1d8941 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -14,7 +14,7 @@ use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::*; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Level, Output, Pull}; -use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; +use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; @@ -27,9 +27,9 @@ async fn ethernet_task( runner: Runner< 'static, W5500, - ExclusiveDevice, Output<'static, PIN_17>, Delay>, - Input<'static, PIN_21>, - Output<'static, PIN_20>, + ExclusiveDevice, Output<'static>, Delay>, + Input<'static>, + Output<'static>, >, ) -> ! { runner.run().await diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index a1678d99a..c7b087476 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs @@ -9,7 +9,6 @@ use defmt::*; use embassy_executor::Executor; use embassy_rp::gpio::{Level, Output}; use embassy_rp::multicore::{spawn_core1, Stack}; -use embassy_rp::peripherals::PIN_25; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::Timer; @@ -52,7 +51,7 @@ async fn core0_task() { } #[embassy_executor::task] -async fn core1_task(mut led: Output<'static, PIN_25>) { +async fn core1_task(mut led: Output<'static>) { info!("Hello from core 1"); loop { match CHANNEL.receive().await { diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 1bd75607e..b60852359 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -14,7 +14,7 @@ use embassy_net::tcp::TcpSocket; use embassy_net::{Config, Stack, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; +use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::Duration; use embedded_io_async::Write; @@ -26,9 +26,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, -) -> ! { +async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 1ed74993c..18eefe41f 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -10,7 +10,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; +use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::{Duration, Timer}; use static_cell::StaticCell; @@ -21,9 +21,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, -) -> ! { +async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index e678209dd..e0f85a6b0 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -13,7 +13,7 @@ use embassy_executor::Spawner; use embassy_net::Stack; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; +use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -23,9 +23,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, -) -> ! { +async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index c346f1ded..f1afc4a00 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -14,7 +14,7 @@ use embassy_net::tcp::TcpSocket; use embassy_net::{Config, Stack, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; +use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; @@ -29,9 +29,7 @@ const WIFI_NETWORK: &str = "EmbassyTest"; const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; #[embassy_executor::task] -async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, -) -> ! { +async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index a1b2946e6..b46ae670a 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -7,7 +7,7 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_net::{Config, Stack, StackResources}; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; +use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::{bind_interrupts, rom_data}; use static_cell::StaticCell; @@ -24,9 +24,7 @@ const WIFI_NETWORK: &str = "EmbassyTest"; const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; #[embassy_executor::task] -async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, -) -> ! { +async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs index 8c9089d0e..5d5547773 100644 --- a/tests/rp/src/bin/ethernet_w5100s_perf.rs +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs @@ -10,7 +10,7 @@ use embassy_net_wiznet::chip::W5100S; use embassy_net_wiznet::*; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Level, Output, Pull}; -use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; +use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; @@ -23,9 +23,9 @@ async fn ethernet_task( runner: Runner< 'static, W5100S, - ExclusiveDevice, Output<'static, PIN_17>, Delay>, - Input<'static, PIN_21>, - Output<'static, PIN_20>, + ExclusiveDevice, Output<'static>, Delay>, + Input<'static>, + Output<'static>, >, ) -> ! { runner.run().await diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs index f4d641175..6e6e5517b 100644 --- a/tests/rp/src/bin/uart.rs +++ b/tests/rp/src/bin/uart.rs @@ -21,7 +21,7 @@ fn read1(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Resu Ok(buf) } -async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option) { +async fn send(pin: &mut Output<'_>, v: u8, parity: Option) { pin.set_low(); Timer::after_millis(1).await; for i in 0..8 { @@ -116,7 +116,7 @@ async fn main(_spawner: Spawner) { config.parity = Parity::ParityEven; let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config); - async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u8) { + async fn chr(pin: &mut Output<'_>, v: u8, parity: u8) { send(pin, v, Some(parity != 0)).await; } @@ -142,7 +142,7 @@ async fn main(_spawner: Spawner) { config.baudrate = 1000; let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config); - async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { + async fn chr(pin: &mut Output<'_>, v: u8, good: bool) { if good { send(pin, v, None).await; } else { diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs index 14647e44a..d68c23cbd 100644 --- a/tests/rp/src/bin/uart_buffered.rs +++ b/tests/rp/src/bin/uart_buffered.rs @@ -36,7 +36,7 @@ async fn read1(uart: &mut BufferedUartRx<'_, impl Instance>) -> } } -async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option) { +async fn send(pin: &mut Output<'_>, v: u8, parity: Option) { pin.set_low(); Timer::after_millis(1).await; for i in 0..8 { @@ -161,7 +161,7 @@ async fn main(_spawner: Spawner) { let rx_buf = &mut [0u8; 16]; let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config); - async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) { + async fn chr(pin: &mut Output<'_>, v: u8, parity: u32) { send(pin, v, Some(parity != 0)).await; } @@ -208,7 +208,7 @@ async fn main(_spawner: Spawner) { let rx_buf = &mut [0u8; 16]; let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config); - async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { + async fn chr(pin: &mut Output<'_>, v: u8, good: bool) { if good { send(pin, v, None).await; } else { diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs index 130d8599e..edc87175a 100644 --- a/tests/rp/src/bin/uart_dma.rs +++ b/tests/rp/src/bin/uart_dma.rs @@ -27,7 +27,7 @@ async fn read1(uart: &mut UartRx<'_, impl Instance, Async>) -> R Ok(buf) } -async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option) { +async fn send(pin: &mut Output<'_>, v: u8, parity: Option) { pin.set_low(); Timer::after_millis(1).await; for i in 0..8 { @@ -160,7 +160,7 @@ async fn main(_spawner: Spawner) { config.parity = Parity::ParityEven; let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config); - async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) { + async fn chr(pin: &mut Output<'_>, v: u8, parity: u32) { send(pin, v, Some(parity != 0)).await; } @@ -205,7 +205,7 @@ async fn main(_spawner: Spawner) { config.baudrate = 1000; let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config); - async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { + async fn chr(pin: &mut Output<'_>, v: u8, good: bool) { if good { send(pin, v, None).await; } else { From 40e9fc36dc3af75a9625413504d4e90a0d5f35d9 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 23 Jan 2024 12:06:28 +0100 Subject: [PATCH 291/760] Update faq.adoc Don't suggest people disable debuginfo, and explain why --- docs/modules/ROOT/pages/faq.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index 147f119b0..bf061d978 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -44,11 +44,12 @@ The first step to managing your binary size is to set up your link:https://doc.r [source,toml] ---- [profile.release] -debug = false lto = true opt-level = "s" incremental = false codegen-units = 1 +# note: debug = true is okay - debuginfo isn't flashed to the device! +debug = true ---- All of these flags are elaborated on in the Rust Book page linked above. From 4410aacafb2141c1c0838598d11581e24aab3b0f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 19 Jan 2024 23:13:46 +0100 Subject: [PATCH 292/760] feat: add basic support for nRF51 chips to embassy-nrf --- embassy-nrf/Cargo.toml | 8 ++ embassy-nrf/src/chips/nrf51.rs | 168 ++++++++++++++++++++++++++++++ embassy-nrf/src/gpio.rs | 12 +++ embassy-nrf/src/lib.rs | 19 +++- embassy-nrf/src/ppi/ppi.rs | 1 + embassy-nrf/src/rng.rs | 2 +- embassy-nrf/src/time_driver.rs | 2 +- embassy-nrf/src/timer.rs | 16 ++- examples/nrf51/.cargo/config.toml | 9 ++ examples/nrf51/Cargo.toml | 20 ++++ examples/nrf51/build.rs | 35 +++++++ examples/nrf51/memory.x | 5 + examples/nrf51/src/bin/blinky.rs | 21 ++++ 13 files changed, 311 insertions(+), 7 deletions(-) create mode 100644 embassy-nrf/src/chips/nrf51.rs create mode 100644 examples/nrf51/.cargo/config.toml create mode 100644 examples/nrf51/Cargo.toml create mode 100644 examples/nrf51/build.rs create mode 100644 examples/nrf51/memory.x create mode 100644 examples/nrf51/src/bin/blinky.rs diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 10f268b51..529a56c46 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -15,6 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/s features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"] flavors = [ + { regex_feature = "nrf51", target = "thumbv6m-none-eabi" }, { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" }, { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" }, @@ -28,6 +29,7 @@ rustdoc-args = ["--cfg", "docsrs"] default = ["rt"] ## Cortex-M runtime (enabled by default) rt = [ + "nrf51-pac?/rt", "nrf52805-pac?/rt", "nrf52810-pac?/rt", "nrf52811-pac?/rt", @@ -71,6 +73,8 @@ reset-pin-as-gpio = [] qspi-multiwrite-flash = [] #! ### Chip selection features +## nRF51 +nrf51 = ["nrf51-pac", "_nrf51", "portable-atomic/unsafe-assume-single-core"] ## nRF52805 nrf52805 = ["nrf52805-pac", "_nrf52"] ## nRF52810 @@ -104,6 +108,7 @@ _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"] _nrf5340 = ["_gpio-p1", "_dppi"] _nrf9160 = ["nrf9160-pac", "_dppi"] _nrf52 = ["_ppi"] +_nrf51 = ["_ppi"] _time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"] @@ -132,6 +137,8 @@ embedded-hal-async = { version = "1.0" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } +portable-atomic = { version = "1", default-features = false, features = ["require-cas"] } + defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" @@ -144,6 +151,7 @@ embedded-storage-async = "0.4.0" cfg-if = "1.0.0" document-features = "0.2.7" +nrf51-pac = { version = "0.12.0", optional = true } nrf52805-pac = { version = "0.12.0", optional = true } nrf52810-pac = { version = "0.12.0", optional = true } nrf52811-pac = { version = "0.12.0", optional = true } diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs new file mode 100644 index 000000000..f5db4b847 --- /dev/null +++ b/embassy-nrf/src/chips/nrf51.rs @@ -0,0 +1,168 @@ +pub use nrf51_pac as pac; + +/// The maximum buffer size that the EasyDMA can send/recv in one operation. +pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; +pub const FORCE_COPY_BUFFER_SIZE: usize = 256; + +pub const FLASH_SIZE: usize = 128 * 1024; + +embassy_hal_internal::peripherals! { + // RTC + RTC0, + RTC1, + + // WDT + WDT, + + // NVMC + NVMC, + + // RNG + RNG, + + // UARTE + UART0, + + // SPI/TWI + TWI0, + SPI0, + + // ADC + ADC, + + // TIMER + TIMER0, + TIMER1, + TIMER2, + + // GPIOTE + GPIOTE_CH0, + GPIOTE_CH1, + GPIOTE_CH2, + GPIOTE_CH3, + + // PPI + PPI_CH0, + PPI_CH1, + PPI_CH2, + PPI_CH3, + PPI_CH4, + PPI_CH5, + PPI_CH6, + PPI_CH7, + PPI_CH8, + PPI_CH9, + PPI_CH10, + PPI_CH11, + PPI_CH12, + PPI_CH13, + PPI_CH14, + PPI_CH15, + + PPI_GROUP0, + PPI_GROUP1, + PPI_GROUP2, + PPI_GROUP3, + + // GPIO port 0 + P0_00, + P0_01, + P0_02, + P0_03, + P0_04, + P0_05, + P0_06, + P0_07, + P0_08, + P0_09, + P0_10, + P0_11, + P0_12, + P0_13, + P0_14, + P0_15, + P0_16, + P0_17, + P0_18, + P0_19, + P0_20, + P0_21, + P0_22, + P0_23, + P0_24, + P0_25, + P0_26, + P0_27, + P0_28, + P0_29, + P0_30, + P0_31, + + // TEMP + TEMP, +} + +// impl_timer!(TIMER0, TIMER0, TIMER0); +// impl_timer!(TIMER1, TIMER1, TIMER1); +// impl_timer!(TIMER2, TIMER2, TIMER2); + +impl_pin!(P0_00, 0, 0); +impl_pin!(P0_01, 0, 1); +impl_pin!(P0_02, 0, 2); +impl_pin!(P0_03, 0, 3); +impl_pin!(P0_04, 0, 4); +impl_pin!(P0_05, 0, 5); +impl_pin!(P0_06, 0, 6); +impl_pin!(P0_07, 0, 7); +impl_pin!(P0_08, 0, 8); +impl_pin!(P0_09, 0, 9); +impl_pin!(P0_10, 0, 10); +impl_pin!(P0_11, 0, 11); +impl_pin!(P0_12, 0, 12); +impl_pin!(P0_13, 0, 13); +impl_pin!(P0_14, 0, 14); +impl_pin!(P0_15, 0, 15); +impl_pin!(P0_16, 0, 16); +impl_pin!(P0_17, 0, 17); +impl_pin!(P0_18, 0, 18); +impl_pin!(P0_19, 0, 19); +impl_pin!(P0_20, 0, 20); +impl_pin!(P0_21, 0, 21); +impl_pin!(P0_22, 0, 22); +impl_pin!(P0_23, 0, 23); +impl_pin!(P0_24, 0, 24); +impl_pin!(P0_25, 0, 25); +impl_pin!(P0_26, 0, 26); +impl_pin!(P0_27, 0, 27); +impl_pin!(P0_28, 0, 28); +impl_pin!(P0_29, 0, 29); +impl_pin!(P0_30, 0, 30); +impl_pin!(P0_31, 0, 31); + +embassy_hal_internal::interrupt_mod!( + POWER_CLOCK, + RADIO, + UART0, + SPI0_TWI0, + SPI1_TWI1, + GPIOTE, + ADC, + TIMER0, + TIMER1, + TIMER2, + RTC0, + TEMP, + RNG, + ECB, + CCM_AAR, + WDT, + RTC1, + QDEC, + LPCOMP, + SWI0, + SWI1, + SWI2, + SWI3, + SWI4, + SWI5, +); diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 287811e61..164363460 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -8,8 +8,17 @@ use cfg_if::cfg_if; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; use self::sealed::Pin as _; + +#[cfg(not(feature = "nrf51"))] use crate::pac::p0 as gpio; +#[cfg(not(feature = "nrf51"))] use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A}; + +#[cfg(feature = "nrf51")] +use crate::pac::gpio; +#[cfg(feature = "nrf51")] +use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A}; + use crate::{pac, Peripheral}; /// A GPIO port with up to 32 pins. @@ -376,6 +385,9 @@ pub(crate) mod sealed { fn block(&self) -> &gpio::RegisterBlock { unsafe { match self.pin_port() / 32 { + #[cfg(feature = "nrf51")] + 0 => &*pac::GPIO::ptr(), + #[cfg(not(feature = "nrf51"))] 0 => &*pac::P0::ptr(), #[cfg(feature = "_gpio-p1")] 1 => &*pac::P1::ptr(), diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index d9c92a76d..923e48ec2 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -40,6 +40,7 @@ pub(crate) mod util; #[cfg(feature = "_time-driver")] mod time_driver; +#[cfg(not(feature = "nrf51"))] pub mod buffered_uarte; pub mod gpio; #[cfg(feature = "gpiote")] @@ -58,7 +59,12 @@ pub mod nvmc; ))] pub mod pdm; pub mod ppi; -#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] +#[cfg(not(any( + feature = "nrf51", + feature = "nrf52805", + feature = "nrf52820", + feature = "_nrf5340-net" +)))] pub mod pwm; #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))] pub mod qdec; @@ -66,15 +72,20 @@ pub mod qdec; pub mod qspi; #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))] pub mod rng; -#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] +#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] pub mod saadc; +#[cfg(not(feature = "nrf51"))] pub mod spim; +#[cfg(not(feature = "nrf51"))] pub mod spis; #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] pub mod temp; pub mod timer; +#[cfg(not(feature = "nrf51"))] pub mod twim; +#[cfg(not(feature = "nrf51"))] pub mod twis; +#[cfg(not(feature = "nrf51"))] pub mod uarte; #[cfg(any( feature = "_nrf5340-app", @@ -87,6 +98,7 @@ pub mod usb; pub mod wdt; // This mod MUST go last, so that it sees all the `impl_foo!` macros +#[cfg_attr(feature = "nrf51", path = "chips/nrf51.rs")] #[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")] #[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")] #[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")] @@ -374,6 +386,7 @@ pub fn init(config: config::Config) -> Peripherals { let mut needs_reset = false; // Setup debug protection. + #[cfg(not(feature = "nrf51"))] match config.debug { config::Debug::Allowed => { #[cfg(feature = "_nrf52")] @@ -489,7 +502,7 @@ pub fn init(config: config::Config) -> Peripherals { } // Configure LFCLK. - #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] + #[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf9160")))] match config.lfclk_source { config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index 3e9e9fc81..4a12764ad 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -84,6 +84,7 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for let n = self.ch.number(); r.ch[n].eep.write(|w| unsafe { w.bits(0) }); r.ch[n].tep.write(|w| unsafe { w.bits(0) }); + #[cfg(not(feature = "nrf51"))] r.fork[n].tep.write(|w| unsafe { w.bits(0) }); } } diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index e2803f0d3..7f2e76a55 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -5,7 +5,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::ptr; -use core::sync::atomic::{AtomicPtr, Ordering}; +use portable_atomic::{AtomicPtr, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 042f7c5f7..855d133df 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -1,6 +1,6 @@ use core::cell::Cell; -use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use core::{mem, ptr}; +use portable_atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 3dbfdac42..272fffc0a 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -122,12 +122,16 @@ impl<'d, T: Instance> Timer<'d, T> { // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. this.stop(); + #[cfg(not(feature = "nrf51"))] if is_counter { regs.mode.write(|w| w.mode().low_power_counter()); } else { regs.mode.write(|w| w.mode().timer()); } + #[cfg(feature = "nrf51")] + regs.mode.write(|w| w.mode().timer()); + // Make the counter's max value as high as possible. // TODO: is there a reason someone would want to set this lower? regs.bitmode.write(|w| w.bitmode()._32bit()); @@ -238,7 +242,11 @@ pub struct Cc<'d, T: Instance> { impl<'d, T: Instance> Cc<'d, T> { /// Get the current value stored in the register. pub fn read(&self) -> u32 { - T::regs().cc[self.n].read().cc().bits() + #[cfg(not(feature = "nrf51"))] + return T::regs().cc[self.n].read().cc().bits(); + + #[cfg(feature = "nrf51")] + return T::regs().cc[self.n].read().bits(); } /// Set the value stored in the register. @@ -246,7 +254,11 @@ impl<'d, T: Instance> Cc<'d, T> { /// `event_compare` will fire when the timer's counter reaches this value. pub fn write(&self, value: u32) { // SAFETY: there are no invalid values for the CC register. - T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }) + #[cfg(not(feature = "nrf51"))] + T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }); + + #[cfg(feature = "nrf51")] + T::regs().cc[self.n].write(|w| unsafe { w.bits(value) }); } /// Capture the current value of the timer's counter in this register, and return it. diff --git a/examples/nrf51/.cargo/config.toml b/examples/nrf51/.cargo/config.toml new file mode 100644 index 000000000..84f0e1572 --- /dev/null +++ b/examples/nrf51/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF51822_xxAA" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml new file mode 100644 index 000000000..8507c415c --- /dev/null +++ b/examples/nrf51/Cargo.toml @@ -0,0 +1,20 @@ +[package] +edition = "2021" +name = "embassy-nrf51-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time", "rt"] } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7" +panic-probe = { version = "0.3", features = ["print-defmt"] } + +[profile.release] +debug = 2 diff --git a/examples/nrf51/build.rs b/examples/nrf51/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf51/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + 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/nrf51/memory.x b/examples/nrf51/memory.x new file mode 100644 index 000000000..ad5f80292 --- /dev/null +++ b/examples/nrf51/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 32K +} diff --git a/examples/nrf51/src/bin/blinky.rs b/examples/nrf51/src/bin/blinky.rs new file mode 100644 index 000000000..ff686c6ae --- /dev/null +++ b/examples/nrf51/src/bin/blinky.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P0_21, Level::Low, OutputDrive::Standard); + + loop { + led.set_high(); + Timer::after_millis(300).await; + led.set_low(); + Timer::after_millis(300).await; + } +} From 2a810a1a6ad5351ef2248133855dc01ba4b7a76b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 20 Jan 2024 16:23:12 +0100 Subject: [PATCH 293/760] rustfmt --- embassy-nrf/src/rng.rs | 2 +- examples/nrf51/src/bin/blinky.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 7f2e76a55..79088b25d 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -5,8 +5,8 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::ptr; -use portable_atomic::{AtomicPtr, Ordering}; use core::task::Poll; +use portable_atomic::{AtomicPtr, Ordering}; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; diff --git a/examples/nrf51/src/bin/blinky.rs b/examples/nrf51/src/bin/blinky.rs index ff686c6ae..7c12ffcbc 100644 --- a/examples/nrf51/src/bin/blinky.rs +++ b/examples/nrf51/src/bin/blinky.rs @@ -8,7 +8,6 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_nrf::init(Default::default()); let mut led = Output::new(p.P0_21, Level::Low, OutputDrive::Standard); From 53ea850d289384ea1810419b980ad73bcd556a04 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 20 Jan 2024 16:24:02 +0100 Subject: [PATCH 294/760] rustfmt again --- embassy-nrf/src/gpio.rs | 11 ++++------- embassy-nrf/src/rng.rs | 2 +- embassy-nrf/src/time_driver.rs | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 164363460..b1eb8ae87 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -8,17 +8,14 @@ use cfg_if::cfg_if; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; use self::sealed::Pin as _; - -#[cfg(not(feature = "nrf51"))] -use crate::pac::p0 as gpio; -#[cfg(not(feature = "nrf51"))] -use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A}; - #[cfg(feature = "nrf51")] use crate::pac::gpio; #[cfg(feature = "nrf51")] use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A}; - +#[cfg(not(feature = "nrf51"))] +use crate::pac::p0 as gpio; +#[cfg(not(feature = "nrf51"))] +use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A}; use crate::{pac, Peripheral}; /// A GPIO port with up to 32 pins. diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 79088b25d..966097578 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -6,11 +6,11 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::ptr; use core::task::Poll; -use portable_atomic::{AtomicPtr, Ordering}; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +use portable_atomic::{AtomicPtr, Ordering}; use crate::interrupt::typelevel::Interrupt; use crate::{interrupt, Peripheral}; diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 855d133df..0f31c5c9c 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -1,11 +1,11 @@ use core::cell::Cell; use core::{mem, ptr}; -use portable_atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; use embassy_time_driver::{AlarmHandle, Driver}; +use portable_atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; From 25f82538aed809c17264bab8cddad30004fb60cf Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 20 Jan 2024 20:56:24 +0100 Subject: [PATCH 295/760] fix doc comment --- examples/nrf51/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nrf51/.cargo/config.toml b/examples/nrf51/.cargo/config.toml index 84f0e1572..29d35a9b4 100644 --- a/examples/nrf51/.cargo/config.toml +++ b/examples/nrf51/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +# replace nRF51822_xxAA with your chip as listed in `probe-rs chip list` runner = "probe-rs run --chip nRF51822_xxAA" [build] From 6126183db852fbf4187d4a5516cc8bd6d3697443 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 23 Jan 2024 23:16:06 +0100 Subject: [PATCH 296/760] fix: remove portable-atomic from rng --- embassy-nrf/src/rng.rs | 127 ++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 60 deletions(-) diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 966097578..6145dd14f 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -9,8 +9,6 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; -use portable_atomic::{AtomicPtr, Ordering}; use crate::interrupt::typelevel::Interrupt; use crate::{interrupt, Peripheral}; @@ -22,7 +20,6 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let s = T::state(); let r = T::regs(); // Clear the event. @@ -30,46 +27,26 @@ impl interrupt::typelevel::Handler for InterruptHandl // Mutate the slice within a critical section, // so that the future isn't dropped in between us loading the pointer and actually dereferencing it. - let (ptr, end) = critical_section::with(|_| { - let ptr = s.ptr.load(Ordering::Relaxed); + critical_section::with(|cs| { + let mut state = T::state().borrow_mut(cs); // We need to make sure we haven't already filled the whole slice, // in case the interrupt fired again before the executor got back to the future. - let end = s.end.load(Ordering::Relaxed); - if !ptr.is_null() && ptr != end { + if !state.ptr.is_null() && state.ptr != state.end { // If the future was dropped, the pointer would have been set to null, // so we're still good to mutate the slice. // The safety contract of `Rng::new` means that the future can't have been dropped // without calling its destructor. unsafe { - *ptr = r.value.read().value().bits(); + *state.ptr = r.value.read().value().bits(); + state.ptr = state.ptr.add(1); } + + if state.ptr == state.end { + state.waker.wake(); + } + } - (ptr, end) }); - - if ptr.is_null() || ptr == end { - // If the future was dropped, there's nothing to do. - // If `ptr == end`, we were called by mistake, so return. - return; - } - - let new_ptr = unsafe { ptr.add(1) }; - match s - .ptr - .compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed) - { - Ok(_) => { - let end = s.end.load(Ordering::Relaxed); - // It doesn't matter if `end` was changed under our feet, because then this will just be false. - if new_ptr == end { - s.waker.wake(); - } - } - Err(_) => { - // If the future was dropped or finished, there's no point trying to wake it. - // It will have already stopped the RNG, so there's no need to do that either. - } - } } } @@ -136,13 +113,15 @@ impl<'d, T: Instance> Rng<'d, T> { return; // Nothing to fill } - let s = T::state(); let range = dest.as_mut_ptr_range(); // Even if we've preempted the interrupt, it can't preempt us again, // so we don't need to worry about the order we write these in. - s.ptr.store(range.start, Ordering::Relaxed); - s.end.store(range.end, Ordering::Relaxed); + critical_section::with(|cs| { + let mut state = T::state().borrow_mut(cs); + state.ptr = range.start; + state.end = range.end; + }); self.enable_irq(); self.start(); @@ -151,24 +130,24 @@ impl<'d, T: Instance> Rng<'d, T> { self.stop(); self.disable_irq(); - // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. - s.ptr.store(ptr::null_mut(), Ordering::Relaxed); - s.end.store(ptr::null_mut(), Ordering::Relaxed); + critical_section::with(|cs| { + let mut state = T::state().borrow_mut(cs); + state.ptr = ptr::null_mut(); + state.end = ptr::null_mut(); + }); }); poll_fn(|cx| { - s.waker.register(cx.waker()); - - // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. - let end = s.end.load(Ordering::Relaxed); - let ptr = s.ptr.load(Ordering::Relaxed); - - if ptr == end { - // We're done. - Poll::Ready(()) - } else { - Poll::Pending - } + critical_section::with(|cs| { + let mut s = T::state().borrow_mut(cs); + s.waker.register(cx.waker()); + if s.ptr == s.end { + // We're done. + Poll::Ready(()) + } else { + Poll::Pending + } + }) }) .await; @@ -194,9 +173,11 @@ impl<'d, T: Instance> Rng<'d, T> { impl<'d, T: Instance> Drop for Rng<'d, T> { fn drop(&mut self) { self.stop(); - let s = T::state(); - s.ptr.store(ptr::null_mut(), Ordering::Relaxed); - s.end.store(ptr::null_mut(), Ordering::Relaxed); + critical_section::with(|cs| { + let mut state = T::state().borrow_mut(cs); + state.ptr = ptr::null_mut(); + state.end = ptr::null_mut(); + }); } } @@ -227,21 +208,47 @@ impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> { impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} pub(crate) mod sealed { + use core::cell::{Ref, RefMut, RefCell}; + + use critical_section::Mutex; + use critical_section::CriticalSection; + use embassy_sync::waitqueue::WakerRegistration; + use super::*; /// Peripheral static state pub struct State { - pub ptr: AtomicPtr, - pub end: AtomicPtr, - pub waker: AtomicWaker, + inner: Mutex>, + } + + pub struct InnerState { + pub ptr: *mut u8, + pub end: *mut u8, + pub waker: WakerRegistration, } impl State { pub const fn new() -> Self { Self { - ptr: AtomicPtr::new(ptr::null_mut()), - end: AtomicPtr::new(ptr::null_mut()), - waker: AtomicWaker::new(), + inner: Mutex::new(RefCell::new(InnerState::new())), + } + } + + pub fn borrow<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, InnerState> { + self.inner.borrow(cs).borrow() + } + + pub fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> { + self.inner.borrow(cs).borrow_mut() + } + } + + impl InnerState { + pub const fn new() -> Self { + Self { + ptr: ptr::null_mut(), + end: ptr::null_mut(), + waker: WakerRegistration::new(), } } } From 00d66cce1db71511b1a872a837c2d5dd0c22a598 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 24 Jan 2024 19:27:55 +0100 Subject: [PATCH 297/760] modify time driver to not require portable-atomic --- embassy-nrf/src/time_driver.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 0f31c5c9c..b41169c01 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -1,11 +1,11 @@ use core::cell::Cell; use core::{mem, ptr}; +use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; use embassy_time_driver::{AlarmHandle, Driver}; -use portable_atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; @@ -171,7 +171,8 @@ impl RtcDriver { fn next_period(&self) { critical_section::with(|cs| { let r = rtc(); - let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; + let period = self.period.load(Ordering::Relaxed) + 1; + self.period.store(period, Ordering::Relaxed); let t = (period as u64) << 23; for n in 0..ALARM_COUNT { @@ -219,18 +220,15 @@ impl Driver for RtcDriver { } unsafe fn allocate_alarm(&self) -> Option { - let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { - if x < ALARM_COUNT as u8 { - Some(x + 1) + critical_section::with(|_| { + let id = self.alarm_count.load(Ordering::Relaxed); + if id < ALARM_COUNT as u8 { + self.alarm_count.store(id + 1, Ordering::Relaxed); + Some(AlarmHandle::new(id)) } else { None } - }); - - match id { - Ok(id) => Some(AlarmHandle::new(id)), - Err(_) => None, - } + }) } fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { From 3ac52b2c4857048d56d943ed24c6d72847e60f0a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 24 Jan 2024 19:28:05 +0100 Subject: [PATCH 298/760] remove portable-atomic dependency --- embassy-nrf/Cargo.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 529a56c46..a682e1227 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -74,7 +74,7 @@ qspi-multiwrite-flash = [] #! ### Chip selection features ## nRF51 -nrf51 = ["nrf51-pac", "_nrf51", "portable-atomic/unsafe-assume-single-core"] +nrf51 = ["nrf51-pac", "_nrf51"] ## nRF52805 nrf52805 = ["nrf52805-pac", "_nrf52"] ## nRF52810 @@ -137,8 +137,6 @@ embedded-hal-async = { version = "1.0" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } -portable-atomic = { version = "1", default-features = false, features = ["require-cas"] } - defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" From 7d961a7f447a56a458a556b747710ec3375950d7 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 24 Jan 2024 19:28:28 +0100 Subject: [PATCH 299/760] cargo fmt --- embassy-nrf/src/rng.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 6145dd14f..a65ad5518 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -44,7 +44,6 @@ impl interrupt::typelevel::Handler for InterruptHandl if state.ptr == state.end { state.waker.wake(); } - } }); } @@ -113,7 +112,6 @@ impl<'d, T: Instance> Rng<'d, T> { return; // Nothing to fill } - let range = dest.as_mut_ptr_range(); // Even if we've preempted the interrupt, it can't preempt us again, // so we don't need to worry about the order we write these in. @@ -208,10 +206,10 @@ impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> { impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} pub(crate) mod sealed { - use core::cell::{Ref, RefMut, RefCell}; + use core::cell::{Ref, RefCell, RefMut}; - use critical_section::Mutex; use critical_section::CriticalSection; + use critical_section::Mutex; use embassy_sync::waitqueue::WakerRegistration; use super::*; From 85d7779668ce14abbde4cd8fb1ea9395df529206 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 24 Jan 2024 19:30:46 +0100 Subject: [PATCH 300/760] rename nrf52 HIL test --- ci.sh | 2 +- tests/{nrf => nrf52840}/.cargo/config.toml | 0 tests/{nrf => nrf52840}/Cargo.toml | 0 tests/{nrf => nrf52840}/build.rs | 0 tests/{nrf => nrf52840}/memory.x | 0 tests/{nrf => nrf52840}/src/bin/buffered_uart.rs | 0 tests/{nrf => nrf52840}/src/bin/buffered_uart_full.rs | 0 tests/{nrf => nrf52840}/src/bin/buffered_uart_spam.rs | 0 tests/{nrf => nrf52840}/src/bin/ethernet_enc28j60_perf.rs | 0 tests/{nrf => nrf52840}/src/bin/timer.rs | 0 tests/{nrf => nrf52840}/src/bin/wifi_esp_hosted_perf.rs | 0 11 files changed, 1 insertion(+), 1 deletion(-) rename tests/{nrf => nrf52840}/.cargo/config.toml (100%) rename tests/{nrf => nrf52840}/Cargo.toml (100%) rename tests/{nrf => nrf52840}/build.rs (100%) rename tests/{nrf => nrf52840}/memory.x (100%) rename tests/{nrf => nrf52840}/src/bin/buffered_uart.rs (100%) rename tests/{nrf => nrf52840}/src/bin/buffered_uart_full.rs (100%) rename tests/{nrf => nrf52840}/src/bin/buffered_uart_spam.rs (100%) rename tests/{nrf => nrf52840}/src/bin/ethernet_enc28j60_perf.rs (100%) rename tests/{nrf => nrf52840}/src/bin/timer.rs (100%) rename tests/{nrf => nrf52840}/src/bin/wifi_esp_hosted_perf.rs (100%) diff --git a/ci.sh b/ci.sh index 3322c60d1..cf12f95fd 100755 --- a/ci.sh +++ b/ci.sh @@ -211,7 +211,7 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \ --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ - --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ + --- build --release --manifest-path tests/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ $BUILD_EXTRA diff --git a/tests/nrf/.cargo/config.toml b/tests/nrf52840/.cargo/config.toml similarity index 100% rename from tests/nrf/.cargo/config.toml rename to tests/nrf52840/.cargo/config.toml diff --git a/tests/nrf/Cargo.toml b/tests/nrf52840/Cargo.toml similarity index 100% rename from tests/nrf/Cargo.toml rename to tests/nrf52840/Cargo.toml diff --git a/tests/nrf/build.rs b/tests/nrf52840/build.rs similarity index 100% rename from tests/nrf/build.rs rename to tests/nrf52840/build.rs diff --git a/tests/nrf/memory.x b/tests/nrf52840/memory.x similarity index 100% rename from tests/nrf/memory.x rename to tests/nrf52840/memory.x diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf52840/src/bin/buffered_uart.rs similarity index 100% rename from tests/nrf/src/bin/buffered_uart.rs rename to tests/nrf52840/src/bin/buffered_uart.rs diff --git a/tests/nrf/src/bin/buffered_uart_full.rs b/tests/nrf52840/src/bin/buffered_uart_full.rs similarity index 100% rename from tests/nrf/src/bin/buffered_uart_full.rs rename to tests/nrf52840/src/bin/buffered_uart_full.rs diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf52840/src/bin/buffered_uart_spam.rs similarity index 100% rename from tests/nrf/src/bin/buffered_uart_spam.rs rename to tests/nrf52840/src/bin/buffered_uart_spam.rs diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf52840/src/bin/ethernet_enc28j60_perf.rs similarity index 100% rename from tests/nrf/src/bin/ethernet_enc28j60_perf.rs rename to tests/nrf52840/src/bin/ethernet_enc28j60_perf.rs diff --git a/tests/nrf/src/bin/timer.rs b/tests/nrf52840/src/bin/timer.rs similarity index 100% rename from tests/nrf/src/bin/timer.rs rename to tests/nrf52840/src/bin/timer.rs diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf52840/src/bin/wifi_esp_hosted_perf.rs similarity index 100% rename from tests/nrf/src/bin/wifi_esp_hosted_perf.rs rename to tests/nrf52840/src/bin/wifi_esp_hosted_perf.rs From db0f4a0b91cc89aef58a6345743fb51ffe1be3a4 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 24 Jan 2024 20:19:34 +0100 Subject: [PATCH 301/760] cleanup --- embassy-nrf/src/chips/nrf51.rs | 8 +++++--- embassy-nrf/src/ppi/mod.rs | 1 + embassy-nrf/src/ppi/ppi.rs | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index f5db4b847..e7147ac93 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -102,9 +102,11 @@ embassy_hal_internal::peripherals! { TEMP, } -// impl_timer!(TIMER0, TIMER0, TIMER0); -// impl_timer!(TIMER1, TIMER1, TIMER1); -// impl_timer!(TIMER2, TIMER2, TIMER2); +impl_timer!(TIMER0, TIMER0, TIMER0); +impl_timer!(TIMER1, TIMER1, TIMER1); +impl_timer!(TIMER2, TIMER2, TIMER2); + +impl_rng!(RNG, RNG, RNG); impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 5b4a64388..f5764b8b7 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -284,6 +284,7 @@ impl ConfigurableChannel for AnyConfigurableChannel { } } +#[cfg(not(feature = "nrf51"))] macro_rules! impl_ppi_channel { ($type:ident, $number:expr) => { impl crate::ppi::sealed::Channel for peripherals::$type {} diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index 4a12764ad..8ff52ece3 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -1,6 +1,6 @@ use embassy_hal_internal::into_ref; -use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task}; +use super::{Channel, ConfigurableChannel, Event, Ppi, Task}; use crate::{pac, Peripheral}; impl<'d> Task<'d> { @@ -19,7 +19,7 @@ pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock { } #[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task -impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> { +impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { /// Configure PPI channel to trigger `task`. pub fn new_zero_to_one(ch: impl Peripheral

+ 'd, task: Task) -> Self { into_ref!(ch); From 1989c229f99b1177133af51d514ba44a5b02fe6f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 08:38:01 +0100 Subject: [PATCH 302/760] fix: make inner state send as it's protected critical section --- embassy-nrf/src/rng.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index a65ad5518..667637bfa 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -225,6 +225,8 @@ pub(crate) mod sealed { pub waker: WakerRegistration, } + unsafe impl Send for InnerState {} + impl State { pub const fn new() -> Self { Self { From 3739cc069914861d891a21734b3da9418bd01e9f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 08:38:28 +0100 Subject: [PATCH 303/760] fix warnings --- embassy-nrf/src/chips/nrf51.rs | 1 - embassy-nrf/src/gpio.rs | 1 + embassy-nrf/src/lib.rs | 4 ++++ embassy-nrf/src/timer.rs | 4 ++-- embassy-nrf/src/util.rs | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index e7147ac93..016352fb8 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -2,7 +2,6 @@ pub use nrf51_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; -pub const FORCE_COPY_BUFFER_SIZE: usize = 256; pub const FLASH_SIZE: usize = 128 * 1024; diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index b1eb8ae87..b2f987109 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -487,6 +487,7 @@ impl<'a, P: Pin> PselBits for Option> { } } +#[allow(dead_code)] pub(crate) fn deconfigure_pin(psel_bits: u32) { if psel_bits & 0x8000_0000 != 0 { return; diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 923e48ec2..358a7cc27 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -336,6 +336,7 @@ mod consts { pub const APPROTECT_DISABLED: u32 = 0x0000_005a; } +#[cfg(not(feature = "nrf51"))] #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] enum WriteResult { @@ -347,10 +348,12 @@ enum WriteResult { Failed, } +#[cfg(not(feature = "nrf51"))] unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult { uicr_write_masked(address, value, 0xFFFF_FFFF) } +#[cfg(not(feature = "nrf51"))] unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult { let curr_val = address.read_volatile(); if curr_val & mask == value & mask { @@ -383,6 +386,7 @@ pub fn init(config: config::Config) -> Peripherals { // before doing anything important. let peripherals = Peripherals::take(); + #[allow(unused_mut)] let mut needs_reset = false; // Setup debug protection. diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 272fffc0a..3c35baee5 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -111,7 +111,7 @@ impl<'d, T: Instance> Timer<'d, T> { Self::new_inner(timer, true) } - fn new_inner(timer: impl Peripheral

+ 'd, is_counter: bool) -> Self { + fn new_inner(timer: impl Peripheral

+ 'd, _is_counter: bool) -> Self { into_ref!(timer); let regs = T::regs(); @@ -123,7 +123,7 @@ impl<'d, T: Instance> Timer<'d, T> { this.stop(); #[cfg(not(feature = "nrf51"))] - if is_counter { + if _is_counter { regs.mode.write(|w| w.mode().low_power_counter()); } else { regs.mode.write(|w| w.mode().timer()); diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs index cd0f59490..b408c517b 100644 --- a/embassy-nrf/src/util.rs +++ b/embassy-nrf/src/util.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use core::mem; const SRAM_LOWER: usize = 0x2000_0000; From 1263d28595d7f92e348c866764e6e6275b08967f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 08:39:25 +0100 Subject: [PATCH 304/760] nightly fmt --- embassy-nrf/src/rng.rs | 3 +-- embassy-nrf/src/time_driver.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 667637bfa..40b73231b 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -208,8 +208,7 @@ impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} pub(crate) mod sealed { use core::cell::{Ref, RefCell, RefMut}; - use critical_section::CriticalSection; - use critical_section::Mutex; + use critical_section::{CriticalSection, Mutex}; use embassy_sync::waitqueue::WakerRegistration; use super::*; diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index b41169c01..3407c9504 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -1,7 +1,7 @@ use core::cell::Cell; +use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use core::{mem, ptr}; -use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; From 9418f0f9e53ceddfcaefe90a7fd3ad308f440758 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 14:05:45 +0100 Subject: [PATCH 305/760] add HIL test to CI --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index cf12f95fd..1299dc2c9 100755 --- a/ci.sh +++ b/ci.sh @@ -212,6 +212,7 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \ --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ --- build --release --manifest-path tests/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ + --- build --release --manifest-path tests/nrf51822/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/nrf51-dk \ --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ $BUILD_EXTRA From 7e6bc64331ad2fad71791ac4e0eb76667212f475 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 14:23:57 +0100 Subject: [PATCH 306/760] fix: add missing hil test project --- tests/nrf51822/.cargo/config.toml | 9 +++++++++ tests/nrf51822/Cargo.toml | 22 ++++++++++++++++++++++ tests/nrf51822/build.rs | 17 +++++++++++++++++ tests/nrf51822/memory.x | 5 +++++ tests/nrf51822/src/bin/gpio.rs | 28 ++++++++++++++++++++++++++++ tests/nrf51822/src/bin/timer.rs | 25 +++++++++++++++++++++++++ 6 files changed, 106 insertions(+) create mode 100644 tests/nrf51822/.cargo/config.toml create mode 100644 tests/nrf51822/Cargo.toml create mode 100644 tests/nrf51822/build.rs create mode 100644 tests/nrf51822/memory.x create mode 100644 tests/nrf51822/src/bin/gpio.rs create mode 100644 tests/nrf51822/src/bin/timer.rs diff --git a/tests/nrf51822/.cargo/config.toml b/tests/nrf51822/.cargo/config.toml new file mode 100644 index 000000000..3d0c71092 --- /dev/null +++ b/tests/nrf51822/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +#runner = "teleprobe local run --chip nRF51822_xxAA --elf" +runner = "teleprobe client run" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace,embassy_hal_internal=debug" diff --git a/tests/nrf51822/Cargo.toml b/tests/nrf51822/Cargo.toml new file mode 100644 index 000000000..468fa03fa --- /dev/null +++ b/tests/nrf51822/Cargo.toml @@ -0,0 +1,22 @@ +[package] +edition = "2021" +name = "embassy-nrf51822-tests" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +teleprobe-meta = "1" + +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", "task-arena-size-8192", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac"] } +embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } +embedded-hal-async = { version = "1.0" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } +cortex-m-rt = "0.7.0" +panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/tests/nrf51822/build.rs b/tests/nrf51822/build.rs new file mode 100644 index 000000000..71c82a70f --- /dev/null +++ b/tests/nrf51822/build.rs @@ -0,0 +1,17 @@ +use std::error::Error; +use std::path::PathBuf; +use std::{env, fs}; + +fn main() -> Result<(), Box> { + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + fs::write(out.join("link_ram.x"), include_bytes!("../link_ram_cortex_m.x")).unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=link_ram.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + println!("cargo:rustc-link-arg-bins=-Tteleprobe.x"); + + Ok(()) +} diff --git a/tests/nrf51822/memory.x b/tests/nrf51822/memory.x new file mode 100644 index 000000000..c140005ce --- /dev/null +++ b/tests/nrf51822/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 32K +} diff --git a/tests/nrf51822/src/bin/gpio.rs b/tests/nrf51822/src/bin/gpio.rs new file mode 100644 index 000000000..6c6bc0839 --- /dev/null +++ b/tests/nrf51822/src/bin/gpio.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] +teleprobe_meta::target!(b"nrf51-dk"); + +use defmt::{assert, info}; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + let input = Input::new(p.P0_13, Pull::None); + let mut output = Output::new(p.P0_14, Level::Low, OutputDrive::Standard); + + output.set_low(); + Timer::after_millis(1).await; + assert!(input.is_low()); + + output.set_high(); + Timer::after_millis(1).await; + assert!(input.is_high()); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/nrf51822/src/bin/timer.rs b/tests/nrf51822/src/bin/timer.rs new file mode 100644 index 000000000..2a147e7ba --- /dev/null +++ b/tests/nrf51822/src/bin/timer.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] +teleprobe_meta::target!(b"nrf52840-dk"); + +use defmt::{assert, info}; +use embassy_executor::Spawner; +use embassy_time::{Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = embassy_nrf::init(Default::default()); + info!("Hello World!"); + + let start = Instant::now(); + Timer::after_millis(100).await; + let end = Instant::now(); + let ms = (end - start).as_millis(); + info!("slept for {} ms", ms); + assert!(ms >= 99); + assert!(ms < 110); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From d19c67023d45ac7482bc05f1cea994abd97d0a2d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 14:36:51 +0100 Subject: [PATCH 307/760] fix: teleprobe target --- tests/nrf51822/src/bin/timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nrf51822/src/bin/timer.rs b/tests/nrf51822/src/bin/timer.rs index 2a147e7ba..93f4c2b1c 100644 --- a/tests/nrf51822/src/bin/timer.rs +++ b/tests/nrf51822/src/bin/timer.rs @@ -1,6 +1,6 @@ #![no_std] #![no_main] -teleprobe_meta::target!(b"nrf52840-dk"); +teleprobe_meta::target!(b"nrf51-dk"); use defmt::{assert, info}; use embassy_executor::Spawner; From 309dda057d05cd0c197ffe2befa271e9cad314b7 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 14:39:09 +0100 Subject: [PATCH 308/760] add nrf51 builds to ci --- ci.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci.sh b/ci.sh index 1299dc2c9..d29a686af 100755 --- a/ci.sh +++ b/ci.sh @@ -67,6 +67,9 @@ cargo batch \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \ @@ -148,6 +151,7 @@ cargo batch \ --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \ + --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ From f117213b6ee80c224e781d7bf4e750df49c345a6 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 21:47:49 +0100 Subject: [PATCH 309/760] fix: use nrf51-dk chip variant --- ci.sh | 2 +- examples/nrf51/.cargo/config.toml | 4 ++-- tests/{nrf51822 => nrf51422}/.cargo/config.toml | 2 +- tests/{nrf51822 => nrf51422}/Cargo.toml | 2 +- tests/{nrf51822 => nrf51422}/build.rs | 0 tests/{nrf51822 => nrf51422}/memory.x | 0 tests/{nrf51822 => nrf51422}/src/bin/gpio.rs | 0 tests/{nrf51822 => nrf51422}/src/bin/timer.rs | 0 8 files changed, 5 insertions(+), 5 deletions(-) rename tests/{nrf51822 => nrf51422}/.cargo/config.toml (75%) rename tests/{nrf51822 => nrf51422}/Cargo.toml (96%) rename tests/{nrf51822 => nrf51422}/build.rs (100%) rename tests/{nrf51822 => nrf51422}/memory.x (100%) rename tests/{nrf51822 => nrf51422}/src/bin/gpio.rs (100%) rename tests/{nrf51822 => nrf51422}/src/bin/timer.rs (100%) diff --git a/ci.sh b/ci.sh index d29a686af..6a5e6e3f5 100755 --- a/ci.sh +++ b/ci.sh @@ -216,7 +216,7 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \ --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ --- build --release --manifest-path tests/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ - --- build --release --manifest-path tests/nrf51822/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/nrf51-dk \ + --- build --release --manifest-path tests/nrf51422/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/nrf51-dk \ --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ $BUILD_EXTRA diff --git a/examples/nrf51/.cargo/config.toml b/examples/nrf51/.cargo/config.toml index 29d35a9b4..1671f5db1 100644 --- a/examples/nrf51/.cargo/config.toml +++ b/examples/nrf51/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF51822_xxAA with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip nRF51822_xxAA" +# replace nRF51422_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF51422_xxAA" [build] target = "thumbv6m-none-eabi" diff --git a/tests/nrf51822/.cargo/config.toml b/tests/nrf51422/.cargo/config.toml similarity index 75% rename from tests/nrf51822/.cargo/config.toml rename to tests/nrf51422/.cargo/config.toml index 3d0c71092..634805633 100644 --- a/tests/nrf51822/.cargo/config.toml +++ b/tests/nrf51422/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -#runner = "teleprobe local run --chip nRF51822_xxAA --elf" +#runner = "teleprobe local run --chip nRF51422_xxAA --elf" runner = "teleprobe client run" [build] diff --git a/tests/nrf51822/Cargo.toml b/tests/nrf51422/Cargo.toml similarity index 96% rename from tests/nrf51822/Cargo.toml rename to tests/nrf51422/Cargo.toml index 468fa03fa..d95f122b0 100644 --- a/tests/nrf51822/Cargo.toml +++ b/tests/nrf51422/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "embassy-nrf51822-tests" +name = "embassy-nrf51-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/nrf51822/build.rs b/tests/nrf51422/build.rs similarity index 100% rename from tests/nrf51822/build.rs rename to tests/nrf51422/build.rs diff --git a/tests/nrf51822/memory.x b/tests/nrf51422/memory.x similarity index 100% rename from tests/nrf51822/memory.x rename to tests/nrf51422/memory.x diff --git a/tests/nrf51822/src/bin/gpio.rs b/tests/nrf51422/src/bin/gpio.rs similarity index 100% rename from tests/nrf51822/src/bin/gpio.rs rename to tests/nrf51422/src/bin/gpio.rs diff --git a/tests/nrf51822/src/bin/timer.rs b/tests/nrf51422/src/bin/timer.rs similarity index 100% rename from tests/nrf51822/src/bin/timer.rs rename to tests/nrf51422/src/bin/timer.rs From b16eca3f21f947dcd4b3fe279bd4f577679428bc Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 21:50:03 +0100 Subject: [PATCH 310/760] adjust memory settings for lower end variant --- examples/nrf51/memory.x | 4 ++-- tests/nrf51422/memory.x | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/nrf51/memory.x b/examples/nrf51/memory.x index ad5f80292..98b3c792f 100644 --- a/examples/nrf51/memory.x +++ b/examples/nrf51/memory.x @@ -1,5 +1,5 @@ MEMORY { - FLASH : ORIGIN = 0x00000000, LENGTH = 256K - RAM : ORIGIN = 0x20000000, LENGTH = 32K + FLASH : ORIGIN = 0x00000000, LENGTH = 128K + RAM : ORIGIN = 0x20000000, LENGTH = 16K } diff --git a/tests/nrf51422/memory.x b/tests/nrf51422/memory.x index c140005ce..a5881e66f 100644 --- a/tests/nrf51422/memory.x +++ b/tests/nrf51422/memory.x @@ -1,5 +1,5 @@ MEMORY { - FLASH : ORIGIN = 0x00000000, LENGTH = 256K - RAM : ORIGIN = 0x20000000, LENGTH = 32K + FLASH : ORIGIN = 0x00000000, LENGTH = 128K + RAM : ORIGIN = 0x20000000, LENGTH = 16K } From 43553381cda95b75d9de1460d5ea6add6e739134 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 25 Jan 2024 21:51:23 +0100 Subject: [PATCH 311/760] lower arena for nrf51 --- examples/nrf51/Cargo.toml | 2 +- tests/nrf51422/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 8507c415c..d1e919a33 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time", "rt"] } diff --git a/tests/nrf51422/Cargo.toml b/tests/nrf51422/Cargo.toml index d95f122b0..246b71117 100644 --- a/tests/nrf51422/Cargo.toml +++ b/tests/nrf51422/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1" 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", "task-arena-size-8192", "integrated-timers"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-4096", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } From 3c159205a78cb2cc72e3dfeec1eff80d7b95846d Mon Sep 17 00:00:00 2001 From: Shane Snover Date: Thu, 25 Jan 2024 22:30:42 -0700 Subject: [PATCH 312/760] Fix the backticks on the getting started page --- docs/modules/ROOT/pages/getting_started.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc index ab819ac2a..24bde1c1f 100644 --- a/docs/modules/ROOT/pages/getting_started.adoc +++ b/docs/modules/ROOT/pages/getting_started.adoc @@ -88,7 +88,7 @@ NOTE: How does the `cargo run` command know how to connect to our board and prog If you hare having issues when running `cargo run --release`, please check the following: -* You are specifying the correct `--chip on the command line``, OR +* You are specifying the correct `--chip` on the command line, OR * You have set `.cargo/config.toml`'s run line to the correct chip, AND * You have changed `examples/Cargo.toml`'s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature) From 2f347ece9149551bd9db1068179f74500641a33e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 26 Jan 2024 08:00:50 +0100 Subject: [PATCH 313/760] add simplest test --- tests/nrf51422/src/bin/test.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/nrf51422/src/bin/test.rs diff --git a/tests/nrf51422/src/bin/test.rs b/tests/nrf51422/src/bin/test.rs new file mode 100644 index 000000000..591bfbccc --- /dev/null +++ b/tests/nrf51422/src/bin/test.rs @@ -0,0 +1,15 @@ +#![no_std] +#![no_main] +teleprobe_meta::target!(b"nrf51-dk"); + +use defmt::{assert, info}; +use embassy_executor::Spawner; +use embassy_time::{Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = embassy_nrf::init(Default::default()); + info!("Test OK"); + cortex_m::asm::bkpt(); +} From 7c21178e378c888963150b879fc9d51684872f9e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 26 Jan 2024 08:14:11 +0100 Subject: [PATCH 314/760] fix warnings --- tests/nrf51422/src/bin/test.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/nrf51422/src/bin/test.rs b/tests/nrf51422/src/bin/test.rs index 591bfbccc..d3ffe26e3 100644 --- a/tests/nrf51422/src/bin/test.rs +++ b/tests/nrf51422/src/bin/test.rs @@ -2,9 +2,8 @@ #![no_main] teleprobe_meta::target!(b"nrf51-dk"); -use defmt::{assert, info}; +use defmt::info; use embassy_executor::Spawner; -use embassy_time::{Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] From 4d8043cade887ecdc8a42e0b9bd9d3b5bcee1dbb Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 26 Jan 2024 08:39:50 +0100 Subject: [PATCH 315/760] assert only at least time slept Cannot deterministically guarantee the upper bound --- tests/nrf51422/src/bin/timer.rs | 1 - tests/nrf52840/src/bin/timer.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/nrf51422/src/bin/timer.rs b/tests/nrf51422/src/bin/timer.rs index 93f4c2b1c..cf9ea41a8 100644 --- a/tests/nrf51422/src/bin/timer.rs +++ b/tests/nrf51422/src/bin/timer.rs @@ -18,7 +18,6 @@ async fn main(_spawner: Spawner) { let ms = (end - start).as_millis(); info!("slept for {} ms", ms); assert!(ms >= 99); - assert!(ms < 110); info!("Test OK"); cortex_m::asm::bkpt(); diff --git a/tests/nrf52840/src/bin/timer.rs b/tests/nrf52840/src/bin/timer.rs index 2a147e7ba..117947a94 100644 --- a/tests/nrf52840/src/bin/timer.rs +++ b/tests/nrf52840/src/bin/timer.rs @@ -18,7 +18,6 @@ async fn main(_spawner: Spawner) { let ms = (end - start).as_millis(); info!("slept for {} ms", ms); assert!(ms >= 99); - assert!(ms < 110); info!("Test OK"); cortex_m::asm::bkpt(); From ee90ee185c150085ee59c873e016b6f88f646b56 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 26 Jan 2024 08:58:23 +0100 Subject: [PATCH 316/760] fix: link nrf51 tests from flash for now --- tests/nrf51422/Cargo.toml | 4 ++-- tests/nrf51422/build.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/nrf51422/Cargo.toml b/tests/nrf51422/Cargo.toml index 246b71117..2cab20ac0 100644 --- a/tests/nrf51422/Cargo.toml +++ b/tests/nrf51422/Cargo.toml @@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1" 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", "task-arena-size-4096", "integrated-timers"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-128", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-hal-async = { version = "1.0" } diff --git a/tests/nrf51422/build.rs b/tests/nrf51422/build.rs index 71c82a70f..13ebbe4ee 100644 --- a/tests/nrf51422/build.rs +++ b/tests/nrf51422/build.rs @@ -4,12 +4,12 @@ use std::{env, fs}; fn main() -> Result<(), Box> { let out = PathBuf::from(env::var("OUT_DIR").unwrap()); - fs::write(out.join("link_ram.x"), include_bytes!("../link_ram_cortex_m.x")).unwrap(); + fs::write(out.join("memory.x"), include_bytes!("memory.x")).unwrap(); println!("cargo:rustc-link-search={}", out.display()); - println!("cargo:rerun-if-changed=link_ram.x"); + println!("cargo:rerun-if-changed=memory.x"); println!("cargo:rustc-link-arg-bins=--nmagic"); - println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); println!("cargo:rustc-link-arg-bins=-Tteleprobe.x"); From 0bd9a2f09434c5c67088bce79597c581a900adeb Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 26 Jan 2024 09:03:08 +0100 Subject: [PATCH 317/760] fix gpio test and remove dummy --- tests/nrf51422/src/bin/gpio.rs | 4 ++-- tests/nrf51422/src/bin/test.rs | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 tests/nrf51422/src/bin/test.rs diff --git a/tests/nrf51422/src/bin/gpio.rs b/tests/nrf51422/src/bin/gpio.rs index 6c6bc0839..0e5712273 100644 --- a/tests/nrf51422/src/bin/gpio.rs +++ b/tests/nrf51422/src/bin/gpio.rs @@ -16,11 +16,11 @@ async fn main(_spawner: Spawner) { let mut output = Output::new(p.P0_14, Level::Low, OutputDrive::Standard); output.set_low(); - Timer::after_millis(1).await; + Timer::after_millis(10).await; assert!(input.is_low()); output.set_high(); - Timer::after_millis(1).await; + Timer::after_millis(10).await; assert!(input.is_high()); info!("Test OK"); diff --git a/tests/nrf51422/src/bin/test.rs b/tests/nrf51422/src/bin/test.rs deleted file mode 100644 index d3ffe26e3..000000000 --- a/tests/nrf51422/src/bin/test.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![no_std] -#![no_main] -teleprobe_meta::target!(b"nrf51-dk"); - -use defmt::info; -use embassy_executor::Spawner; -use {defmt_rtt as _, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let _p = embassy_nrf::init(Default::default()); - info!("Test OK"); - cortex_m::asm::bkpt(); -} From bea3c5495a37481c85bcfce8d55f94049e4b89fd Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 26 Jan 2024 09:05:58 +0100 Subject: [PATCH 318/760] use pull-up to ensure we assert the correct change --- tests/nrf51422/src/bin/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nrf51422/src/bin/gpio.rs b/tests/nrf51422/src/bin/gpio.rs index 0e5712273..6d5a87d0a 100644 --- a/tests/nrf51422/src/bin/gpio.rs +++ b/tests/nrf51422/src/bin/gpio.rs @@ -12,7 +12,7 @@ use {defmt_rtt as _, panic_probe as _}; async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let input = Input::new(p.P0_13, Pull::None); + let input = Input::new(p.P0_13, Pull::Up); let mut output = Output::new(p.P0_14, Level::Low, OutputDrive::Standard); output.set_low(); From 531645e5d4650c87df5c0a3e2603a43ee9049f7b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 26 Jan 2024 09:11:17 +0100 Subject: [PATCH 319/760] docs: mention nrf51 --- embassy-nrf/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md index 50662749d..3df5f1fa5 100644 --- a/embassy-nrf/README.md +++ b/embassy-nrf/README.md @@ -14,11 +14,12 @@ For a complete list of available peripherals and features, see the [embassy-nrf The `embassy-nrf` HAL supports most variants of the nRF family: +* nRF51 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf51)) * nRF52 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840)) * nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340)) * nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160)) -Most peripherals are supported. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf). +Most peripherals are supported, but can vary between chip families. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf). For MCUs with TrustZone support, both Secure (S) and Non-Secure (NS) modes are supported. Running in Secure mode allows running Rust code without a SPM or TF-M binary, saving flash space and simplifying development. From d4542f443688d37a204096f68d84710e5c52d3f5 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 26 Jan 2024 12:36:28 +0200 Subject: [PATCH 320/760] docs(ci): add embassy-usb-dfu to the docs build --- .github/ci/doc.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index 70833f934..d0aff1e43 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -35,6 +35,7 @@ docserver-builder -i ./embassy-time-driver -o webroot/crates/embassy-time-driver docserver-builder -i ./embassy-time-queue-driver -o webroot/crates/embassy-time-queue-driver/git.zup docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup +docserver-builder -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup From adb024bdbe49ba77b3f30af016c0c2ee184f456b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Jan 2024 14:23:51 +0100 Subject: [PATCH 321/760] usb-dfu: add docs metadata. --- .github/ci/doc.sh | 2 +- embassy-usb-dfu/Cargo.toml | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index d0aff1e43..7112d8aaa 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -1,7 +1,7 @@ #!/bin/bash ## on push branch=main -set -euo pipefail +set -euxo pipefail export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 1ca5fea42..4d6ffeb5f 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -12,14 +12,24 @@ categories = [ "asynchronous" ] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-v$VERSION/embassy-usb-dfu/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-dfu/src/" +features = ["defmt", "cortex-m"] +target = "thumbv7em-none-eabi" +flavors = [ + { name = "dfu", features = [ "dfu" ] }, + { name = "application", features = [ "application" ] }, +] + +[package.metadata.docs.rs] +features = ["defmt", "cortex-m", "dfu"] [dependencies] bitflags = "2.4.1" cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } defmt = { version = "0.3.5", optional = true } embassy-boot = { version = "0.2.0", path = "../embassy-boot" } -# embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../embassy-sync" } embassy-time = { version = "0.3.0", path = "../embassy-time" } From 31fa0aebd8825fa2faf8ec988f0eda2e62ad4dad Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Jan 2024 14:26:19 +0100 Subject: [PATCH 322/760] executor: update remove portable-atomic comment. Fixes #2481 --- embassy-executor/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index d6fe8ee8b..409df0d75 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -41,7 +41,7 @@ critical-section = "1.1" document-features = "0.2.7" # needed for riscv and avr -# remove when https://github.com/rust-lang/rust/pull/114499 is merged +# remove when https://github.com/rust-lang/rust/pull/114499 lands on stable (on 1.76) portable-atomic = { version = "1.5", optional = true } # arch-cortex-m dependencies From dd2577fcf06cd2805097769b4fcad4e0feea5639 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Fri, 26 Jan 2024 20:55:53 +0100 Subject: [PATCH 323/760] use constant for the pwm clock Description: So it can be used outside of the crate to calculate max duty --- embassy-nrf/src/pwm.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 2f0397632..197ba640c 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -47,6 +47,7 @@ pub enum Error { } const MAX_SEQUENCE_LEN: usize = 32767; +pub const PWM_CLK_HZ: u32 = 16_000_000; impl<'d, T: Instance> SequencePwm<'d, T> { /// Create a new 1-channel PWM @@ -788,7 +789,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { /// Sets the PWM output frequency. #[inline(always)] pub fn set_period(&self, freq: u32) { - let clk = 16_000_000u32 >> (self.prescaler() as u8); + let clk = PWM_CLK_HZ >> (self.prescaler() as u8); let duty = clk / freq; self.set_max_duty(duty.min(32767) as u16); } @@ -796,7 +797,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { /// Returns the PWM output frequency. #[inline(always)] pub fn period(&self) -> u32 { - let clk = 16_000_000u32 >> (self.prescaler() as u8); + let clk = PWM_CLK_HZ >> (self.prescaler() as u8); let max_duty = self.max_duty() as u32; clk / max_duty } From c26e62e4f4a17e4c7165b7e2b9fc7c7b0f670960 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Fri, 26 Jan 2024 21:24:14 +0100 Subject: [PATCH 324/760] add documentation --- embassy-nrf/src/pwm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 197ba640c..03354abf8 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -47,6 +47,7 @@ pub enum Error { } const MAX_SEQUENCE_LEN: usize = 32767; +/// The used pwm clock frequency pub const PWM_CLK_HZ: u32 = 16_000_000; impl<'d, T: Instance> SequencePwm<'d, T> { From 2809d3bd45c9d469ae398d55f8d2c4bfda33c9dd Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Fri, 26 Jan 2024 22:09:49 +0100 Subject: [PATCH 325/760] add is_enabled() function --- embassy-nrf/src/pwm.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 03354abf8..856e12024 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -715,6 +715,13 @@ impl<'d, T: Instance> SimplePwm<'d, T> { pwm } + /// Returns the enable state of the pwm counter + #[inline(always)] + pub fn is_enabled(&self) -> bool { + let r = T::regs(); + r.enable.read().enable().bit_is_set() + } + /// Enables the PWM generator. #[inline(always)] pub fn enable(&self) { From 6efb5fd28425876ad72faa8bbc34facd7f3e3f81 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Fri, 26 Jan 2024 22:38:03 -0600 Subject: [PATCH 326/760] nrf/spi: add bit order config --- embassy-nrf/src/spim.rs | 13 +++++++++---- embassy-nrf/src/spis.rs | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index b0723d495..6b6f79188 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -10,6 +10,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::{into_ref, PeripheralRef}; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use pac::spim0::config::ORDER_A as BitOrder; pub use pac::spim0::frequency::FREQUENCY_A as Frequency; use crate::chip::FORCE_COPY_BUFFER_SIZE; @@ -41,6 +42,9 @@ pub struct Config { /// SPI mode pub mode: Mode, + /// Bit order + pub bit_order: BitOrder, + /// Overread character. /// /// When doing bidirectional transfers, if the TX buffer is shorter than the RX buffer, @@ -53,6 +57,7 @@ impl Default for Config { Self { frequency: Frequency::M1, mode: MODE_0, + bit_order: BitOrder::MSB_FIRST, orc: 0x00, } } @@ -580,22 +585,22 @@ impl<'d, T: Instance> SetConfig for Spim<'d, T> { r.config.write(|w| { match mode { MODE_0 => { - w.order().msb_first(); + w.order().variant(config.bit_order); w.cpol().active_high(); w.cpha().leading(); } MODE_1 => { - w.order().msb_first(); + w.order().variant(config.bit_order); w.cpol().active_high(); w.cpha().trailing(); } MODE_2 => { - w.order().msb_first(); + w.order().variant(config.bit_order); w.cpol().active_low(); w.cpha().leading(); } MODE_3 => { - w.order().msb_first(); + w.order().variant(config.bit_order); w.cpol().active_low(); w.cpha().trailing(); } diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 3aad25298..60f4c9865 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -9,6 +9,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::{into_ref, PeripheralRef}; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use pac::spis0::config::ORDER_A as BitOrder; use crate::chip::FORCE_COPY_BUFFER_SIZE; use crate::gpio::sealed::Pin as _; @@ -36,6 +37,9 @@ pub struct Config { /// SPI mode pub mode: Mode, + /// Bit order + pub bit_order: BitOrder, + /// Overread character. /// /// If the master keeps clocking the bus after all the bytes in the TX buffer have @@ -56,6 +60,7 @@ impl Default for Config { fn default() -> Self { Self { mode: MODE_0, + bit_order: BitOrder::MSB_FIRST, orc: 0x00, def: 0x00, auto_acquire: true, @@ -503,22 +508,22 @@ impl<'d, T: Instance> SetConfig for Spis<'d, T> { r.config.write(|w| { match mode { MODE_0 => { - w.order().msb_first(); + w.order().variant(config.bit_order); w.cpol().active_high(); w.cpha().leading(); } MODE_1 => { - w.order().msb_first(); + w.order().variant(config.bit_order); w.cpol().active_high(); w.cpha().trailing(); } MODE_2 => { - w.order().msb_first(); + w.order().variant(config.bit_order); w.cpol().active_low(); w.cpha().leading(); } MODE_3 => { - w.order().msb_first(); + w.order().variant(config.bit_order); w.cpol().active_low(); w.cpha().trailing(); } From b08a0955c3d6e66c0163508e86f9dc7e40e142d3 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sat, 27 Jan 2024 18:19:56 +0100 Subject: [PATCH 327/760] implement retriving duty. Description: When disabling the pwm and enabling again, it is required to restart the sequence. If the previous duty is not known, it is not possible to turn on the pwm again --- embassy-nrf/src/pwm.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 856e12024..90aeb09c0 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -736,6 +736,11 @@ impl<'d, T: Instance> SimplePwm<'d, T> { r.enable.write(|w| w.enable().disabled()); } + /// Returns the current duty of the channel + pub fn duty(&self, channel: usize) -> u16 { + self.duty[channel] + } + /// Sets duty cycle (15 bit) for a PWM channel. pub fn set_duty(&mut self, channel: usize, duty: u16) { let r = T::regs(); From 319b0fe3d78c60aa123a8cbdfac850d61f1478b0 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sat, 27 Jan 2024 18:20:53 +0100 Subject: [PATCH 328/760] Do not wait when the pwm is disabled Reason: because in this case no seqend event is raised and therefore an infinity loop occurs --- embassy-nrf/src/pwm.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 90aeb09c0..e0583b770 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -760,7 +760,9 @@ impl<'d, T: Instance> SimplePwm<'d, T> { // defensive wait until waveform is loaded after seqstart so set_duty // can't be called again while dma is still reading - while r.events_seqend[0].read().bits() == 0 {} + if self.is_enabled() { + while r.events_seqend[0].read().bits() == 0 {} + } } /// Sets the PWM clock prescaler. From 283debfda4b84a15e3f6de551256b9a65c729715 Mon Sep 17 00:00:00 2001 From: Valentin Trophime <60969974+ValouBambou@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:36:03 +0100 Subject: [PATCH 329/760] fix: typo in netcat command for std example The previous given command `nc -l 8000` doesn't let me see anything and lead to a "WARN connect error: ConnectionReset". By explicitly changing the `local-port` of `nc` with the `-p` I can now see the `Hello` message printed, and the warning log disappeared. --- examples/std/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/std/README.md b/examples/std/README.md index adc795928..e3a59d6ea 100644 --- a/examples/std/README.md +++ b/examples/std/README.md @@ -13,11 +13,11 @@ sudo ip -6 route add fe80::/64 dev tap0 sudo ip -6 route add fdaa::/64 dev tap0 ``` -Second, have something listening there. For example `nc -l 8000` +Second, have something listening there. For example `nc -lp 8000` Then run the example located in the `examples` folder: ```sh cd $EMBASSY_ROOT/examples/std/ cargo run --bin net -- --static-ip -``` \ No newline at end of file +``` From 0708ce1410404ebf66c94fadc71cb7b0128161d3 Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Mon, 29 Jan 2024 17:14:23 +0100 Subject: [PATCH 330/760] Use saturating_sub to make sure we don't overflow --- embassy-rp/src/uart/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 9f5ba4e8a..f372cb640 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -604,8 +604,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { return match (all_full, last_was_break) { (true, true) | (false, _) => { // We got less than the full amount + a break, or the full amount - // and the last byte was a break. Subtract the break off. - Ok((next_addr - 1) - sval) + // and the last byte was a break. Subtract the break off by adding one to sval. + Ok(next_addr.saturating_sub(1 + sval)) } (true, false) => { // We finished the whole DMA, and the last DMA'd byte was NOT a break From 5b2293e2b147736b9d324b1b561ae4227e057a04 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 30 Jan 2024 02:34:12 +0100 Subject: [PATCH 331/760] update stm32-metapac. --- embassy-stm32/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 865970dfb..70d4daf09 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -67,8 +67,8 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa 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-656ecf6714fa34fdfb3b3e2f2cd034bffed3f303" } +#stm32-metapac = { version = "15" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ab2bc2a739324793656ca1640e1caee2d88df72d" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -86,8 +86,8 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] 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-656ecf6714fa34fdfb3b3e2f2cd034bffed3f303", default-features = false, features = ["metadata"]} +#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ab2bc2a739324793656ca1640e1caee2d88df72d", default-features = false, features = ["metadata"]} [features] From f38807433882374fe4ccf3510070abb42639c1cb Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 30 Jan 2024 10:34:09 +0100 Subject: [PATCH 332/760] Add some comments from chat --- docs/modules/ROOT/pages/faq.adoc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index bf061d978..254c0aa97 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -181,3 +181,21 @@ Check out link:https://docs.embassy.dev/embassy-executor/git/cortex-m/index.html == Can I use manual ISRs alongside Embassy? Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task” flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project]. + +== How can I measure resource usage (CPU, RAM, etc.)? + +=== For CPU Usage: + +There are a couple techniques that have been documented, generally you want to measure how long you are spending in the idle or low priority loop. + +We need to document specifically how to do this in embassy, but link:https://blog.japaric.io/cpu-monitor/[this older post] describes the general process. + +If you end up doing this, please update this section with more specific examples! + +=== For Static Memory Usage + +Tools like `cargo size` and `cargo nm` can tell you the size of any globals or other static usage. Specifically you will want to see the size of the `.data` and `.bss` sections, which together make up the total global/static memory usage. + +=== For Max Stack Usage + +Check out link:https://github.com/Dirbaio/cargo-call-stack/[`cargo-call-stack`] for statically calculating worst-case stack usage. There are some caveats and inaccuracies possible with this, but this is a good way to get the general idea. From 5e7876c80047718457923bcd8f1e9859e6483b57 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 30 Jan 2024 12:41:46 +0100 Subject: [PATCH 333/760] Update docs/modules/ROOT/pages/faq.adoc --- docs/modules/ROOT/pages/faq.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index 254c0aa97..05ff7c598 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -198,4 +198,4 @@ Tools like `cargo size` and `cargo nm` can tell you the size of any globals or o === For Max Stack Usage -Check out link:https://github.com/Dirbaio/cargo-call-stack/[`cargo-call-stack`] for statically calculating worst-case stack usage. There are some caveats and inaccuracies possible with this, but this is a good way to get the general idea. +Check out link:https://github.com/Dirbaio/cargo-call-stack/[`cargo-call-stack`] for statically calculating worst-case stack usage. There are some caveats and inaccuracies possible with this, but this is a good way to get the general idea. See link:https://github.com/dirbaio/cargo-call-stack#known-limitations[the README] for more details. From a91a7a8557ae8998de7b08d753e7a55172fb43c8 Mon Sep 17 00:00:00 2001 From: Tomasz bla Fortuna Date: Sun, 14 Jan 2024 09:44:37 +0100 Subject: [PATCH 334/760] Add FDCAN dependency in correct flavor based on selected chip. Author: Torin Cooper-Bennun Change from review. --- embassy-stm32/Cargo.toml | 896 ++++++++++++++++++------------------ examples/stm32g4/Cargo.toml | 2 +- 2 files changed, 450 insertions(+), 448 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 70d4daf09..6c7591f57 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -80,6 +80,8 @@ chrono = { version = "^0.4", default-features = false, optional = true} bit_field = "0.10.2" document-features = "0.2.7" +fdcan = { version = "0.2.0", optional = true } + [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } @@ -693,373 +695,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ] stm32f779bi = [ "stm32-metapac/stm32f779bi" ] stm32f779ii = [ "stm32-metapac/stm32f779ii" ] stm32f779ni = [ "stm32-metapac/stm32f779ni" ] -stm32g030c6 = [ "stm32-metapac/stm32g030c6" ] -stm32g030c8 = [ "stm32-metapac/stm32g030c8" ] -stm32g030f6 = [ "stm32-metapac/stm32g030f6" ] -stm32g030j6 = [ "stm32-metapac/stm32g030j6" ] -stm32g030k6 = [ "stm32-metapac/stm32g030k6" ] -stm32g030k8 = [ "stm32-metapac/stm32g030k8" ] -stm32g031c4 = [ "stm32-metapac/stm32g031c4" ] -stm32g031c6 = [ "stm32-metapac/stm32g031c6" ] -stm32g031c8 = [ "stm32-metapac/stm32g031c8" ] -stm32g031f4 = [ "stm32-metapac/stm32g031f4" ] -stm32g031f6 = [ "stm32-metapac/stm32g031f6" ] -stm32g031f8 = [ "stm32-metapac/stm32g031f8" ] -stm32g031g4 = [ "stm32-metapac/stm32g031g4" ] -stm32g031g6 = [ "stm32-metapac/stm32g031g6" ] -stm32g031g8 = [ "stm32-metapac/stm32g031g8" ] -stm32g031j4 = [ "stm32-metapac/stm32g031j4" ] -stm32g031j6 = [ "stm32-metapac/stm32g031j6" ] -stm32g031k4 = [ "stm32-metapac/stm32g031k4" ] -stm32g031k6 = [ "stm32-metapac/stm32g031k6" ] -stm32g031k8 = [ "stm32-metapac/stm32g031k8" ] -stm32g031y8 = [ "stm32-metapac/stm32g031y8" ] -stm32g041c6 = [ "stm32-metapac/stm32g041c6" ] -stm32g041c8 = [ "stm32-metapac/stm32g041c8" ] -stm32g041f6 = [ "stm32-metapac/stm32g041f6" ] -stm32g041f8 = [ "stm32-metapac/stm32g041f8" ] -stm32g041g6 = [ "stm32-metapac/stm32g041g6" ] -stm32g041g8 = [ "stm32-metapac/stm32g041g8" ] -stm32g041j6 = [ "stm32-metapac/stm32g041j6" ] -stm32g041k6 = [ "stm32-metapac/stm32g041k6" ] -stm32g041k8 = [ "stm32-metapac/stm32g041k8" ] -stm32g041y8 = [ "stm32-metapac/stm32g041y8" ] -stm32g050c6 = [ "stm32-metapac/stm32g050c6" ] -stm32g050c8 = [ "stm32-metapac/stm32g050c8" ] -stm32g050f6 = [ "stm32-metapac/stm32g050f6" ] -stm32g050k6 = [ "stm32-metapac/stm32g050k6" ] -stm32g050k8 = [ "stm32-metapac/stm32g050k8" ] -stm32g051c6 = [ "stm32-metapac/stm32g051c6" ] -stm32g051c8 = [ "stm32-metapac/stm32g051c8" ] -stm32g051f6 = [ "stm32-metapac/stm32g051f6" ] -stm32g051f8 = [ "stm32-metapac/stm32g051f8" ] -stm32g051g6 = [ "stm32-metapac/stm32g051g6" ] -stm32g051g8 = [ "stm32-metapac/stm32g051g8" ] -stm32g051k6 = [ "stm32-metapac/stm32g051k6" ] -stm32g051k8 = [ "stm32-metapac/stm32g051k8" ] -stm32g061c6 = [ "stm32-metapac/stm32g061c6" ] -stm32g061c8 = [ "stm32-metapac/stm32g061c8" ] -stm32g061f6 = [ "stm32-metapac/stm32g061f6" ] -stm32g061f8 = [ "stm32-metapac/stm32g061f8" ] -stm32g061g6 = [ "stm32-metapac/stm32g061g6" ] -stm32g061g8 = [ "stm32-metapac/stm32g061g8" ] -stm32g061k6 = [ "stm32-metapac/stm32g061k6" ] -stm32g061k8 = [ "stm32-metapac/stm32g061k8" ] -stm32g070cb = [ "stm32-metapac/stm32g070cb" ] -stm32g070kb = [ "stm32-metapac/stm32g070kb" ] -stm32g070rb = [ "stm32-metapac/stm32g070rb" ] -stm32g071c6 = [ "stm32-metapac/stm32g071c6" ] -stm32g071c8 = [ "stm32-metapac/stm32g071c8" ] -stm32g071cb = [ "stm32-metapac/stm32g071cb" ] -stm32g071eb = [ "stm32-metapac/stm32g071eb" ] -stm32g071g6 = [ "stm32-metapac/stm32g071g6" ] -stm32g071g8 = [ "stm32-metapac/stm32g071g8" ] -stm32g071gb = [ "stm32-metapac/stm32g071gb" ] -stm32g071k6 = [ "stm32-metapac/stm32g071k6" ] -stm32g071k8 = [ "stm32-metapac/stm32g071k8" ] -stm32g071kb = [ "stm32-metapac/stm32g071kb" ] -stm32g071r6 = [ "stm32-metapac/stm32g071r6" ] -stm32g071r8 = [ "stm32-metapac/stm32g071r8" ] -stm32g071rb = [ "stm32-metapac/stm32g071rb" ] -stm32g081cb = [ "stm32-metapac/stm32g081cb" ] -stm32g081eb = [ "stm32-metapac/stm32g081eb" ] -stm32g081gb = [ "stm32-metapac/stm32g081gb" ] -stm32g081kb = [ "stm32-metapac/stm32g081kb" ] -stm32g081rb = [ "stm32-metapac/stm32g081rb" ] -stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce" ] -stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke" ] -stm32g0b0re = [ "stm32-metapac/stm32g0b0re" ] -stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve" ] -stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb" ] -stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc" ] -stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce" ] -stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb" ] -stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc" ] -stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke" ] -stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb" ] -stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc" ] -stm32g0b1me = [ "stm32-metapac/stm32g0b1me" ] -stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne" ] -stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb" ] -stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc" ] -stm32g0b1re = [ "stm32-metapac/stm32g0b1re" ] -stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb" ] -stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc" ] -stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve" ] -stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc" ] -stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce" ] -stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc" ] -stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke" ] -stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc" ] -stm32g0c1me = [ "stm32-metapac/stm32g0c1me" ] -stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne" ] -stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc" ] -stm32g0c1re = [ "stm32-metapac/stm32g0c1re" ] -stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc" ] -stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve" ] -stm32g431c6 = [ "stm32-metapac/stm32g431c6" ] -stm32g431c8 = [ "stm32-metapac/stm32g431c8" ] -stm32g431cb = [ "stm32-metapac/stm32g431cb" ] -stm32g431k6 = [ "stm32-metapac/stm32g431k6" ] -stm32g431k8 = [ "stm32-metapac/stm32g431k8" ] -stm32g431kb = [ "stm32-metapac/stm32g431kb" ] -stm32g431m6 = [ "stm32-metapac/stm32g431m6" ] -stm32g431m8 = [ "stm32-metapac/stm32g431m8" ] -stm32g431mb = [ "stm32-metapac/stm32g431mb" ] -stm32g431r6 = [ "stm32-metapac/stm32g431r6" ] -stm32g431r8 = [ "stm32-metapac/stm32g431r8" ] -stm32g431rb = [ "stm32-metapac/stm32g431rb" ] -stm32g431v6 = [ "stm32-metapac/stm32g431v6" ] -stm32g431v8 = [ "stm32-metapac/stm32g431v8" ] -stm32g431vb = [ "stm32-metapac/stm32g431vb" ] -stm32g441cb = [ "stm32-metapac/stm32g441cb" ] -stm32g441kb = [ "stm32-metapac/stm32g441kb" ] -stm32g441mb = [ "stm32-metapac/stm32g441mb" ] -stm32g441rb = [ "stm32-metapac/stm32g441rb" ] -stm32g441vb = [ "stm32-metapac/stm32g441vb" ] -stm32g471cc = [ "stm32-metapac/stm32g471cc" ] -stm32g471ce = [ "stm32-metapac/stm32g471ce" ] -stm32g471mc = [ "stm32-metapac/stm32g471mc" ] -stm32g471me = [ "stm32-metapac/stm32g471me" ] -stm32g471qc = [ "stm32-metapac/stm32g471qc" ] -stm32g471qe = [ "stm32-metapac/stm32g471qe" ] -stm32g471rc = [ "stm32-metapac/stm32g471rc" ] -stm32g471re = [ "stm32-metapac/stm32g471re" ] -stm32g471vc = [ "stm32-metapac/stm32g471vc" ] -stm32g471ve = [ "stm32-metapac/stm32g471ve" ] -stm32g473cb = [ "stm32-metapac/stm32g473cb" ] -stm32g473cc = [ "stm32-metapac/stm32g473cc" ] -stm32g473ce = [ "stm32-metapac/stm32g473ce" ] -stm32g473mb = [ "stm32-metapac/stm32g473mb" ] -stm32g473mc = [ "stm32-metapac/stm32g473mc" ] -stm32g473me = [ "stm32-metapac/stm32g473me" ] -stm32g473pb = [ "stm32-metapac/stm32g473pb" ] -stm32g473pc = [ "stm32-metapac/stm32g473pc" ] -stm32g473pe = [ "stm32-metapac/stm32g473pe" ] -stm32g473qb = [ "stm32-metapac/stm32g473qb" ] -stm32g473qc = [ "stm32-metapac/stm32g473qc" ] -stm32g473qe = [ "stm32-metapac/stm32g473qe" ] -stm32g473rb = [ "stm32-metapac/stm32g473rb" ] -stm32g473rc = [ "stm32-metapac/stm32g473rc" ] -stm32g473re = [ "stm32-metapac/stm32g473re" ] -stm32g473vb = [ "stm32-metapac/stm32g473vb" ] -stm32g473vc = [ "stm32-metapac/stm32g473vc" ] -stm32g473ve = [ "stm32-metapac/stm32g473ve" ] -stm32g474cb = [ "stm32-metapac/stm32g474cb" ] -stm32g474cc = [ "stm32-metapac/stm32g474cc" ] -stm32g474ce = [ "stm32-metapac/stm32g474ce" ] -stm32g474mb = [ "stm32-metapac/stm32g474mb" ] -stm32g474mc = [ "stm32-metapac/stm32g474mc" ] -stm32g474me = [ "stm32-metapac/stm32g474me" ] -stm32g474pb = [ "stm32-metapac/stm32g474pb" ] -stm32g474pc = [ "stm32-metapac/stm32g474pc" ] -stm32g474pe = [ "stm32-metapac/stm32g474pe" ] -stm32g474qb = [ "stm32-metapac/stm32g474qb" ] -stm32g474qc = [ "stm32-metapac/stm32g474qc" ] -stm32g474qe = [ "stm32-metapac/stm32g474qe" ] -stm32g474rb = [ "stm32-metapac/stm32g474rb" ] -stm32g474rc = [ "stm32-metapac/stm32g474rc" ] -stm32g474re = [ "stm32-metapac/stm32g474re" ] -stm32g474vb = [ "stm32-metapac/stm32g474vb" ] -stm32g474vc = [ "stm32-metapac/stm32g474vc" ] -stm32g474ve = [ "stm32-metapac/stm32g474ve" ] -stm32g483ce = [ "stm32-metapac/stm32g483ce" ] -stm32g483me = [ "stm32-metapac/stm32g483me" ] -stm32g483pe = [ "stm32-metapac/stm32g483pe" ] -stm32g483qe = [ "stm32-metapac/stm32g483qe" ] -stm32g483re = [ "stm32-metapac/stm32g483re" ] -stm32g483ve = [ "stm32-metapac/stm32g483ve" ] -stm32g484ce = [ "stm32-metapac/stm32g484ce" ] -stm32g484me = [ "stm32-metapac/stm32g484me" ] -stm32g484pe = [ "stm32-metapac/stm32g484pe" ] -stm32g484qe = [ "stm32-metapac/stm32g484qe" ] -stm32g484re = [ "stm32-metapac/stm32g484re" ] -stm32g484ve = [ "stm32-metapac/stm32g484ve" ] -stm32g491cc = [ "stm32-metapac/stm32g491cc" ] -stm32g491ce = [ "stm32-metapac/stm32g491ce" ] -stm32g491kc = [ "stm32-metapac/stm32g491kc" ] -stm32g491ke = [ "stm32-metapac/stm32g491ke" ] -stm32g491mc = [ "stm32-metapac/stm32g491mc" ] -stm32g491me = [ "stm32-metapac/stm32g491me" ] -stm32g491rc = [ "stm32-metapac/stm32g491rc" ] -stm32g491re = [ "stm32-metapac/stm32g491re" ] -stm32g491vc = [ "stm32-metapac/stm32g491vc" ] -stm32g491ve = [ "stm32-metapac/stm32g491ve" ] -stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce" ] -stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ] -stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] -stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] -stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] -stm32h503cb = [ "stm32-metapac/stm32h503cb" ] -stm32h503eb = [ "stm32-metapac/stm32h503eb" ] -stm32h503kb = [ "stm32-metapac/stm32h503kb" ] -stm32h503rb = [ "stm32-metapac/stm32h503rb" ] -stm32h562ag = [ "stm32-metapac/stm32h562ag" ] -stm32h562ai = [ "stm32-metapac/stm32h562ai" ] -stm32h562ig = [ "stm32-metapac/stm32h562ig" ] -stm32h562ii = [ "stm32-metapac/stm32h562ii" ] -stm32h562rg = [ "stm32-metapac/stm32h562rg" ] -stm32h562ri = [ "stm32-metapac/stm32h562ri" ] -stm32h562vg = [ "stm32-metapac/stm32h562vg" ] -stm32h562vi = [ "stm32-metapac/stm32h562vi" ] -stm32h562zg = [ "stm32-metapac/stm32h562zg" ] -stm32h562zi = [ "stm32-metapac/stm32h562zi" ] -stm32h563ag = [ "stm32-metapac/stm32h563ag" ] -stm32h563ai = [ "stm32-metapac/stm32h563ai" ] -stm32h563ig = [ "stm32-metapac/stm32h563ig" ] -stm32h563ii = [ "stm32-metapac/stm32h563ii" ] -stm32h563mi = [ "stm32-metapac/stm32h563mi" ] -stm32h563rg = [ "stm32-metapac/stm32h563rg" ] -stm32h563ri = [ "stm32-metapac/stm32h563ri" ] -stm32h563vg = [ "stm32-metapac/stm32h563vg" ] -stm32h563vi = [ "stm32-metapac/stm32h563vi" ] -stm32h563zg = [ "stm32-metapac/stm32h563zg" ] -stm32h563zi = [ "stm32-metapac/stm32h563zi" ] -stm32h573ai = [ "stm32-metapac/stm32h573ai" ] -stm32h573ii = [ "stm32-metapac/stm32h573ii" ] -stm32h573mi = [ "stm32-metapac/stm32h573mi" ] -stm32h573ri = [ "stm32-metapac/stm32h573ri" ] -stm32h573vi = [ "stm32-metapac/stm32h573vi" ] -stm32h573zi = [ "stm32-metapac/stm32h573zi" ] -stm32h723ve = [ "stm32-metapac/stm32h723ve" ] -stm32h723vg = [ "stm32-metapac/stm32h723vg" ] -stm32h723ze = [ "stm32-metapac/stm32h723ze" ] -stm32h723zg = [ "stm32-metapac/stm32h723zg" ] -stm32h725ae = [ "stm32-metapac/stm32h725ae" ] -stm32h725ag = [ "stm32-metapac/stm32h725ag" ] -stm32h725ie = [ "stm32-metapac/stm32h725ie" ] -stm32h725ig = [ "stm32-metapac/stm32h725ig" ] -stm32h725re = [ "stm32-metapac/stm32h725re" ] -stm32h725rg = [ "stm32-metapac/stm32h725rg" ] -stm32h725ve = [ "stm32-metapac/stm32h725ve" ] -stm32h725vg = [ "stm32-metapac/stm32h725vg" ] -stm32h725ze = [ "stm32-metapac/stm32h725ze" ] -stm32h725zg = [ "stm32-metapac/stm32h725zg" ] -stm32h730ab = [ "stm32-metapac/stm32h730ab" ] -stm32h730ib = [ "stm32-metapac/stm32h730ib" ] -stm32h730vb = [ "stm32-metapac/stm32h730vb" ] -stm32h730zb = [ "stm32-metapac/stm32h730zb" ] -stm32h733vg = [ "stm32-metapac/stm32h733vg" ] -stm32h733zg = [ "stm32-metapac/stm32h733zg" ] -stm32h735ag = [ "stm32-metapac/stm32h735ag" ] -stm32h735ig = [ "stm32-metapac/stm32h735ig" ] -stm32h735rg = [ "stm32-metapac/stm32h735rg" ] -stm32h735vg = [ "stm32-metapac/stm32h735vg" ] -stm32h735zg = [ "stm32-metapac/stm32h735zg" ] -stm32h742ag = [ "stm32-metapac/stm32h742ag" ] -stm32h742ai = [ "stm32-metapac/stm32h742ai" ] -stm32h742bg = [ "stm32-metapac/stm32h742bg" ] -stm32h742bi = [ "stm32-metapac/stm32h742bi" ] -stm32h742ig = [ "stm32-metapac/stm32h742ig" ] -stm32h742ii = [ "stm32-metapac/stm32h742ii" ] -stm32h742vg = [ "stm32-metapac/stm32h742vg" ] -stm32h742vi = [ "stm32-metapac/stm32h742vi" ] -stm32h742xg = [ "stm32-metapac/stm32h742xg" ] -stm32h742xi = [ "stm32-metapac/stm32h742xi" ] -stm32h742zg = [ "stm32-metapac/stm32h742zg" ] -stm32h742zi = [ "stm32-metapac/stm32h742zi" ] -stm32h743ag = [ "stm32-metapac/stm32h743ag" ] -stm32h743ai = [ "stm32-metapac/stm32h743ai" ] -stm32h743bg = [ "stm32-metapac/stm32h743bg" ] -stm32h743bi = [ "stm32-metapac/stm32h743bi" ] -stm32h743ig = [ "stm32-metapac/stm32h743ig" ] -stm32h743ii = [ "stm32-metapac/stm32h743ii" ] -stm32h743vg = [ "stm32-metapac/stm32h743vg" ] -stm32h743vi = [ "stm32-metapac/stm32h743vi" ] -stm32h743xg = [ "stm32-metapac/stm32h743xg" ] -stm32h743xi = [ "stm32-metapac/stm32h743xi" ] -stm32h743zg = [ "stm32-metapac/stm32h743zg" ] -stm32h743zi = [ "stm32-metapac/stm32h743zi" ] -stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ] -stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ] -stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ] -stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ] -stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ] -stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ] -stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ] -stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ] -stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ] -stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ] -stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ] -stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ] -stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ] -stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ] -stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ] -stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ] -stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ] -stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ] -stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ] -stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ] -stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ] -stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ] -stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ] -stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ] -stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ] -stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ] -stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ] -stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ] -stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ] -stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ] -stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ] -stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ] -stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ] -stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ] -stm32h750ib = [ "stm32-metapac/stm32h750ib" ] -stm32h750vb = [ "stm32-metapac/stm32h750vb" ] -stm32h750xb = [ "stm32-metapac/stm32h750xb" ] -stm32h750zb = [ "stm32-metapac/stm32h750zb" ] -stm32h753ai = [ "stm32-metapac/stm32h753ai" ] -stm32h753bi = [ "stm32-metapac/stm32h753bi" ] -stm32h753ii = [ "stm32-metapac/stm32h753ii" ] -stm32h753vi = [ "stm32-metapac/stm32h753vi" ] -stm32h753xi = [ "stm32-metapac/stm32h753xi" ] -stm32h753zi = [ "stm32-metapac/stm32h753zi" ] -stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ] -stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ] -stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ] -stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ] -stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ] -stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ] -stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ] -stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ] -stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ] -stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ] -stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ] -stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ] -stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ] -stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ] -stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ] -stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ] -stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ] -stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ] -stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] -stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] -stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] -stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii" ] -stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg" ] -stm32h7a3li = [ "stm32-metapac/stm32h7a3li" ] -stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng" ] -stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni" ] -stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi" ] -stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg" ] -stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri" ] -stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg" ] -stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi" ] -stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg" ] -stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi" ] -stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab" ] -stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib" ] -stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb" ] -stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb" ] -stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb" ] -stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai" ] -stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii" ] -stm32h7b3li = [ "stm32-metapac/stm32h7b3li" ] -stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni" ] -stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ] -stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ] -stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ] -stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ] +stm32g030c6 = [ "stm32-metapac/stm32g030c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g030c8 = [ "stm32-metapac/stm32g030c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g030f6 = [ "stm32-metapac/stm32g030f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g030j6 = [ "stm32-metapac/stm32g030j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g030k6 = [ "stm32-metapac/stm32g030k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g030k8 = [ "stm32-metapac/stm32g030k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031c4 = [ "stm32-metapac/stm32g031c4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031c6 = [ "stm32-metapac/stm32g031c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031c8 = [ "stm32-metapac/stm32g031c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031f4 = [ "stm32-metapac/stm32g031f4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031f6 = [ "stm32-metapac/stm32g031f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031f8 = [ "stm32-metapac/stm32g031f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031g4 = [ "stm32-metapac/stm32g031g4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031g6 = [ "stm32-metapac/stm32g031g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031g8 = [ "stm32-metapac/stm32g031g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031j4 = [ "stm32-metapac/stm32g031j4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031j6 = [ "stm32-metapac/stm32g031j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031k4 = [ "stm32-metapac/stm32g031k4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031k6 = [ "stm32-metapac/stm32g031k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031k8 = [ "stm32-metapac/stm32g031k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g031y8 = [ "stm32-metapac/stm32g031y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041c6 = [ "stm32-metapac/stm32g041c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041c8 = [ "stm32-metapac/stm32g041c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041f6 = [ "stm32-metapac/stm32g041f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041f8 = [ "stm32-metapac/stm32g041f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041g6 = [ "stm32-metapac/stm32g041g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041g8 = [ "stm32-metapac/stm32g041g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041j6 = [ "stm32-metapac/stm32g041j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041k6 = [ "stm32-metapac/stm32g041k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041k8 = [ "stm32-metapac/stm32g041k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g041y8 = [ "stm32-metapac/stm32g041y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g050c6 = [ "stm32-metapac/stm32g050c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g050c8 = [ "stm32-metapac/stm32g050c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g050f6 = [ "stm32-metapac/stm32g050f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g050k6 = [ "stm32-metapac/stm32g050k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g050k8 = [ "stm32-metapac/stm32g050k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g051c6 = [ "stm32-metapac/stm32g051c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g051c8 = [ "stm32-metapac/stm32g051c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g051f6 = [ "stm32-metapac/stm32g051f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g051f8 = [ "stm32-metapac/stm32g051f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g051g6 = [ "stm32-metapac/stm32g051g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g051g8 = [ "stm32-metapac/stm32g051g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g051k6 = [ "stm32-metapac/stm32g051k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g051k8 = [ "stm32-metapac/stm32g051k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g061c6 = [ "stm32-metapac/stm32g061c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g061c8 = [ "stm32-metapac/stm32g061c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g061f6 = [ "stm32-metapac/stm32g061f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g061f8 = [ "stm32-metapac/stm32g061f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g061g6 = [ "stm32-metapac/stm32g061g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g061g8 = [ "stm32-metapac/stm32g061g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g061k6 = [ "stm32-metapac/stm32g061k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g061k8 = [ "stm32-metapac/stm32g061k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g070cb = [ "stm32-metapac/stm32g070cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g070kb = [ "stm32-metapac/stm32g070kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g070rb = [ "stm32-metapac/stm32g070rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071c6 = [ "stm32-metapac/stm32g071c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071c8 = [ "stm32-metapac/stm32g071c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071cb = [ "stm32-metapac/stm32g071cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071eb = [ "stm32-metapac/stm32g071eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071g6 = [ "stm32-metapac/stm32g071g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071g8 = [ "stm32-metapac/stm32g071g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071gb = [ "stm32-metapac/stm32g071gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071k6 = [ "stm32-metapac/stm32g071k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071k8 = [ "stm32-metapac/stm32g071k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071kb = [ "stm32-metapac/stm32g071kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071r6 = [ "stm32-metapac/stm32g071r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071r8 = [ "stm32-metapac/stm32g071r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g071rb = [ "stm32-metapac/stm32g071rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g081cb = [ "stm32-metapac/stm32g081cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g081eb = [ "stm32-metapac/stm32g081eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g081gb = [ "stm32-metapac/stm32g081gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g081kb = [ "stm32-metapac/stm32g081kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g081rb = [ "stm32-metapac/stm32g081rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b0re = [ "stm32-metapac/stm32g0b0re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1me = [ "stm32-metapac/stm32g0b1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1re = [ "stm32-metapac/stm32g0b1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1me = [ "stm32-metapac/stm32g0c1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1re = [ "stm32-metapac/stm32g0c1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431c6 = [ "stm32-metapac/stm32g431c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431c8 = [ "stm32-metapac/stm32g431c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431cb = [ "stm32-metapac/stm32g431cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431k6 = [ "stm32-metapac/stm32g431k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431k8 = [ "stm32-metapac/stm32g431k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431kb = [ "stm32-metapac/stm32g431kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431m6 = [ "stm32-metapac/stm32g431m6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431m8 = [ "stm32-metapac/stm32g431m8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431mb = [ "stm32-metapac/stm32g431mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431r6 = [ "stm32-metapac/stm32g431r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431r8 = [ "stm32-metapac/stm32g431r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431rb = [ "stm32-metapac/stm32g431rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431v6 = [ "stm32-metapac/stm32g431v6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431v8 = [ "stm32-metapac/stm32g431v8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g431vb = [ "stm32-metapac/stm32g431vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g441cb = [ "stm32-metapac/stm32g441cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g441kb = [ "stm32-metapac/stm32g441kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g441mb = [ "stm32-metapac/stm32g441mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g441rb = [ "stm32-metapac/stm32g441rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g441vb = [ "stm32-metapac/stm32g441vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471cc = [ "stm32-metapac/stm32g471cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471ce = [ "stm32-metapac/stm32g471ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471mc = [ "stm32-metapac/stm32g471mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471me = [ "stm32-metapac/stm32g471me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471qc = [ "stm32-metapac/stm32g471qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471qe = [ "stm32-metapac/stm32g471qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471rc = [ "stm32-metapac/stm32g471rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471re = [ "stm32-metapac/stm32g471re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471vc = [ "stm32-metapac/stm32g471vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g471ve = [ "stm32-metapac/stm32g471ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473cb = [ "stm32-metapac/stm32g473cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473cc = [ "stm32-metapac/stm32g473cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473ce = [ "stm32-metapac/stm32g473ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473mb = [ "stm32-metapac/stm32g473mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473mc = [ "stm32-metapac/stm32g473mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473me = [ "stm32-metapac/stm32g473me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473pb = [ "stm32-metapac/stm32g473pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473pc = [ "stm32-metapac/stm32g473pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473pe = [ "stm32-metapac/stm32g473pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473qb = [ "stm32-metapac/stm32g473qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473qc = [ "stm32-metapac/stm32g473qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473qe = [ "stm32-metapac/stm32g473qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473rb = [ "stm32-metapac/stm32g473rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473rc = [ "stm32-metapac/stm32g473rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473re = [ "stm32-metapac/stm32g473re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473vb = [ "stm32-metapac/stm32g473vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473vc = [ "stm32-metapac/stm32g473vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g473ve = [ "stm32-metapac/stm32g473ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474cb = [ "stm32-metapac/stm32g474cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474cc = [ "stm32-metapac/stm32g474cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474ce = [ "stm32-metapac/stm32g474ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474mb = [ "stm32-metapac/stm32g474mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474mc = [ "stm32-metapac/stm32g474mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474me = [ "stm32-metapac/stm32g474me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474pb = [ "stm32-metapac/stm32g474pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474pc = [ "stm32-metapac/stm32g474pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474pe = [ "stm32-metapac/stm32g474pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474qb = [ "stm32-metapac/stm32g474qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474qc = [ "stm32-metapac/stm32g474qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474qe = [ "stm32-metapac/stm32g474qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474rb = [ "stm32-metapac/stm32g474rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474rc = [ "stm32-metapac/stm32g474rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474re = [ "stm32-metapac/stm32g474re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474vb = [ "stm32-metapac/stm32g474vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474vc = [ "stm32-metapac/stm32g474vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g474ve = [ "stm32-metapac/stm32g474ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g483ce = [ "stm32-metapac/stm32g483ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g483me = [ "stm32-metapac/stm32g483me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g483pe = [ "stm32-metapac/stm32g483pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g483qe = [ "stm32-metapac/stm32g483qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g483re = [ "stm32-metapac/stm32g483re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g483ve = [ "stm32-metapac/stm32g483ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g484ce = [ "stm32-metapac/stm32g484ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g484me = [ "stm32-metapac/stm32g484me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g484pe = [ "stm32-metapac/stm32g484pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g484qe = [ "stm32-metapac/stm32g484qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g484re = [ "stm32-metapac/stm32g484re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g484ve = [ "stm32-metapac/stm32g484ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491cc = [ "stm32-metapac/stm32g491cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491ce = [ "stm32-metapac/stm32g491ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491kc = [ "stm32-metapac/stm32g491kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491ke = [ "stm32-metapac/stm32g491ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491mc = [ "stm32-metapac/stm32g491mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491me = [ "stm32-metapac/stm32g491me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491rc = [ "stm32-metapac/stm32g491rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491re = [ "stm32-metapac/stm32g491re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491vc = [ "stm32-metapac/stm32g491vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g491ve = [ "stm32-metapac/stm32g491ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g4a1me = [ "stm32-metapac/stm32g4a1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g4a1re = [ "stm32-metapac/stm32g4a1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h503cb = [ "stm32-metapac/stm32h503cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h503eb = [ "stm32-metapac/stm32h503eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h503kb = [ "stm32-metapac/stm32h503kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h503rb = [ "stm32-metapac/stm32h503rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562ag = [ "stm32-metapac/stm32h562ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562ai = [ "stm32-metapac/stm32h562ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562ig = [ "stm32-metapac/stm32h562ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562ii = [ "stm32-metapac/stm32h562ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562rg = [ "stm32-metapac/stm32h562rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562ri = [ "stm32-metapac/stm32h562ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562vg = [ "stm32-metapac/stm32h562vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562vi = [ "stm32-metapac/stm32h562vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562zg = [ "stm32-metapac/stm32h562zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h562zi = [ "stm32-metapac/stm32h562zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563ag = [ "stm32-metapac/stm32h563ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563ai = [ "stm32-metapac/stm32h563ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563ig = [ "stm32-metapac/stm32h563ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563ii = [ "stm32-metapac/stm32h563ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563mi = [ "stm32-metapac/stm32h563mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563rg = [ "stm32-metapac/stm32h563rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563ri = [ "stm32-metapac/stm32h563ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563vg = [ "stm32-metapac/stm32h563vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563vi = [ "stm32-metapac/stm32h563vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563zg = [ "stm32-metapac/stm32h563zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h563zi = [ "stm32-metapac/stm32h563zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h573ai = [ "stm32-metapac/stm32h573ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h573ii = [ "stm32-metapac/stm32h573ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h573mi = [ "stm32-metapac/stm32h573mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h573ri = [ "stm32-metapac/stm32h573ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h573vi = [ "stm32-metapac/stm32h573vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h573zi = [ "stm32-metapac/stm32h573zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32h723ve = [ "stm32-metapac/stm32h723ve", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h723vg = [ "stm32-metapac/stm32h723vg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h723ze = [ "stm32-metapac/stm32h723ze", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h723zg = [ "stm32-metapac/stm32h723zg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725ae = [ "stm32-metapac/stm32h725ae", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725ag = [ "stm32-metapac/stm32h725ag", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725ie = [ "stm32-metapac/stm32h725ie", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725ig = [ "stm32-metapac/stm32h725ig", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725re = [ "stm32-metapac/stm32h725re", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725rg = [ "stm32-metapac/stm32h725rg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725ve = [ "stm32-metapac/stm32h725ve", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725vg = [ "stm32-metapac/stm32h725vg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725ze = [ "stm32-metapac/stm32h725ze", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h725zg = [ "stm32-metapac/stm32h725zg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h730ab = [ "stm32-metapac/stm32h730ab", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h730ib = [ "stm32-metapac/stm32h730ib", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h730vb = [ "stm32-metapac/stm32h730vb", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h730zb = [ "stm32-metapac/stm32h730zb", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h733vg = [ "stm32-metapac/stm32h733vg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h733zg = [ "stm32-metapac/stm32h733zg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h735ag = [ "stm32-metapac/stm32h735ag", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h735ig = [ "stm32-metapac/stm32h735ig", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h735rg = [ "stm32-metapac/stm32h735rg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h735vg = [ "stm32-metapac/stm32h735vg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h735zg = [ "stm32-metapac/stm32h735zg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742ag = [ "stm32-metapac/stm32h742ag", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742ai = [ "stm32-metapac/stm32h742ai", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742bg = [ "stm32-metapac/stm32h742bg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742bi = [ "stm32-metapac/stm32h742bi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742ig = [ "stm32-metapac/stm32h742ig", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742ii = [ "stm32-metapac/stm32h742ii", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742vg = [ "stm32-metapac/stm32h742vg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742vi = [ "stm32-metapac/stm32h742vi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742xg = [ "stm32-metapac/stm32h742xg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742xi = [ "stm32-metapac/stm32h742xi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742zg = [ "stm32-metapac/stm32h742zg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h742zi = [ "stm32-metapac/stm32h742zi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743ag = [ "stm32-metapac/stm32h743ag", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743ai = [ "stm32-metapac/stm32h743ai", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743bg = [ "stm32-metapac/stm32h743bg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743bi = [ "stm32-metapac/stm32h743bi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743ig = [ "stm32-metapac/stm32h743ig", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743ii = [ "stm32-metapac/stm32h743ii", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743vg = [ "stm32-metapac/stm32h743vg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743vi = [ "stm32-metapac/stm32h743vi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743xg = [ "stm32-metapac/stm32h743xg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743xi = [ "stm32-metapac/stm32h743xi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743zg = [ "stm32-metapac/stm32h743zg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h743zi = [ "stm32-metapac/stm32h743zi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h750ib = [ "stm32-metapac/stm32h750ib", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h750vb = [ "stm32-metapac/stm32h750vb", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h750xb = [ "stm32-metapac/stm32h750xb", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h750zb = [ "stm32-metapac/stm32h750zb", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h753ai = [ "stm32-metapac/stm32h753ai", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h753bi = [ "stm32-metapac/stm32h753bi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h753ii = [ "stm32-metapac/stm32h753ii", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h753vi = [ "stm32-metapac/stm32h753vi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h753xi = [ "stm32-metapac/stm32h753xi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h753zi = [ "stm32-metapac/stm32h753zi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3li = [ "stm32-metapac/stm32h7a3li", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b3li = [ "stm32-metapac/stm32h7b3li", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi", "dep:fdcan", "fdcan/fdcan_h7" ] stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] @@ -1386,86 +1388,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ] stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] -stm32l552cc = [ "stm32-metapac/stm32l552cc" ] -stm32l552ce = [ "stm32-metapac/stm32l552ce" ] -stm32l552me = [ "stm32-metapac/stm32l552me" ] -stm32l552qc = [ "stm32-metapac/stm32l552qc" ] -stm32l552qe = [ "stm32-metapac/stm32l552qe" ] -stm32l552rc = [ "stm32-metapac/stm32l552rc" ] -stm32l552re = [ "stm32-metapac/stm32l552re" ] -stm32l552vc = [ "stm32-metapac/stm32l552vc" ] -stm32l552ve = [ "stm32-metapac/stm32l552ve" ] -stm32l552zc = [ "stm32-metapac/stm32l552zc" ] -stm32l552ze = [ "stm32-metapac/stm32l552ze" ] -stm32l562ce = [ "stm32-metapac/stm32l562ce" ] -stm32l562me = [ "stm32-metapac/stm32l562me" ] -stm32l562qe = [ "stm32-metapac/stm32l562qe" ] -stm32l562re = [ "stm32-metapac/stm32l562re" ] -stm32l562ve = [ "stm32-metapac/stm32l562ve" ] -stm32l562ze = [ "stm32-metapac/stm32l562ze" ] -stm32u535cb = [ "stm32-metapac/stm32u535cb" ] -stm32u535cc = [ "stm32-metapac/stm32u535cc" ] -stm32u535ce = [ "stm32-metapac/stm32u535ce" ] -stm32u535je = [ "stm32-metapac/stm32u535je" ] -stm32u535nc = [ "stm32-metapac/stm32u535nc" ] -stm32u535ne = [ "stm32-metapac/stm32u535ne" ] -stm32u535rb = [ "stm32-metapac/stm32u535rb" ] -stm32u535rc = [ "stm32-metapac/stm32u535rc" ] -stm32u535re = [ "stm32-metapac/stm32u535re" ] -stm32u535vc = [ "stm32-metapac/stm32u535vc" ] -stm32u535ve = [ "stm32-metapac/stm32u535ve" ] -stm32u545ce = [ "stm32-metapac/stm32u545ce" ] -stm32u545je = [ "stm32-metapac/stm32u545je" ] -stm32u545ne = [ "stm32-metapac/stm32u545ne" ] -stm32u545re = [ "stm32-metapac/stm32u545re" ] -stm32u545ve = [ "stm32-metapac/stm32u545ve" ] -stm32u575ag = [ "stm32-metapac/stm32u575ag" ] -stm32u575ai = [ "stm32-metapac/stm32u575ai" ] -stm32u575cg = [ "stm32-metapac/stm32u575cg" ] -stm32u575ci = [ "stm32-metapac/stm32u575ci" ] -stm32u575og = [ "stm32-metapac/stm32u575og" ] -stm32u575oi = [ "stm32-metapac/stm32u575oi" ] -stm32u575qg = [ "stm32-metapac/stm32u575qg" ] -stm32u575qi = [ "stm32-metapac/stm32u575qi" ] -stm32u575rg = [ "stm32-metapac/stm32u575rg" ] -stm32u575ri = [ "stm32-metapac/stm32u575ri" ] -stm32u575vg = [ "stm32-metapac/stm32u575vg" ] -stm32u575vi = [ "stm32-metapac/stm32u575vi" ] -stm32u575zg = [ "stm32-metapac/stm32u575zg" ] -stm32u575zi = [ "stm32-metapac/stm32u575zi" ] -stm32u585ai = [ "stm32-metapac/stm32u585ai" ] -stm32u585ci = [ "stm32-metapac/stm32u585ci" ] -stm32u585oi = [ "stm32-metapac/stm32u585oi" ] -stm32u585qi = [ "stm32-metapac/stm32u585qi" ] -stm32u585ri = [ "stm32-metapac/stm32u585ri" ] -stm32u585vi = [ "stm32-metapac/stm32u585vi" ] -stm32u585zi = [ "stm32-metapac/stm32u585zi" ] -stm32u595ai = [ "stm32-metapac/stm32u595ai" ] -stm32u595aj = [ "stm32-metapac/stm32u595aj" ] -stm32u595qi = [ "stm32-metapac/stm32u595qi" ] -stm32u595qj = [ "stm32-metapac/stm32u595qj" ] -stm32u595ri = [ "stm32-metapac/stm32u595ri" ] -stm32u595rj = [ "stm32-metapac/stm32u595rj" ] -stm32u595vi = [ "stm32-metapac/stm32u595vi" ] -stm32u595vj = [ "stm32-metapac/stm32u595vj" ] -stm32u595zi = [ "stm32-metapac/stm32u595zi" ] -stm32u595zj = [ "stm32-metapac/stm32u595zj" ] -stm32u599bj = [ "stm32-metapac/stm32u599bj" ] -stm32u599ni = [ "stm32-metapac/stm32u599ni" ] -stm32u599nj = [ "stm32-metapac/stm32u599nj" ] -stm32u599vi = [ "stm32-metapac/stm32u599vi" ] -stm32u599vj = [ "stm32-metapac/stm32u599vj" ] -stm32u599zi = [ "stm32-metapac/stm32u599zi" ] -stm32u599zj = [ "stm32-metapac/stm32u599zj" ] -stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] -stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] -stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] -stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] -stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ] -stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ] -stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ] -stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ] -stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ] +stm32l552cc = [ "stm32-metapac/stm32l552cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552ce = [ "stm32-metapac/stm32l552ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552me = [ "stm32-metapac/stm32l552me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552qc = [ "stm32-metapac/stm32l552qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552qe = [ "stm32-metapac/stm32l552qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552rc = [ "stm32-metapac/stm32l552rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552re = [ "stm32-metapac/stm32l552re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552vc = [ "stm32-metapac/stm32l552vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552ve = [ "stm32-metapac/stm32l552ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552zc = [ "stm32-metapac/stm32l552zc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552ze = [ "stm32-metapac/stm32l552ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l562ce = [ "stm32-metapac/stm32l562ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l562me = [ "stm32-metapac/stm32l562me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l562qe = [ "stm32-metapac/stm32l562qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l562re = [ "stm32-metapac/stm32l562re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l562ve = [ "stm32-metapac/stm32l562ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l562ze = [ "stm32-metapac/stm32l562ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535cb = [ "stm32-metapac/stm32u535cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535cc = [ "stm32-metapac/stm32u535cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535ce = [ "stm32-metapac/stm32u535ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535je = [ "stm32-metapac/stm32u535je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535nc = [ "stm32-metapac/stm32u535nc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535ne = [ "stm32-metapac/stm32u535ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535rb = [ "stm32-metapac/stm32u535rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535rc = [ "stm32-metapac/stm32u535rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535re = [ "stm32-metapac/stm32u535re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535vc = [ "stm32-metapac/stm32u535vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u535ve = [ "stm32-metapac/stm32u535ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u545ce = [ "stm32-metapac/stm32u545ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u545je = [ "stm32-metapac/stm32u545je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u545ne = [ "stm32-metapac/stm32u545ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u545re = [ "stm32-metapac/stm32u545re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u545ve = [ "stm32-metapac/stm32u545ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575ag = [ "stm32-metapac/stm32u575ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575ai = [ "stm32-metapac/stm32u575ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575cg = [ "stm32-metapac/stm32u575cg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575ci = [ "stm32-metapac/stm32u575ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575og = [ "stm32-metapac/stm32u575og", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575oi = [ "stm32-metapac/stm32u575oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575qg = [ "stm32-metapac/stm32u575qg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575qi = [ "stm32-metapac/stm32u575qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575rg = [ "stm32-metapac/stm32u575rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575ri = [ "stm32-metapac/stm32u575ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575vg = [ "stm32-metapac/stm32u575vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575vi = [ "stm32-metapac/stm32u575vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575zg = [ "stm32-metapac/stm32u575zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u575zi = [ "stm32-metapac/stm32u575zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u585ai = [ "stm32-metapac/stm32u585ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u585ci = [ "stm32-metapac/stm32u585ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u585oi = [ "stm32-metapac/stm32u585oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u585qi = [ "stm32-metapac/stm32u585qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u585ri = [ "stm32-metapac/stm32u585ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u585vi = [ "stm32-metapac/stm32u585vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u585zi = [ "stm32-metapac/stm32u585zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595ai = [ "stm32-metapac/stm32u595ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595aj = [ "stm32-metapac/stm32u595aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595qi = [ "stm32-metapac/stm32u595qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595qj = [ "stm32-metapac/stm32u595qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595ri = [ "stm32-metapac/stm32u595ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595rj = [ "stm32-metapac/stm32u595rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595vi = [ "stm32-metapac/stm32u595vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595vj = [ "stm32-metapac/stm32u595vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595zi = [ "stm32-metapac/stm32u595zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u595zj = [ "stm32-metapac/stm32u595zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u599bj = [ "stm32-metapac/stm32u599bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u599ni = [ "stm32-metapac/stm32u599ni", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u599nj = [ "stm32-metapac/stm32u599nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u599vi = [ "stm32-metapac/stm32u599vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u599vj = [ "stm32-metapac/stm32u599vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u599zi = [ "stm32-metapac/stm32u599zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u599zj = [ "stm32-metapac/stm32u599zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 895ad3e7c..b87f461b4 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g473re", "memory-x", "unstable-pac", "exti", "fdcan"] } 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"] } From 03ba45065e529284d41ebca5a8e716633107fc48 Mon Sep 17 00:00:00 2001 From: Tomasz bla Fortuna Date: Sun, 14 Jan 2024 09:47:26 +0100 Subject: [PATCH 335/760] Add FDCAN clock registers to G4 RCC. Author: Adam Morgan Break definitions out of bxcan that can be used innm fdcan. Typo --- embassy-stm32/build.rs | 2 +- embassy-stm32/src/can/bxcan.rs | 124 ++++----------------------------- embassy-stm32/src/can/enums.rs | 30 ++++++++ embassy-stm32/src/can/util.rs | 117 +++++++++++++++++++++++++++++++ embassy-stm32/src/rcc/g4.rs | 7 +- embassy-stm32/src/rcc/h.rs | 8 ++- 6 files changed, 173 insertions(+), 115 deletions(-) create mode 100644 embassy-stm32/src/can/enums.rs create mode 100644 embassy-stm32/src/can/util.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 948ce3aff..414723573 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -449,7 +449,7 @@ fn main() { // ======== // Generate RccPeripheral impls - let refcounted_peripherals = HashSet::from(["usart", "adc"]); + let refcounted_peripherals = HashSet::from(["usart", "adc", "can"]); let mut refcount_statics = BTreeSet::new(); for p in METADATA.peripherals { diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index cc87b2565..7e00eca6f 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -13,9 +13,12 @@ use crate::gpio::sealed::AFType; use crate::interrupt::typelevel::Interrupt; use crate::pac::can::vals::{Ide, Lec}; use crate::rcc::RccPeripheral; -use crate::time::Hertz; use crate::{interrupt, peripherals, Peripheral}; +pub mod enums; +use enums::*; +pub mod util; + /// Contains CAN frame and additional metadata. /// /// Timestamp is available if `time` feature is enabled. @@ -93,23 +96,6 @@ pub struct Can<'d, T: Instance> { can: bxcan::Can>, } -/// CAN bus error -#[allow(missing_docs)] -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum BusError { - Stuff, - Form, - Acknowledge, - BitRecessive, - BitDominant, - Crc, - Software, - BusOff, - BusPassive, - BusWarning, -} - /// Error returned by `try_read` #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -186,8 +172,15 @@ impl<'d, T: Instance> Can<'d, T> { /// Set CAN bit rate. pub fn set_bitrate(&mut self, bitrate: u32) { - let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); - self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); + let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); + let sjw = u8::from(bit_timing.sync_jump_width) as u32; + let seg1 = u8::from(bit_timing.seg1) as u32; + let seg2 = u8::from(bit_timing.seg2) as u32; + let prescaler = u16::from(bit_timing.prescaler) as u32; + self.can + .modify_config() + .set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1)) + .leave_disabled(); } /// Enables the peripheral and synchronizes with the bus. @@ -302,97 +295,6 @@ impl<'d, T: Instance> Can<'d, T> { } } - const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option { - const BS1_MAX: u8 = 16; - const BS2_MAX: u8 = 8; - const MAX_SAMPLE_POINT_PERMILL: u16 = 900; - - let periph_clock = periph_clock.0; - - if can_bitrate < 1000 { - return None; - } - - // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG - // CAN in Automation, 2003 - // - // According to the source, optimal quanta per bit are: - // Bitrate Optimal Maximum - // 1000 kbps 8 10 - // 500 kbps 16 17 - // 250 kbps 16 17 - // 125 kbps 16 17 - let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 }; - - // Computing (prescaler * BS): - // BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual - // BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified - // let: - // BS = 1 + BS1 + BS2 -- Number of time quanta per bit - // PRESCALER_BS = PRESCALER * BS - // ==> - // PRESCALER_BS = PCLK / BITRATE - let prescaler_bs = periph_clock / can_bitrate; - - // Searching for such prescaler value so that the number of quanta per bit is highest. - let mut bs1_bs2_sum = max_quanta_per_bit - 1; - while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { - if bs1_bs2_sum <= 2 { - return None; // No solution - } - bs1_bs2_sum -= 1; - } - - let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; - if (prescaler < 1) || (prescaler > 1024) { - return None; // No solution - } - - // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. - // We need to find such values so that the sample point is as close as possible to the optimal value, - // which is 87.5%, which is 7/8. - // - // Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *) - // {{bs2 -> (1 + bs1)/7}} - // - // Hence: - // bs2 = (1 + bs1) / 7 - // bs1 = (7 * bs1_bs2_sum - 1) / 8 - // - // Sample point location can be computed as follows: - // Sample point location = (1 + bs1) / (1 + bs1 + bs2) - // - // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one: - // - With rounding to nearest - // - With rounding to zero - let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first - let mut bs2 = bs1_bs2_sum - bs1; - core::assert!(bs1_bs2_sum > bs1); - - let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16; - if sample_point_permill > MAX_SAMPLE_POINT_PERMILL { - // Nope, too far; now rounding to zero - bs1 = (7 * bs1_bs2_sum - 1) / 8; - bs2 = bs1_bs2_sum - bs1; - } - - // Check is BS1 and BS2 are in range - if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { - return None; - } - - // Check if final bitrate matches the requested - if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { - return None; - } - - // One is recommended by DS-015, CANOpen, and DeviceNet - let sjw = 1; - - // Pack into BTR register values - Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) - } - /// Split the CAN driver into transmit and receive halves. /// /// Useful for doing separate transmit/receive tasks. diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs new file mode 100644 index 000000000..36139a45c --- /dev/null +++ b/embassy-stm32/src/can/enums.rs @@ -0,0 +1,30 @@ +//! Enums shared between CAN controller types. + +/// Bus error +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum BusError { + /// Bit stuffing error - more than 5 equal bits + Stuff, + /// Form error - A fixed format part of a received message has wrong format + Form, + /// The message transmitted by the FDCAN was not acknowledged by another node. + Acknowledge, + /// Bit0Error: During the transmission of a message the device wanted to send a dominant level + /// but the monitored bus value was recessive. + BitRecessive, + /// Bit1Error: During the transmission of a message the device wanted to send a recessive level + /// but the monitored bus value was dominant. + BitDominant, + /// The CRC check sum of a received message was incorrect. The CRC of an + /// incoming message does not match with the CRC calculated from the received data. + Crc, + /// A software error occured + Software, + /// The FDCAN is in Bus_Off state. + BusOff, + /// The FDCAN is in the Error_Passive state. + BusPassive, + /// At least one of error counter has reached the Error_Warning limit of 96. + BusWarning, +} diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs new file mode 100644 index 000000000..fcdbbad62 --- /dev/null +++ b/embassy-stm32/src/can/util.rs @@ -0,0 +1,117 @@ +//! Utility functions shared between CAN controller types. + +use core::num::{NonZeroU16, NonZeroU8}; + +/// Shared struct to represent bit timings used by calc_can_timings. +#[derive(Clone, Copy, Debug)] +pub struct NominalBitTiming { + /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit + /// time is built up from a multiple of this quanta. Valid values are 1 to 512. + pub prescaler: NonZeroU16, + /// Valid values are 1 to 128. + pub seg1: NonZeroU8, + /// Valid values are 1 to 255. + pub seg2: NonZeroU8, + /// Valid values are 1 to 128. + pub sync_jump_width: NonZeroU8, +} + +/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency +pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option { + const BS1_MAX: u8 = 16; + const BS2_MAX: u8 = 8; + const MAX_SAMPLE_POINT_PERMILL: u16 = 900; + + let periph_clock = periph_clock.0; + + if can_bitrate < 1000 { + return None; + } + + // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG + // CAN in Automation, 2003 + // + // According to the source, optimal quanta per bit are: + // Bitrate Optimal Maximum + // 1000 kbps 8 10 + // 500 kbps 16 17 + // 250 kbps 16 17 + // 125 kbps 16 17 + let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 }; + + // Computing (prescaler * BS): + // BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual + // BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified + // let: + // BS = 1 + BS1 + BS2 -- Number of time quanta per bit + // PRESCALER_BS = PRESCALER * BS + // ==> + // PRESCALER_BS = PCLK / BITRATE + let prescaler_bs = periph_clock / can_bitrate; + + // Searching for such prescaler value so that the number of quanta per bit is highest. + let mut bs1_bs2_sum = max_quanta_per_bit - 1; + while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { + if bs1_bs2_sum <= 2 { + return None; // No solution + } + bs1_bs2_sum -= 1; + } + + let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; + if (prescaler < 1) || (prescaler > 1024) { + return None; // No solution + } + + // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. + // We need to find such values so that the sample point is as close as possible to the optimal value, + // which is 87.5%, which is 7/8. + // + // Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *) + // {{bs2 -> (1 + bs1)/7}} + // + // Hence: + // bs2 = (1 + bs1) / 7 + // bs1 = (7 * bs1_bs2_sum - 1) / 8 + // + // Sample point location can be computed as follows: + // Sample point location = (1 + bs1) / (1 + bs1 + bs2) + // + // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one: + // - With rounding to nearest + // - With rounding to zero + let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first + let mut bs2 = bs1_bs2_sum - bs1; + core::assert!(bs1_bs2_sum > bs1); + + let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16; + if sample_point_permill > MAX_SAMPLE_POINT_PERMILL { + // Nope, too far; now rounding to zero + bs1 = (7 * bs1_bs2_sum - 1) / 8; + bs2 = bs1_bs2_sum - bs1; + } + + // Check is BS1 and BS2 are in range + if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { + return None; + } + + // Check if final bitrate matches the requested + if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { + return None; + } + + // One is recommended by DS-015, CANOpen, and DeviceNet + let sync_jump_width = core::num::NonZeroU8::new(1)?; + + let seg1 = core::num::NonZeroU8::new(bs1)?; + let seg2 = core::num::NonZeroU8::new(bs2)?; + let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?; + + Some(NominalBitTiming { + sync_jump_width, + prescaler: nz_prescaler, + seg1, + seg2, + }) +} diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index fca364c21..891f0490b 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -3,8 +3,8 @@ use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw}; use stm32_metapac::FLASH; pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ, - Pllr as PllR, Ppre as APBPrescaler, + Adcsel as AdcClockSource, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, + Pllp as PllP, Pllq as PllQ, Pllr as PllR, Ppre as APBPrescaler, }; use crate::pac::{PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; @@ -87,6 +87,7 @@ pub struct Config { pub clock_48mhz_src: Option, pub adc12_clock_source: AdcClockSource, pub adc345_clock_source: AdcClockSource, + pub fdcan_clock_source: FdCanClockSource, pub ls: super::LsConfig, } @@ -104,6 +105,7 @@ impl Default for Config { clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())), adc12_clock_source: Adcsel::DISABLE, adc345_clock_source: Adcsel::DISABLE, + fdcan_clock_source: FdCanClockSource::PCLK1, ls: Default::default(), } } @@ -282,6 +284,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); + RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source)); let adc12_ck = match config.adc12_clock_source { AdcClockSource::DISABLE => None, diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 15b51a398..85e12637e 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -6,6 +6,7 @@ use crate::pac::pwr::vals::Vos; pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; #[cfg(stm32h7)] pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; +pub use crate::pac::rcc::vals::Fdcansel as FdCanClockSource; pub use crate::pac::rcc::vals::{ Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, @@ -212,6 +213,8 @@ pub struct Config { pub per_clock_source: PerClockSource, pub adc_clock_source: AdcClockSource, + pub fdcan_clock_source: FdCanClockSource, + pub timer_prescaler: TimerPrescaler, pub voltage_scale: VoltageScale, pub ls: super::LsConfig, @@ -248,6 +251,8 @@ impl Default for Config { #[cfg(stm32h7)] adc_clock_source: AdcClockSource::PER, + fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE + timer_prescaler: TimerPrescaler::DefaultX2, voltage_scale: VoltageScale::Scale0, ls: Default::default(), @@ -585,7 +590,8 @@ pub(crate) unsafe fn init(config: Config) { RCC.ccipr5().modify(|w| { w.set_ckpersel(config.per_clock_source); - w.set_adcdacsel(config.adc_clock_source) + w.set_adcdacsel(config.adc_clock_source); + w.set_fdcan1sel(config.fdcan_clock_source) }); } From 1de78d049017b7d21946a2e64d94c990f1bf4e7e Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 14 Jan 2024 10:12:49 +0100 Subject: [PATCH 336/760] Initial FDCAN driver implementation. Original author: Torin Cooper-Bennun Cleanup and documentaion by: Tomasz bla Fortuna Corey Schuhen Use new PAC method now that the names are common. Use broken out definitions that can be shared with bxcan Populate Rx struct with an embassy timestamp. Remove use of RefCell. As per review comment. - THis will probably get squashed down. Fix --- embassy-stm32/src/can/fdcan.rs | 714 ++++++++++++++++++++++++++++++++- embassy-stm32/src/rcc/h.rs | 7 +- 2 files changed, 706 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 0cc2559cf..faf4af73f 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -1,14 +1,577 @@ -use crate::peripherals; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; +use core::task::Poll; + +use cfg_if::cfg_if; +use embassy_hal_internal::{into_ref, PeripheralRef}; +pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader}; +pub use fdcan::id::{ExtendedId, Id, StandardId}; +use fdcan::message_ram::RegisterBlock; +use fdcan::{self, LastErrorCode}; +pub use fdcan::{config, filter}; + +use crate::gpio::sealed::AFType; +use crate::interrupt::typelevel::Interrupt; +use crate::rcc::RccPeripheral; +use crate::{interrupt, peripherals, Peripheral}; + +pub mod enums; +use enums::*; +pub mod util; + +/// CAN Frame returned by read +pub struct RxFrame { + /// CAN Header info: frame ID, data length and other meta + pub header: RxFrameInfo, + /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data + pub data: Data, + /// Reception time. + #[cfg(feature = "time")] + pub timestamp: embassy_time::Instant, +} + +/// CAN frame used for write +pub struct TxFrame { + /// CAN Header info: frame ID, data length and other meta + pub header: TxFrameHeader, + /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data + pub data: Data, +} + +impl TxFrame { + /// Create new TX frame from header and data + pub fn new(header: TxFrameHeader, data: &[u8]) -> Option { + if data.len() < header.len as usize { + return None; + } + + let Some(data) = Data::new(data) else { return None }; + + Some(TxFrame { header, data }) + } + + fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option { + let mut data = [0u8; 64]; + + for i in 0..data32.len() { + data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes()); + } + + let Some(data) = Data::new(&data) else { return None }; + + Some(TxFrame { header, data }) + } + + /// Access frame data. Slice length will match header. + pub fn data(&self) -> &[u8] { + &self.data.bytes[..(self.header.len as usize)] + } +} + +impl RxFrame { + pub(crate) fn new( + header: RxFrameInfo, + data: &[u8], + #[cfg(feature = "time")] timestamp: embassy_time::Instant, + ) -> Self { + let data = Data::new(&data).unwrap_or_else(|| Data::empty()); + + RxFrame { + header, + data, + #[cfg(feature = "time")] + timestamp, + } + } + + /// Access frame data. Slice length will match header. + pub fn data(&self) -> &[u8] { + &self.data.bytes[..(self.header.len as usize)] + } +} + +/// Payload of a (FD)CAN data frame. +/// +/// Contains 0 to 64 Bytes of data. +#[derive(Debug, Copy, Clone)] +pub struct Data { + pub(crate) bytes: [u8; 64], +} + +impl Data { + /// Creates a data payload from a raw byte slice. + /// + /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or + /// cannot be represented with an FDCAN DLC. + pub fn new(data: &[u8]) -> Option { + if !Data::is_valid_len(data.len()) { + return None; + } + + let mut bytes = [0; 64]; + bytes[..data.len()].copy_from_slice(data); + + Some(Self { bytes }) + } + + /// Raw read access to data. + pub fn raw(&self) -> &[u8] { + &self.bytes + } + + /// Checks if the length can be encoded in FDCAN DLC field. + pub const fn is_valid_len(len: usize) -> bool { + match len { + 0..=8 => true, + 12 => true, + 16 => true, + 20 => true, + 24 => true, + 32 => true, + 48 => true, + 64 => true, + _ => false, + } + } + + /// Creates an empty data payload containing 0 bytes. + #[inline] + pub const fn empty() -> Self { + Self { bytes: [0; 64] } + } +} + +/// Interrupt handler channel 0. +pub struct IT0InterruptHandler { + _phantom: PhantomData, +} + +// We use IT0 for everything currently +impl interrupt::typelevel::Handler for IT0InterruptHandler { + unsafe fn on_interrupt() { + let regs = T::regs(); + + let ir = regs.ir().read(); + + if ir.tc() { + regs.ir().write(|w| w.set_tc(true)); + T::state().tx_waker.wake(); + } + + if ir.tefn() { + regs.ir().write(|w| w.set_tefn(true)); + T::state().tx_waker.wake(); + } + + if ir.ped() || ir.pea() { + regs.ir().write(|w| { + w.set_ped(true); + w.set_pea(true); + }); + } + + if ir.rfn(0) { + regs.ir().write(|w| w.set_rfn(0, true)); + T::state().rx_waker.wake(); + } + + if ir.rfn(1) { + regs.ir().write(|w| w.set_rfn(1, true)); + T::state().rx_waker.wake(); + } + } +} + +/// Interrupt handler channel 1. +pub struct IT1InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for IT1InterruptHandler { + unsafe fn on_interrupt() {} +} + +impl BusError { + fn try_from(lec: LastErrorCode) -> Option { + match lec { + LastErrorCode::AckError => Some(BusError::Acknowledge), + // `0` data bit encodes a dominant state. `1` data bit is recessive. + // Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1 + LastErrorCode::Bit0Error => Some(BusError::BitRecessive), + LastErrorCode::Bit1Error => Some(BusError::BitDominant), + LastErrorCode::CRCError => Some(BusError::Crc), + LastErrorCode::FormError => Some(BusError::Form), + LastErrorCode::StuffError => Some(BusError::Stuff), + _ => None, + } + } +} + +/// Operating modes trait +pub trait FdcanOperatingMode {} +impl FdcanOperatingMode for fdcan::PoweredDownMode {} +impl FdcanOperatingMode for fdcan::ConfigMode {} +impl FdcanOperatingMode for fdcan::InternalLoopbackMode {} +impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {} +impl FdcanOperatingMode for fdcan::NormalOperationMode {} +impl FdcanOperatingMode for fdcan::RestrictedOperationMode {} +impl FdcanOperatingMode for fdcan::BusMonitoringMode {} +impl FdcanOperatingMode for fdcan::TestMode {} + +/// FDCAN Instance +pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { + /// Reference to internals. + pub can: fdcan::FdCan, M>, + ns_per_timer_tick: u64, // For FDCAN internal timer +} + +fn calc_ns_per_timer_tick(mode: config::FrameTransmissionConfig) -> u64 { + match mode { + // Use timestamp from Rx FIFO to adjust timestamp reported to user + config::FrameTransmissionConfig::ClassicCanOnly => { + let freq = T::frequency(); + let prescale: u64 = + ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; + 1_000_000_000 as u64 / (freq.0 as u64 * prescale) + } + // For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use + // timer3 instead which is too hard to do from this module. + _ => 0, + } +} + +#[cfg(feature = "time")] +fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant { + let now_embassy = embassy_time::Instant::now(); + if ns_per_timer_tick == 0 { + return now_embassy; + } + let now_can = { T::regs().tscv().read().tsc() }; + let delta = now_can.overflowing_sub(ts_val).0 as u64; + let ns = ns_per_timer_tick * delta as u64; + now_embassy - embassy_time::Duration::from_nanos(ns) +} + +fn curr_error() -> Option { + let err = { T::regs().psr().read() }; + if err.bo() { + return Some(BusError::BusOff); + } else if err.ep() { + return Some(BusError::BusPassive); + } else if err.ew() { + return Some(BusError::BusWarning); + } else { + cfg_if! { + if #[cfg(stm32h7)] { + let lec = err.lec(); + } else { + let lec = err.lec().to_bits(); + } + } + if let Ok(err) = LastErrorCode::try_from(lec) { + return BusError::try_from(err); + } + } + None +} + +impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { + /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. + /// You must call [Fdcan::enable_non_blocking] to use the peripheral. + pub fn new( + peri: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + tx: impl Peripheral

> + 'd, + _irqs: impl interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + 'd, + ) -> Fdcan<'d, T, fdcan::ConfigMode> { + into_ref!(peri, rx, tx); + + rx.set_as_af(rx.af_num(), AFType::Input); + tx.set_as_af(tx.af_num(), AFType::OutputPushPull); + + T::enable_and_reset(); + + rx.set_as_af(rx.af_num(), AFType::Input); + tx.set_as_af(tx.af_num(), AFType::OutputPushPull); + + let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode(); + + T::configure_msg_ram(); + unsafe { + // Enable timestamping + #[cfg(not(stm32h7))] + T::regs() + .tscc() + .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); + #[cfg(stm32h7)] + T::regs().tscc().write(|w| w.set_tss(0x01)); + + T::IT0Interrupt::unpend(); // Not unsafe + T::IT0Interrupt::enable(); + + T::IT1Interrupt::unpend(); // Not unsafe + T::IT1Interrupt::enable(); + + // this isn't really documented in the reference manual + // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire + T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); + } + + can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); + can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg); + can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete); + can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); + can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true); + + let ns_per_timer_tick = calc_ns_per_timer_tick::(can.get_config().frame_transmit); + Self { can, ns_per_timer_tick } + } + + /// Configures the bit timings calculated from supplied bitrate. + pub fn set_bitrate(&mut self, bitrate: u32) { + let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); + self.can.set_nominal_bit_timing(config::NominalBitTiming { + sync_jump_width: bit_timing.sync_jump_width, + prescaler: bit_timing.prescaler, + seg1: bit_timing.seg1, + seg2: bit_timing.seg2, + }); + } +} + +macro_rules! impl_transition { + ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => { + impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> { + /// Transition from $from_mode:ident mode to $to_mode:ident mode + pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> { + let ns_per_timer_tick = calc_ns_per_timer_tick::(self.can.get_config().frame_transmit); + Fdcan { + can: self.can.$func(), + ns_per_timer_tick, + } + } + } + }; +} + +impl_transition!(PoweredDownMode, ConfigMode, into_config_mode, into_config_mode); +impl_transition!(InternalLoopbackMode, ConfigMode, into_config_mode, into_config_mode); + +impl_transition!(ConfigMode, NormalOperationMode, into_normal_mode, into_normal); +impl_transition!( + ConfigMode, + ExternalLoopbackMode, + into_external_loopback_mode, + into_external_loopback +); +impl_transition!( + ConfigMode, + InternalLoopbackMode, + into_internal_loopback_mode, + into_internal_loopback +); + +impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M> +where + M: fdcan::Transmit, + M: fdcan::Receive, +{ + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + pub async fn write(&mut self, frame: &TxFrame) -> Option { + poll_fn(|cx| { + T::state().tx_waker.register(cx.waker()); + if let Ok(dropped) = self + .can + .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { + TxFrame::from_preserved(hdr, data32) + }) + { + return Poll::Ready(dropped.flatten()); + } + + // Couldn't replace any lower priority frames. Need to wait for some mailboxes + // to clear. + Poll::Pending + }) + .await + } + + /// Flush one of the TX mailboxes. + pub async fn flush(&self, mb: fdcan::Mailbox) { + poll_fn(|cx| { + T::state().tx_waker.register(cx.waker()); + + let idx: u8 = mb.into(); + let idx = 1 << idx; + if !T::regs().txbrp().read().trp(idx) { + return Poll::Ready(()); + } + + Poll::Pending + }) + .await; + } + + /// Returns the next received message frame + pub async fn read(&mut self) -> Result { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + T::state().rx_waker.register(cx.waker()); + + let mut buffer: [u8; 64] = [0; 64]; + if let Ok(rx) = self.can.receive0(&mut buffer) { + // rx: fdcan::ReceiveOverrun + // TODO: report overrun? + // for now we just drop it + + let frame: RxFrame = RxFrame::new( + rx.unwrap(), + &buffer, + #[cfg(feature = "time")] + calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), + ); + return Poll::Ready(Ok(frame)); + } else if let Ok(rx) = self.can.receive1(&mut buffer) { + // rx: fdcan::ReceiveOverrun + // TODO: report overrun? + // for now we just drop it + + let frame: RxFrame = RxFrame::new( + rx.unwrap(), + &buffer, + #[cfg(feature = "time")] + calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), + ); + return Poll::Ready(Ok(frame)); + } else if let Some(err) = curr_error::() { + // TODO: this is probably wrong + return Poll::Ready(Err(err)); + } + Poll::Pending + }) + .await + } + + /// Split instance into separate Tx(write) and Rx(read) portions + pub fn split<'c>(&'c mut self) -> (FdcanTx<'c, 'd, T, M>, FdcanRx<'c, 'd, T, M>) { + let (mut _control, tx, rx0, rx1) = self.can.split_by_ref(); + ( + FdcanTx { _control, tx }, + FdcanRx { + rx0, + rx1, + ns_per_timer_tick: self.ns_per_timer_tick, + }, + ) + } +} + +/// FDCAN Tx only Instance +pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> { + _control: &'c mut fdcan::FdCanControl, M>, + tx: &'c mut fdcan::Tx, M>, +} + +impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> { + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + pub async fn write(&mut self, frame: &TxFrame) -> Option { + poll_fn(|cx| { + T::state().tx_waker.register(cx.waker()); + if let Ok(dropped) = self + .tx + .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { + TxFrame::from_preserved(hdr, data32) + }) + { + return Poll::Ready(dropped.flatten()); + } + + // Couldn't replace any lower priority frames. Need to wait for some mailboxes + // to clear. + Poll::Pending + }) + .await + } +} + +/// FDCAN Rx only Instance +#[allow(dead_code)] +pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> { + rx0: &'c mut fdcan::Rx, M, fdcan::Fifo0>, + rx1: &'c mut fdcan::Rx, M, fdcan::Fifo1>, + ns_per_timer_tick: u64, // For FDCAN internal timer +} + +impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> { + /// Returns the next received message frame + pub async fn read(&mut self) -> Result { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + T::state().rx_waker.register(cx.waker()); + + let mut buffer: [u8; 64] = [0; 64]; + if let Ok(rx) = self.rx0.receive(&mut buffer) { + // rx: fdcan::ReceiveOverrun + // TODO: report overrun? + // for now we just drop it + let frame: RxFrame = RxFrame::new( + rx.unwrap(), + &buffer, + #[cfg(feature = "time")] + calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), + ); + return Poll::Ready(Ok(frame)); + } else if let Ok(rx) = self.rx1.receive(&mut buffer) { + // rx: fdcan::ReceiveOverrun + // TODO: report overrun? + // for now we just drop it + let frame: RxFrame = RxFrame::new( + rx.unwrap(), + &buffer, + #[cfg(feature = "time")] + calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), + ); + return Poll::Ready(Ok(frame)); + } else if let Some(err) = curr_error::() { + // TODO: this is probably wrong + return Poll::Ready(Err(err)); + } + + Poll::Pending + }) + .await + } +} +impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> { + type Target = fdcan::FdCan, M>; + + fn deref(&self) -> &Self::Target { + &self.can + } +} + +impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.can + } +} pub(crate) mod sealed { - use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; - use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; pub struct State { pub tx_waker: AtomicWaker, pub err_waker: AtomicWaker, - pub rx_queue: Channel, + pub rx_waker: AtomicWaker, } impl State { @@ -16,25 +579,122 @@ pub(crate) mod sealed { Self { tx_waker: AtomicWaker::new(), err_waker: AtomicWaker::new(), - rx_queue: Channel::new(), + rx_waker: AtomicWaker::new(), } } } pub trait Instance { + const REGISTERS: *mut fdcan::RegisterBlock; + const MSG_RAM: *mut fdcan::message_ram::RegisterBlock; + const MSG_RAM_OFFSET: usize; + fn regs() -> &'static crate::pac::can::Fdcan; fn state() -> &'static State; + + #[cfg(not(stm32h7))] + fn configure_msg_ram() {} + + #[cfg(stm32h7)] + fn configure_msg_ram() { + let r = Self::regs(); + + use fdcan::message_ram::*; + let mut offset_words = Self::MSG_RAM_OFFSET as u16; + + // 11-bit filter + r.sidfc().modify(|w| w.set_flssa(offset_words)); + offset_words += STANDARD_FILTER_MAX as u16; + + // 29-bit filter + r.xidfc().modify(|w| w.set_flesa(offset_words)); + offset_words += 2 * EXTENDED_FILTER_MAX as u16; + + // Rx FIFO 0 and 1 + for i in 0..=1 { + r.rxfc(i).modify(|w| { + w.set_fsa(offset_words); + w.set_fs(RX_FIFO_MAX); + w.set_fwm(RX_FIFO_MAX); + }); + offset_words += 18 * RX_FIFO_MAX as u16; + } + + // Rx buffer - see below + // Tx event FIFO + r.txefc().modify(|w| { + w.set_efsa(offset_words); + w.set_efs(TX_EVENT_MAX); + w.set_efwm(TX_EVENT_MAX); + }); + offset_words += 2 * TX_EVENT_MAX as u16; + + // Tx buffers + r.txbc().modify(|w| { + w.set_tbsa(offset_words); + w.set_tfqs(TX_FIFO_MAX); + }); + offset_words += 18 * TX_FIFO_MAX as u16; + + // Rx Buffer - not used + r.rxbc().modify(|w| { + w.set_rbsa(offset_words); + }); + + // TX event FIFO? + // Trigger memory? + + // Set the element sizes to 16 bytes + r.rxesc().modify(|w| { + w.set_rbds(0b111); + for i in 0..=1 { + w.set_fds(i, 0b111); + } + }); + r.txesc().modify(|w| { + w.set_tbds(0b111); + }) + } } } -/// Interruptable FDCAN instance. -pub trait InterruptableInstance {} -/// FDCAN instance. -pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} +/// Trait for FDCAN interrupt channel 0 +pub trait IT0Instance { + /// Type for FDCAN interrupt channel 0 + type IT0Interrupt: crate::interrupt::typelevel::Interrupt; +} -foreach_peripheral!( - (can, $inst:ident) => { +/// Trait for FDCAN interrupt channel 1 +pub trait IT1Instance { + /// Type for FDCAN interrupt channel 1 + type IT1Interrupt: crate::interrupt::typelevel::Interrupt; +} + +/// InterruptableInstance trait +pub trait InterruptableInstance: IT0Instance + IT1Instance {} +/// Instance trait +pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {} +/// Fdcan Instance struct +pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); + +unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> { + const MSG_RAM: *mut RegisterBlock = T::MSG_RAM; +} + +unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T> +where + FdcanInstance<'d, T>: fdcan::message_ram::Instance, +{ + const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS; +} + +macro_rules! impl_fdcan { + ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { impl sealed::Instance for peripherals::$inst { + const REGISTERS: *mut fdcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; + const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = crate::pac::$msg_ram_inst.as_ptr() as *mut _; + const MSG_RAM_OFFSET: usize = $msg_ram_offset; + fn regs() -> &'static crate::pac::can::Fdcan { &crate::pac::$inst } @@ -47,8 +707,40 @@ foreach_peripheral!( impl Instance for peripherals::$inst {} + foreach_interrupt!( + ($inst,can,FDCAN,IT0,$irq:ident) => { + impl IT0Instance for peripherals::$inst { + type IT0Interrupt = crate::interrupt::typelevel::$irq; + } + }; + ($inst,can,FDCAN,IT1,$irq:ident) => { + impl IT1Instance for peripherals::$inst { + type IT1Interrupt = crate::interrupt::typelevel::$irq; + } + }; + ); + impl InterruptableInstance for peripherals::$inst {} }; + + ($inst:ident, $msg_ram_inst:ident) => { + impl_fdcan!($inst, $msg_ram_inst, 0); + }; +} + +#[cfg(not(stm32h7))] +foreach_peripheral!( + (can, FDCAN) => { impl_fdcan!(FDCAN, FDCANRAM); }; + (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM1); }; + (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM2); }; + (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM3); }; +); + +#[cfg(stm32h7)] +foreach_peripheral!( + (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM, 0x0000); }; + (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM, 0x0C00); }; + (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM, 0x1800); }; ); pin_trait!(RxPin, Instance); diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 85e12637e..dcaf2dced 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -6,10 +6,9 @@ use crate::pac::pwr::vals::Vos; pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; #[cfg(stm32h7)] pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; -pub use crate::pac::rcc::vals::Fdcansel as FdCanClockSource; pub use crate::pac::rcc::vals::{ - Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, - Pllsrc as PllSource, Sw as Sysclk, + Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, + Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, }; use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; use crate::pac::{FLASH, PWR, RCC}; @@ -591,7 +590,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.ccipr5().modify(|w| { w.set_ckpersel(config.per_clock_source); w.set_adcdacsel(config.adc_clock_source); - w.set_fdcan1sel(config.fdcan_clock_source) + w.set_fdcan12sel(config.fdcan_clock_source) }); } From 1698f4dbc3b5f4e561c3edd20246af63c22da507 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 25 Jan 2024 17:10:25 +1000 Subject: [PATCH 337/760] Add FDCAN examples for STM32G4, STM32H5 and STM32H7 Fix examples Fix examples Fix examples. --- examples/stm32g4/Cargo.toml | 2 +- examples/stm32g4/src/bin/can.rs | 56 +++++++++++++++++++++++++ examples/stm32h5/src/bin/can.rs | 74 +++++++++++++++++++++++++++++++++ examples/stm32h7/src/bin/can.rs | 74 +++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 examples/stm32g4/src/bin/can.rs create mode 100644 examples/stm32h5/src/bin/can.rs create mode 100644 examples/stm32h7/src/bin/can.rs diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index b87f461b4..895ad3e7c 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g473re", "memory-x", "unstable-pac", "exti", "fdcan"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "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"] } diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs new file mode 100644 index 000000000..727921fba --- /dev/null +++ b/examples/stm32g4/src/bin/can.rs @@ -0,0 +1,56 @@ +#![no_std] +#![no_main] +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::peripherals::*; +use embassy_stm32::{bind_interrupts, can, Config}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + FDCAN1_IT0 => can::IT0InterruptHandler; + FDCAN1_IT1 => can::IT1InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let config = Config::default(); + + let peripherals = embassy_stm32::init(config); + + let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + + // 250k bps + can.set_bitrate(250_000); + + info!("Configured"); + + //let mut can = can.into_external_loopback_mode(); + let mut can = can.into_normal_mode(); + + let mut i = 0; + loop { + let frame = can::TxFrame::new( + can::TxFrameHeader { + len: 1, + frame_format: can::FrameFormat::Standard, + id: can::StandardId::new(0x123).unwrap().into(), + bit_rate_switching: false, + marker: None, + }, + &[i], + ) + .unwrap(); + info!("Writing frame"); + _ = can.write(&frame).await; + + match can.read().await { + Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + } +} diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs new file mode 100644 index 000000000..2906d1576 --- /dev/null +++ b/examples/stm32h5/src/bin/can.rs @@ -0,0 +1,74 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::peripherals::*; +use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + FDCAN1_IT0 => can::IT0InterruptHandler; + FDCAN1_IT1 => can::IT1InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + + // configure FDCAN to use PLL1_Q at 64 MHz + config.rcc.pll1 = Some(rcc::Pll { + source: rcc::PllSource::HSI, + prediv: rcc::PllPreDiv::DIV4, + mul: rcc::PllMul::MUL8, + divp: None, + divq: Some(rcc::PllDiv::DIV2), + divr: None, + }); + config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; + + let peripherals = embassy_stm32::init(config); + + let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + + can.can.apply_config( + can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { + sync_jump_width: 1.try_into().unwrap(), + prescaler: 8.try_into().unwrap(), + seg1: 13.try_into().unwrap(), + seg2: 2.try_into().unwrap(), + }), + ); + + info!("Configured"); + + let mut can = can.into_external_loopback_mode(); + //let mut can = can.into_normal_mode(); + + let mut i = 0; + loop { + let frame = can::TxFrame::new( + can::TxFrameHeader { + len: 1, + frame_format: can::FrameFormat::Standard, + id: can::StandardId::new(0x123).unwrap().into(), + bit_rate_switching: false, + marker: None, + }, + &[i], + ) + .unwrap(); + info!("Writing frame"); + _ = can.write(&frame).await; + + match can.read().await { + Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + } +} diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs new file mode 100644 index 000000000..2906d1576 --- /dev/null +++ b/examples/stm32h7/src/bin/can.rs @@ -0,0 +1,74 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::peripherals::*; +use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + FDCAN1_IT0 => can::IT0InterruptHandler; + FDCAN1_IT1 => can::IT1InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + + // configure FDCAN to use PLL1_Q at 64 MHz + config.rcc.pll1 = Some(rcc::Pll { + source: rcc::PllSource::HSI, + prediv: rcc::PllPreDiv::DIV4, + mul: rcc::PllMul::MUL8, + divp: None, + divq: Some(rcc::PllDiv::DIV2), + divr: None, + }); + config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; + + let peripherals = embassy_stm32::init(config); + + let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + + can.can.apply_config( + can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { + sync_jump_width: 1.try_into().unwrap(), + prescaler: 8.try_into().unwrap(), + seg1: 13.try_into().unwrap(), + seg2: 2.try_into().unwrap(), + }), + ); + + info!("Configured"); + + let mut can = can.into_external_loopback_mode(); + //let mut can = can.into_normal_mode(); + + let mut i = 0; + loop { + let frame = can::TxFrame::new( + can::TxFrameHeader { + len: 1, + frame_format: can::FrameFormat::Standard, + id: can::StandardId::new(0x123).unwrap().into(), + bit_rate_switching: false, + marker: None, + }, + &[i], + ) + .unwrap(); + info!("Writing frame"); + _ = can.write(&frame).await; + + match can.read().await { + Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + } +} From 6e1047395d56dbbd1aa1a0352bdd3147e3994c5b Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Wed, 17 Jan 2024 21:13:24 +1000 Subject: [PATCH 338/760] HIL test for STM32 FDCAN support. Internal loopback. fdcan: use common.rs for HIL test. Fix tests. Fix tests. Fix tests Add HIL tests for H7 even though they are a bit crippled. CI fixes Bah Test bah --- tests/stm32/Cargo.toml | 16 ++- tests/stm32/src/bin/fdcan.rs | 243 +++++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 tests/stm32/src/bin/fdcan.rs diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bf85f05d2..b8b52c076 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -14,11 +14,11 @@ stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] -stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"] -stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] -stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"] -stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"] -stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"] +stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] +stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan"] +stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"] +stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"] +stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] @@ -37,6 +37,7 @@ sdmmc = [] stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] chrono = ["embassy-stm32/chrono", "dep:chrono"] can = [] +fdcan = [] ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] embassy-stm32-wpan = [] @@ -96,6 +97,11 @@ name = "eth" path = "src/bin/eth.rs" required-features = [ "eth",] +[[bin]] +name = "fdcan" +path = "src/bin/fdcan.rs" +required-features = [ "fdcan",] + [[bin]] name = "gpio" path = "src/bin/gpio.rs" diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs new file mode 100644 index 000000000..7363eaa16 --- /dev/null +++ b/tests/stm32/src/bin/fdcan.rs @@ -0,0 +1,243 @@ +#![no_std] +#![no_main] + +// required-features: fdcan + +#[path = "../common.rs"] +mod common; +use common::*; +use defmt::assert; +use embassy_executor::Spawner; +use embassy_stm32::peripherals::*; +use embassy_stm32::{bind_interrupts, can, Config}; +use embassy_time::{Duration, Instant}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + FDCAN1_IT0 => can::IT0InterruptHandler; + FDCAN1_IT1 => can::IT1InterruptHandler; +}); + +struct TestOptions { + config: Config, + max_latency: Duration, + second_fifo_working: bool, +} + +#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] +fn options() -> TestOptions { + use embassy_stm32::rcc; + info!("H75 config"); + let mut c = config(); + c.rcc.hse = Some(rcc::Hse { + freq: embassy_stm32::time::Hertz(25_000_000), + mode: rcc::HseMode::Oscillator, + }); + c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + TestOptions { + config: c, + max_latency: Duration::from_micros(3800), + second_fifo_working: false, + } +} + +#[cfg(any(feature = "stm32h7a3zi"))] +fn options() -> TestOptions { + use embassy_stm32::rcc; + info!("H7a config"); + let mut c = config(); + c.rcc.hse = Some(rcc::Hse { + freq: embassy_stm32::time::Hertz(25_000_000), + mode: rcc::HseMode::Oscillator, + }); + c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + TestOptions { + config: c, + max_latency: Duration::from_micros(5500), + second_fifo_working: false, + } +} + +#[cfg(any(feature = "stm32g491re"))] +fn options() -> TestOptions { + info!("G4 config"); + TestOptions { + config: config(), + max_latency: Duration::from_micros(500), + second_fifo_working: true, + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + //let peripherals = embassy_stm32::init(config()); + + let options = options(); + let peripherals = embassy_stm32::init(options.config); + + let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); + + // 250k bps + can.set_bitrate(250_000); + + can.can.set_extended_filter( + can::filter::ExtendedFilterSlot::_0, + can::filter::ExtendedFilter::accept_all_into_fifo1(), + ); + + let mut can = can.into_internal_loopback_mode(); + + info!("CAN Configured"); + + let mut i: u8 = 0; + loop { + let tx_frame = can::TxFrame::new( + can::TxFrameHeader { + len: 1, + frame_format: can::FrameFormat::Standard, + id: can::StandardId::new(0x123).unwrap().into(), + bit_rate_switching: false, + marker: None, + }, + &[i], + ) + .unwrap(); + + info!("Transmitting frame..."); + let tx_ts = Instant::now(); + can.write(&tx_frame).await; + + let envelope = can.read().await.unwrap(); + info!("Frame received!"); + + // Check data. + assert!(i == envelope.data()[0], "{} == {}", i, envelope.data()[0]); + + info!("loopback time {}", envelope.header.time_stamp); + info!("loopback frame {=u8}", envelope.data()[0]); + let latency = envelope.timestamp.saturating_duration_since(tx_ts); + info!("loopback latency {} us", latency.as_micros()); + + // Theoretical minimum latency is 55us, actual is usually ~80us + const MIN_LATENCY: Duration = Duration::from_micros(50); + // Was failing at 150 but we are not getting a real time stamp. I'm not + // sure if there are other delays + assert!( + MIN_LATENCY <= latency && latency <= options.max_latency, + "{} <= {} <= {}", + MIN_LATENCY, + latency, + options.max_latency + ); + + i += 1; + if i > 10 { + break; + } + } + + let max_buffered = if options.second_fifo_working { 6 } else { 3 }; + + // Below here, check that we can receive from both FIFO0 and FIFO0 + // Above we configured FIFO1 for extended ID packets. There are only 3 slots + // in each FIFO so make sure we write enough to fill them both up before reading. + for i in 0..3 { + // Try filling up the RX FIFO0 buffers with standard packets + let tx_frame = can::TxFrame::new( + can::TxFrameHeader { + len: 1, + frame_format: can::FrameFormat::Standard, + id: can::StandardId::new(0x123).unwrap().into(), + bit_rate_switching: false, + marker: None, + }, + &[i], + ) + .unwrap(); + info!("Transmitting frame {}", i); + can.write(&tx_frame).await; + } + for i in 3..max_buffered { + // Try filling up the RX FIFO0 buffers with extended packets + let tx_frame = can::TxFrame::new( + can::TxFrameHeader { + len: 1, + frame_format: can::FrameFormat::Standard, + id: can::ExtendedId::new(0x1232344).unwrap().into(), + bit_rate_switching: false, + marker: None, + }, + &[i], + ) + .unwrap(); + + info!("Transmitting frame {}", i); + can.write(&tx_frame).await; + } + + // Try and receive all 6 packets + for i in 0..max_buffered { + let envelope = can.read().await.unwrap(); + match envelope.header.id { + can::Id::Extended(id) => { + info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); + } + can::Id::Standard(id) => { + info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); + } + } + } + + // Test again with a split + let (mut tx, mut rx) = can.split(); + for i in 0..3 { + // Try filling up the RX FIFO0 buffers with standard packets + let tx_frame = can::TxFrame::new( + can::TxFrameHeader { + len: 1, + frame_format: can::FrameFormat::Standard, + id: can::StandardId::new(0x123).unwrap().into(), + bit_rate_switching: false, + marker: None, + }, + &[i], + ) + .unwrap(); + + info!("Transmitting frame {}", i); + tx.write(&tx_frame).await; + } + for i in 3..max_buffered { + // Try filling up the RX FIFO0 buffers with extended packets + let tx_frame = can::TxFrame::new( + can::TxFrameHeader { + len: 1, + frame_format: can::FrameFormat::Standard, + id: can::ExtendedId::new(0x1232344).unwrap().into(), + bit_rate_switching: false, + marker: None, + }, + &[i], + ) + .unwrap(); + + info!("Transmitting frame {}", i); + tx.write(&tx_frame).await; + } + + // Try and receive all 6 packets + for i in 0..max_buffered { + let envelope = rx.read().await.unwrap(); + match envelope.header.id { + can::Id::Extended(id) => { + info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); + } + can::Id::Standard(id) => { + info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); + } + } + } + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From a14dc8413abacc78002a972cd55b1fbf19bac6df Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Wed, 31 Jan 2024 05:43:37 +1000 Subject: [PATCH 339/760] Disable h563 test. --- tests/stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index b8b52c076..cb1bd9a50 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -15,7 +15,7 @@ stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma" stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] -stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan"] +stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"] stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"] stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] From 7ff21e8b8ba3bd03b4317abbc40f0e6a0b02289f Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Tue, 30 Jan 2024 17:06:57 -0500 Subject: [PATCH 340/760] Handle Uarte RX errors --- embassy-nrf/Cargo.toml | 1 + embassy-nrf/src/uarte.rs | 95 +++++++++++++++++++++++++++++++++++----- 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 10f268b51..580f0e3e6 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -133,6 +133,7 @@ embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } defmt = { version = "0.3", optional = true } +bitflags = "2.4.2" log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 95434e7a7..90d851139 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -52,6 +52,39 @@ impl Default for Config { } } +bitflags::bitflags! { + /// Error source flags + pub struct ErrorSource: u32 { + /// Buffer overrun + const OVERRUN = 0x01; + /// Parity error + const PARITY = 0x02; + /// Framing error + const FRAMING = 0x04; + /// Break condition + const BREAK = 0x08; + } +} + +impl TryFrom for () { + type Error = Error; + + #[inline] + fn try_from(errors: ErrorSource) -> Result { + if errors.contains(ErrorSource::OVERRUN) { + Err(Error::Overrun) + } else if errors.contains(ErrorSource::PARITY) { + Err(Error::Parity) + } else if errors.contains(ErrorSource::FRAMING) { + Err(Error::Framing) + } else if errors.contains(ErrorSource::BREAK) { + Err(Error::Break) + } else { + Ok(()) + } + } +} + /// UART error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -61,6 +94,14 @@ pub enum Error { BufferTooLong, /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. BufferNotInRAM, + /// Framing Error + Framing, + /// Parity Error + Parity, + /// Buffer Overrun + Overrun, + /// Break condition + Break, } /// Interrupt handler. @@ -73,9 +114,16 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - if r.events_endrx.read().bits() != 0 { + let endrx = r.events_endrx.read().bits(); + let error = r.events_error.read().bits(); + if endrx != 0 || error != 0 { s.endrx_waker.wake(); - r.intenclr.write(|w| w.endrx().clear()); + if endrx != 0 { + r.intenclr.write(|w| w.endrx().clear()); + } + if error != 0 { + r.intenclr.write(|w| w.error().clear()); + } } if r.events_endtx.read().bits() != 0 { s.endtx_waker.wake(); @@ -486,6 +534,13 @@ impl<'d, T: Instance> UarteRx<'d, T> { Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) } + fn read_and_clear_errors(&mut self) -> Result<(), Error> { + let r = T::regs(); + let err_bits = r.errorsrc.read().bits(); + r.errorsrc.write(|w| unsafe { w.bits(err_bits) }); + ErrorSource::from_bits_truncate(err_bits).try_into() + } + fn new_inner( uarte: impl Peripheral

+ 'd, rxd: PeripheralRef<'d, AnyPin>, @@ -572,7 +627,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { /// Read bytes until the buffer is filled. pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - if buffer.len() == 0 { + if buffer.is_empty() { return Ok(()); } if buffer.len() > EASY_DMA_SIZE { @@ -588,8 +643,13 @@ impl<'d, T: Instance> UarteRx<'d, T> { let drop = OnDrop::new(move || { trace!("read drop: stopping"); - r.intenclr.write(|w| w.endrx().clear()); + r.intenclr.write(|w| { + w.endrx().clear(); + w.error().clear() + }); r.events_rxto.reset(); + r.events_error.reset(); + r.errorsrc.reset(); r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); while r.events_endrx.read().bits() == 0 {} @@ -601,17 +661,26 @@ impl<'d, T: Instance> UarteRx<'d, T> { r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); r.events_endrx.reset(); - r.intenset.write(|w| w.endrx().set()); + r.events_error.reset(); + r.intenset.write(|w| { + w.endrx().set(); + w.error().set() + }); compiler_fence(Ordering::SeqCst); trace!("startrx"); r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - poll_fn(|cx| { + let result = poll_fn(|cx| { s.endrx_waker.register(cx.waker()); + + let maybe_err = self.read_and_clear_errors(); + if let Err(e) = maybe_err { + return Poll::Ready(Err(e)); + } if r.events_endrx.read().bits() != 0 { - return Poll::Ready(()); + return Poll::Ready(Ok(())); } Poll::Pending }) @@ -621,7 +690,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { r.events_rxstarted.reset(); drop.defuse(); - Ok(()) + result } /// Read bytes until the buffer is filled. @@ -642,19 +711,23 @@ impl<'d, T: Instance> UarteRx<'d, T> { r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); r.events_endrx.reset(); - r.intenclr.write(|w| w.endrx().clear()); + r.events_error.reset(); + r.intenclr.write(|w| { + w.endrx().clear(); + w.error().clear() + }); compiler_fence(Ordering::SeqCst); trace!("startrx"); r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - while r.events_endrx.read().bits() == 0 {} + while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {} compiler_fence(Ordering::SeqCst); r.events_rxstarted.reset(); - Ok(()) + self.read_and_clear_errors() } } From 1e698af05bc6e7e520d3f35ef661f34ea6ea359e Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 31 Jan 2024 14:04:48 -0500 Subject: [PATCH 341/760] Add timeout_at convenience function and example. --- embassy-time/src/lib.rs | 2 +- embassy-time/src/timer.rs | 15 ++++++- examples/rp/src/bin/debounce.rs | 80 +++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 examples/rp/src/bin/debounce.rs diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index d27eb92f6..e7efce49c 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -32,7 +32,7 @@ pub use delay::{block_for, Delay}; pub use duration::Duration; pub use embassy_time_driver::TICK_HZ; pub use instant::Instant; -pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; +pub use timer::{timeout_at, with_timeout, Ticker, TimeoutError, Timer}; const fn gcd(a: u64, b: u64) -> u64 { if b == 0 { diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 565a65cb8..dbce9297c 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -8,7 +8,7 @@ use futures_util::{pin_mut, Stream}; use crate::{Duration, Instant}; -/// Error returned by [`with_timeout`] on timeout. +/// Error returned by [`with_timeout`] and [`timeout_at`] on timeout. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct TimeoutError; @@ -26,6 +26,19 @@ pub async fn with_timeout(timeout: Duration, fut: F) -> Result(at: Instant, fut: F) -> Result { + let timeout_fut = Timer::at(at); + pin_mut!(fut); + match select(fut, timeout_fut).await { + Either::Left((r, _)) => Ok(r), + Either::Right(_) => Err(TimeoutError), + } +} + /// A future that completes at a specified [Instant](struct.Instant.html). #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Timer { diff --git a/examples/rp/src/bin/debounce.rs b/examples/rp/src/bin/debounce.rs new file mode 100644 index 000000000..bf1579091 --- /dev/null +++ b/examples/rp/src/bin/debounce.rs @@ -0,0 +1,80 @@ +//! This example shows the ease of debouncing a button with async rust. +//! Hook up a button or switch between pin 9 and ground. + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::gpio::{Input, Level, Pull}; +use embassy_time::{timeout_at, Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +pub struct Debouncer<'a> { + input: Input<'a>, + debounce: Duration, +} + +impl<'a> Debouncer<'a> { + pub fn new(input: Input<'a>, debounce: Duration) -> Self { + Self { input, debounce } + } + + pub async fn debounce(&mut self) -> Level { + loop { + let l1 = self.input.get_level(); + + self.input.wait_for_any_edge().await; + + Timer::after(self.debounce).await; + + let l2 = self.input.get_level(); + if l1 != l2 { + break l2; + } + } + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20)); + + info!("Debounce Demo"); + + loop { + // button pressed + btn.debounce().await; + let start = Instant::now(); + info!("Button Press"); + + match timeout_at(start + Duration::from_secs(1), btn.debounce()).await { + // Button Released < 1s + Ok(_) => { + info!("Button pressed for: {}ms", start.elapsed().as_millis()); + continue; + } + // button held for > 1s + Err(_) => { + info!("Button Held"); + } + } + + match timeout_at(start + Duration::from_secs(5), btn.debounce()).await { + // Button released <5s + Ok(_) => { + info!("Button pressed for: {}ms", start.elapsed().as_millis()); + continue; + } + // button held for > >5s + Err(_) => { + info!("Button Long Held"); + } + } + + // wait for button release before handling another press + btn.debounce().await; + info!("Button pressed for: {}ms", start.elapsed().as_millis()); + } +} From d364447a34377c708fe6a7ea87aabda3ea1231ba Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Wed, 31 Jan 2024 14:16:58 -0500 Subject: [PATCH 342/760] Add error handling to UarteRxWithIdle --- embassy-nrf/src/uarte.rs | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 90d851139..97c887ab2 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -534,7 +534,8 @@ impl<'d, T: Instance> UarteRx<'d, T> { Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) } - fn read_and_clear_errors(&mut self) -> Result<(), Error> { + /// Check for errors and clear the error register if an error occured. + fn check_and_clear_errors(&mut self) -> Result<(), Error> { let r = T::regs(); let err_bits = r.errorsrc.read().bits(); r.errorsrc.write(|w| unsafe { w.bits(err_bits) }); @@ -675,8 +676,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { let result = poll_fn(|cx| { s.endrx_waker.register(cx.waker()); - let maybe_err = self.read_and_clear_errors(); - if let Err(e) = maybe_err { + if let Err(e) = self.check_and_clear_errors() { return Poll::Ready(Err(e)); } if r.events_endrx.read().bits() != 0 { @@ -727,7 +727,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { compiler_fence(Ordering::SeqCst); r.events_rxstarted.reset(); - self.read_and_clear_errors() + self.check_and_clear_errors() } } @@ -794,8 +794,12 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { let drop = OnDrop::new(|| { self.timer.stop(); - r.intenclr.write(|w| w.endrx().clear()); + r.intenclr.write(|w| { + w.endrx().clear(); + w.error().clear() + }); r.events_rxto.reset(); + r.events_error.reset(); r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); while r.events_endrx.read().bits() == 0 {} @@ -805,17 +809,23 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); r.events_endrx.reset(); - r.intenset.write(|w| w.endrx().set()); + r.events_error.reset(); + r.intenset.write(|w| {w.endrx().set(); w.error().set()}); compiler_fence(Ordering::SeqCst); r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - poll_fn(|cx| { + let result = poll_fn(|cx| { s.endrx_waker.register(cx.waker()); - if r.events_endrx.read().bits() != 0 { - return Poll::Ready(()); + + if let Err(e) = self.rx.check_and_clear_errors() { + return Poll::Ready(Err(e)); } + if r.events_endrx.read().bits() != 0 { + return Poll::Ready(Ok(())); + } + Poll::Pending }) .await; @@ -828,7 +838,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { drop.defuse(); - Ok(n) + result.map(|_| n) } /// Read bytes until the buffer is filled, or the line becomes idle. @@ -853,13 +863,14 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); r.events_endrx.reset(); - r.intenclr.write(|w| w.endrx().clear()); + r.events_error.reset(); + r.intenclr.write(|w| {w.endrx().clear(); w.error().clear()}); compiler_fence(Ordering::SeqCst); r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - while r.events_endrx.read().bits() == 0 {} + while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {} compiler_fence(Ordering::SeqCst); let n = r.rxd.amount.read().amount().bits() as usize; @@ -867,7 +878,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { self.timer.stop(); r.events_rxstarted.reset(); - Ok(n) + self.rx.check_and_clear_errors().map(|_| n) } } From cc12eb9680513f380e9a04e76322ae4355c2b6b2 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Wed, 31 Jan 2024 14:20:06 -0500 Subject: [PATCH 343/760] Rustfmt --- embassy-nrf/src/uarte.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 97c887ab2..f29b5061b 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -676,7 +676,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { let result = poll_fn(|cx| { s.endrx_waker.register(cx.waker()); - if let Err(e) = self.check_and_clear_errors() { + if let Err(e) = self.check_and_clear_errors() { return Poll::Ready(Err(e)); } if r.events_endrx.read().bits() != 0 { @@ -810,7 +810,10 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { r.events_endrx.reset(); r.events_error.reset(); - r.intenset.write(|w| {w.endrx().set(); w.error().set()}); + r.intenset.write(|w| { + w.endrx().set(); + w.error().set() + }); compiler_fence(Ordering::SeqCst); @@ -864,7 +867,10 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { r.events_endrx.reset(); r.events_error.reset(); - r.intenclr.write(|w| {w.endrx().clear(); w.error().clear()}); + r.intenclr.write(|w| { + w.endrx().clear(); + w.error().clear() + }); compiler_fence(Ordering::SeqCst); From 8b7d85619537fc20ad7ad533433d84ba4975ddc4 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 31 Jan 2024 16:26:11 -0500 Subject: [PATCH 344/760] Rename timeout_at to with_deadline --- embassy-time/src/lib.rs | 2 +- embassy-time/src/timer.rs | 2 +- examples/rp/src/bin/debounce.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index e7efce49c..3c8575ee9 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -32,7 +32,7 @@ pub use delay::{block_for, Delay}; pub use duration::Duration; pub use embassy_time_driver::TICK_HZ; pub use instant::Instant; -pub use timer::{timeout_at, with_timeout, Ticker, TimeoutError, Timer}; +pub use timer::{with_deadline, with_timeout, Ticker, TimeoutError, Timer}; const fn gcd(a: u64, b: u64) -> u64 { if b == 0 { diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index dbce9297c..bcd6bf4f7 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -30,7 +30,7 @@ pub async fn with_timeout(timeout: Duration, fut: F) -> Result(at: Instant, fut: F) -> Result { +pub async fn with_deadline(at: Instant, fut: F) -> Result { let timeout_fut = Timer::at(at); pin_mut!(fut); match select(fut, timeout_fut).await { diff --git a/examples/rp/src/bin/debounce.rs b/examples/rp/src/bin/debounce.rs index bf1579091..0077f19fc 100644 --- a/examples/rp/src/bin/debounce.rs +++ b/examples/rp/src/bin/debounce.rs @@ -7,7 +7,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{Input, Level, Pull}; -use embassy_time::{timeout_at, Duration, Instant, Timer}; +use embassy_time::{with_deadline, Duration, Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; pub struct Debouncer<'a> { @@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) { let start = Instant::now(); info!("Button Press"); - match timeout_at(start + Duration::from_secs(1), btn.debounce()).await { + match with_deadline(start + Duration::from_secs(1), btn.debounce()).await { // Button Released < 1s Ok(_) => { info!("Button pressed for: {}ms", start.elapsed().as_millis()); @@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) { } } - match timeout_at(start + Duration::from_secs(5), btn.debounce()).await { + match with_deadline(start + Duration::from_secs(5), btn.debounce()).await { // Button released <5s Ok(_) => { info!("Button pressed for: {}ms", start.elapsed().as_millis()); From 0ab0b5590a0b07756ceaed9b26c78a6a821b34d5 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 31 Jan 2024 16:28:06 -0500 Subject: [PATCH 345/760] Fixup docs --- embassy-time/src/timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index bcd6bf4f7..daa4c1699 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -8,7 +8,7 @@ use futures_util::{pin_mut, Stream}; use crate::{Duration, Instant}; -/// Error returned by [`with_timeout`] and [`timeout_at`] on timeout. +/// Error returned by [`with_timeout`] and [`with_deadline`] on timeout. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct TimeoutError; From 42d8f3930a861dcc4540198bf2038151eb4e3e27 Mon Sep 17 00:00:00 2001 From: "Simon B. Gasse" Date: Fri, 19 Jan 2024 21:10:03 +0100 Subject: [PATCH 346/760] Implement MII interface - Extend the eth/v2 module to support MII besides RMII. - Replace `Ethernet::new` with `Ethernet::new_mii` and `Ethernet::new_rmii`. - Update ethernet examples. - Add example for MII ethernet. --- embassy-stm32/build.rs | 7 + embassy-stm32/src/eth/mod.rs | 7 + embassy-stm32/src/eth/v2/mod.rs | 136 ++++++++++++++++---- examples/stm32f4/src/bin/eth.rs | 2 +- examples/stm32f7/src/bin/eth.rs | 2 +- examples/stm32h5/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth_client.rs | 2 +- examples/stm32h7/src/bin/eth_client_mii.rs | 142 +++++++++++++++++++++ tests/stm32/src/bin/eth.rs | 21 +++ 10 files changed, 295 insertions(+), 28 deletions(-) create mode 100644 examples/stm32h7/src/bin/eth_client_mii.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 414723573..bd4195619 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -735,13 +735,20 @@ fn main() { (("can", "TX"), quote!(crate::can::TxPin)), (("can", "RX"), quote!(crate::can::RxPin)), (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), + (("eth", "RX_CLK"), quote!(crate::eth::RXClkPin)), + (("eth", "TX_CLK"), quote!(crate::eth::TXClkPin)), (("eth", "MDIO"), quote!(crate::eth::MDIOPin)), (("eth", "MDC"), quote!(crate::eth::MDCPin)), (("eth", "CRS_DV"), quote!(crate::eth::CRSPin)), + (("eth", "RX_DV"), quote!(crate::eth::RXDVPin)), (("eth", "RXD0"), quote!(crate::eth::RXD0Pin)), (("eth", "RXD1"), quote!(crate::eth::RXD1Pin)), + (("eth", "RXD2"), quote!(crate::eth::RXD2Pin)), + (("eth", "RXD3"), quote!(crate::eth::RXD3Pin)), (("eth", "TXD0"), quote!(crate::eth::TXD0Pin)), (("eth", "TXD1"), quote!(crate::eth::TXD1Pin)), + (("eth", "TXD2"), quote!(crate::eth::TXD2Pin)), + (("eth", "TXD3"), quote!(crate::eth::TXD3Pin)), (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)), (("fmc", "A0"), quote!(crate::fmc::A0Pin)), (("fmc", "A1"), quote!(crate::fmc::A1Pin)), diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 448405507..fbcdd7fae 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -192,12 +192,19 @@ impl sealed::Instance for crate::peripherals::ETH { } impl Instance for crate::peripherals::ETH {} +pin_trait!(RXClkPin, Instance); +pin_trait!(TXClkPin, Instance); pin_trait!(RefClkPin, Instance); pin_trait!(MDIOPin, Instance); pin_trait!(MDCPin, Instance); +pin_trait!(RXDVPin, Instance); pin_trait!(CRSPin, Instance); pin_trait!(RXD0Pin, Instance); pin_trait!(RXD1Pin, Instance); +pin_trait!(RXD2Pin, Instance); +pin_trait!(RXD3Pin, Instance); pin_trait!(TXD0Pin, Instance); pin_trait!(TXD1Pin, Instance); +pin_trait!(TXD2Pin, Instance); +pin_trait!(TXD3Pin, Instance); pin_trait!(TXEnPin, Instance); diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 59745cba0..a176b01e5 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -39,12 +39,18 @@ pub struct Ethernet<'d, T: Instance, P: PHY> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, pub(crate) rx: RDesRing<'d>, - pins: [PeripheralRef<'d, AnyPin>; 9], + pins: Pins<'d>, pub(crate) phy: P, pub(crate) station_management: EthernetStationManagement, pub(crate) mac_addr: [u8; 6], } +/// Pins of ethernet driver. +enum Pins<'d> { + Rmii([PeripheralRef<'d, AnyPin>; 9]), + Mii([PeripheralRef<'d, AnyPin>; 14]), +} + macro_rules! config_pins { ($($pin:ident),*) => { critical_section::with(|_| { @@ -57,11 +63,11 @@ macro_rules! config_pins { } impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { - /// Create a new Ethernet driver. - pub fn new( + /// Create a new RMII ethernet driver using 9 pins. + pub fn new_rmii( queue: &'d mut PacketQueue, peri: impl Peripheral

+ 'd, - _irq: impl interrupt::typelevel::Binding + 'd, + irq: impl interrupt::typelevel::Binding + 'd, ref_clk: impl Peripheral

> + 'd, mdio: impl Peripheral

> + 'd, mdc: impl Peripheral

> + 'd, @@ -74,8 +80,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { phy: P, mac_addr: [u8; 6], ) -> Self { - into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); - // Enable the necessary Clocks #[cfg(not(rcc_h5))] critical_section::with(|_| { @@ -85,7 +89,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_eth1rxen(true); }); - // RMII crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); }); @@ -99,14 +102,110 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_ethrxen(true); }); - // RMII crate::pac::SYSCFG .pmcr() .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); }); + into_ref!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); + let pins = Pins::Rmii([ + ref_clk.map_into(), + mdio.map_into(), + mdc.map_into(), + crs.map_into(), + rx_d0.map_into(), + rx_d1.map_into(), + tx_d0.map_into(), + tx_d1.map_into(), + tx_en.map_into(), + ]); + + Self::new_inner(queue, peri, irq, pins, phy, mac_addr) + } + + /// Create a new MII ethernet driver using 14 pins. + pub fn new_mii( + queue: &'d mut PacketQueue, + peri: impl Peripheral

+ 'd, + irq: impl interrupt::typelevel::Binding + 'd, + rx_clk: impl Peripheral

> + 'd, + tx_clk: impl Peripheral

> + 'd, + mdio: impl Peripheral

> + 'd, + mdc: impl Peripheral

> + 'd, + rxdv: impl Peripheral

> + 'd, + rx_d0: impl Peripheral

> + 'd, + rx_d1: impl Peripheral

> + 'd, + rx_d2: impl Peripheral

> + 'd, + rx_d3: impl Peripheral

> + 'd, + tx_d0: impl Peripheral

> + 'd, + tx_d1: impl Peripheral

> + 'd, + tx_d2: impl Peripheral

> + 'd, + tx_d3: impl Peripheral

> + 'd, + tx_en: impl Peripheral

> + 'd, + phy: P, + mac_addr: [u8; 6], + ) -> Self { + // Enable necessary clocks. + #[cfg(not(rcc_h5))] + critical_section::with(|_| { + crate::pac::RCC.ahb1enr().modify(|w| { + w.set_eth1macen(true); + w.set_eth1txen(true); + w.set_eth1rxen(true); + }); + + crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b000)); + }); + + #[cfg(rcc_h5)] + critical_section::with(|_| { + crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true)); + + crate::pac::RCC.ahb1enr().modify(|w| { + w.set_ethen(true); + w.set_ethtxen(true); + w.set_ethrxen(true); + }); + + // TODO: This is for RMII - what would MII need here? + crate::pac::SYSCFG + .pmcr() + .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); + }); + + into_ref!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); + config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); + + let pins = Pins::Mii([ + rx_clk.map_into(), + tx_clk.map_into(), + mdio.map_into(), + mdc.map_into(), + rxdv.map_into(), + rx_d0.map_into(), + rx_d1.map_into(), + rx_d2.map_into(), + rx_d3.map_into(), + tx_d0.map_into(), + tx_d1.map_into(), + tx_d2.map_into(), + tx_d3.map_into(), + tx_en.map_into(), + ]); + + Self::new_inner(queue, peri, irq, pins, phy, mac_addr) + } + + fn new_inner( + queue: &'d mut PacketQueue, + peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding + 'd, + pins: Pins<'d>, + phy: P, + mac_addr: [u8; 6], + ) -> Self { let dma = ETH.ethernet_dma(); let mac = ETH.ethernet_mac(); let mtl = ETH.ethernet_mtl(); @@ -182,24 +281,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { } }; - let pins = [ - ref_clk.map_into(), - mdio.map_into(), - mdc.map_into(), - crs.map_into(), - rx_d0.map_into(), - rx_d1.map_into(), - tx_d0.map_into(), - tx_d1.map_into(), - tx_en.map_into(), - ]; - let mut this = Self { - _peri: peri, + _peri: peri.into_ref(), tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), pins, - phy: phy, + phy, station_management: EthernetStationManagement { peri: PhantomData, clock_range: clock_range, @@ -302,7 +389,10 @@ impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { dma.dmacrx_cr().modify(|w| w.set_sr(false)); critical_section::with(|_| { - for pin in self.pins.iter_mut() { + for pin in match self.pins { + Pins::Rmii(ref mut pins) => pins.iter_mut(), + Pins::Mii(ref mut pins) => pins.iter_mut(), + } { pin.set_as_disconnected(); } }) diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 7f5c8fdb1..2933cfe3c 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -63,7 +63,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new( + let device = Ethernet::new_rmii( PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 5bff48197..85b5bd3e0 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -64,7 +64,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new( + let device = Ethernet::new_rmii( PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 2370656e6..79288877f 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -67,7 +67,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new( + let device = Ethernet::new_rmii( PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index cd9a27fcd..9abdcf3c0 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -64,7 +64,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new( + let device = Ethernet::new_rmii( PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index dcc6e36e2..c4da5776f 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -65,7 +65,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new( + let device = Ethernet::new_rmii( PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs new file mode 100644 index 000000000..de6ea522a --- /dev/null +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -0,0 +1,142 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_net::tcp::client::{TcpClient, TcpClientState}; +use embassy_net::{Stack, StackResources}; +use embassy_stm32::eth::generic_smi::GenericSMI; +use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::peripherals::ETH; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_time::Timer; +use embedded_io_async::Write; +use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; +use rand_core::RngCore; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; + RNG => rng::InterruptHandler; +}); + +type Device = Ethernet<'static, ETH, GenericSMI>; + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack) -> ! { + stack.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) -> ! { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.hsi48 = Some(Default::default()); // needed for RNG + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } + let p = embassy_stm32::init(config); + info!("Hello World!"); + + // Generate random seed. + let mut rng = Rng::new(p.RNG, Irqs); + let mut seed = [0; 8]; + rng.fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + + static PACKETS: StaticCell> = StaticCell::new(); + + let device = Ethernet::new_mii( + PACKETS.init(PacketQueue::<16, 16>::new()), + p.ETH, + Irqs, + p.PA1, + p.PC3, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PB0, + p.PB1, + p.PG13, + p.PG12, + p.PC2, + p.PE2, + p.PG11, + GenericSMI::new(1), + mac_addr, + ); + info!("Device created"); + + let config = embassy_net::Config::dhcpv4(Default::default()); + //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { + // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), + // dns_servers: Vec::new(), + // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), + //}); + + // Init network stack + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( + device, + config, + RESOURCES.init(StackResources::<3>::new()), + seed, + )); + + // Launch network task + unwrap!(spawner.spawn(net_task(stack))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; + + info!("Network task initialized"); + + let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); + let client = TcpClient::new(&stack, &state); + + loop { + // You need to start a server on the host machine, for example: `nc -l 8000` + let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 100, 1), 8000)); + + info!("connecting..."); + let r = client.connect(addr).await; + if let Err(e) = r { + info!("connect error: {:?}", e); + Timer::after_secs(1).await; + continue; + } + let mut connection = r.unwrap(); + info!("connected!"); + loop { + let r = connection.write_all(b"Hello\n").await; + if let Err(e) = r { + info!("write error: {:?}", e); + break; + } + Timer::after_secs(1).await; + } + } +} diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index 7c02f0354..b244874e7 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -71,6 +71,7 @@ async fn main(spawner: Spawner) { const PACKET_QUEUE_SIZE: usize = 4; static PACKETS: StaticCell> = StaticCell::new(); + #[cfg(not(eth_v2))] let device = Ethernet::new( PACKETS.init(PacketQueue::::new()), p.ETH, @@ -90,6 +91,26 @@ async fn main(spawner: Spawner) { GenericSMI::new(0), mac_addr, ); + #[cfg(eth_v2)] + let device = Ethernet::new_rmii( + PACKETS.init(PacketQueue::::new()), + p.ETH, + Irqs, + p.PA1, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PG13, + #[cfg(not(feature = "stm32h563zi"))] + p.PB13, + #[cfg(feature = "stm32h563zi")] + p.PB15, + p.PG11, + GenericSMI::new(0), + mac_addr, + ); let config = embassy_net::Config::dhcpv4(Default::default()); //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { From e613324e1603741df150730fd26652458d0d0c50 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 1 Feb 2024 01:39:52 +0100 Subject: [PATCH 347/760] stm32/eth: rename new_rmii to new, update metapac to fix issues with PC2_C. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/eth/v2/mod.rs | 2 +- examples/stm32f4/src/bin/eth.rs | 2 +- examples/stm32f7/src/bin/eth.rs | 2 +- examples/stm32h5/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth_client.rs | 3 ++- tests/stm32/src/bin/eth.rs | 21 --------------------- 8 files changed, 9 insertions(+), 29 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6c7591f57..698febf71 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-ab2bc2a739324793656ca1640e1caee2d88df72d" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-ab2bc2a739324793656ca1640e1caee2d88df72d", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index a176b01e5..4b22d1d21 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -64,7 +64,7 @@ macro_rules! config_pins { impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { /// Create a new RMII ethernet driver using 9 pins. - pub fn new_rmii( + pub fn new( queue: &'d mut PacketQueue, peri: impl Peripheral

+ 'd, irq: impl interrupt::typelevel::Binding + 'd, diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 2933cfe3c..7f5c8fdb1 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -63,7 +63,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new_rmii( + let device = Ethernet::new( PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 85b5bd3e0..5bff48197 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -64,7 +64,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new_rmii( + let device = Ethernet::new( PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 79288877f..2370656e6 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -67,7 +67,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new_rmii( + let device = Ethernet::new( PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 9abdcf3c0..cd9a27fcd 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -64,7 +64,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new_rmii( + let device = Ethernet::new( PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index c4da5776f..aeb169e19 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -65,7 +65,8 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); - let device = Ethernet::new_rmii( + + let device = Ethernet::new( PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, Irqs, diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index b244874e7..7c02f0354 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -71,7 +71,6 @@ async fn main(spawner: Spawner) { const PACKET_QUEUE_SIZE: usize = 4; static PACKETS: StaticCell> = StaticCell::new(); - #[cfg(not(eth_v2))] let device = Ethernet::new( PACKETS.init(PacketQueue::::new()), p.ETH, @@ -91,26 +90,6 @@ async fn main(spawner: Spawner) { GenericSMI::new(0), mac_addr, ); - #[cfg(eth_v2)] - let device = Ethernet::new_rmii( - PACKETS.init(PacketQueue::::new()), - p.ETH, - Irqs, - p.PA1, - p.PA2, - p.PC1, - p.PA7, - p.PC4, - p.PC5, - p.PG13, - #[cfg(not(feature = "stm32h563zi"))] - p.PB13, - #[cfg(feature = "stm32h563zi")] - p.PB15, - p.PG11, - GenericSMI::new(0), - mac_addr, - ); let config = embassy_net::Config::dhcpv4(Default::default()); //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { From 6e9ddd46267fd0fce2333af4f15bfd86f6f17f4d Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Wed, 31 Jan 2024 21:21:36 -0500 Subject: [PATCH 348/760] Added hash module with blocking implementation. Included SHA256 example. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/hash/mod.rs | 260 +++++++++++++++++++++++++++++++ embassy-stm32/src/lib.rs | 2 + examples/stm32f7/Cargo.toml | 5 +- examples/stm32f7/src/bin/hash.rs | 49 ++++++ 5 files changed, 316 insertions(+), 4 deletions(-) create mode 100644 embassy-stm32/src/hash/mod.rs create mode 100644 examples/stm32f7/src/bin/hash.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 70d4daf09..d8a4c65fa 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-ab2bc2a739324793656ca1640e1caee2d88df72d" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -87,7 +87,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-ab2bc2a739324793656ca1640e1caee2d88df72d", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs new file mode 100644 index 000000000..e3d2d7b16 --- /dev/null +++ b/embassy-stm32/src/hash/mod.rs @@ -0,0 +1,260 @@ +//! Hash generator (HASH) +use core::cmp::min; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +use stm32_metapac::hash::regs::*; + +use crate::pac::HASH as PAC_HASH; +use crate::peripherals::HASH; +use crate::rcc::sealed::RccPeripheral; +use crate::Peripheral; + +const NUM_CONTEXT_REGS: usize = 54; +const HASH_BUFFER_LEN: usize = 68; +const DIGEST_BLOCK_SIZE: usize = 64; + +///Hash algorithm selection +#[derive(PartialEq)] +pub enum Algorithm { + /// SHA-1 Algorithm + SHA1 = 0, + /// MD5 Algorithm + MD5 = 1, + /// SHA-224 Algorithm + SHA224 = 2, + /// SHA-256 Algorithm + SHA256 = 3, +} + +/// Input data width selection +#[repr(u8)] +#[derive(Clone, Copy)] +pub enum DataType { + ///32-bit data, no data is swapped. + Width32 = 0, + ///16-bit data, each half-word is swapped. + Width16 = 1, + ///8-bit data, all bytes are swapped. + Width8 = 2, + ///1-bit data, all bits are swapped. + Width1 = 3, +} + +/// Stores the state of the HASH peripheral for suspending/resuming +/// digest calculation. +pub struct Context { + first_word_sent: bool, + buffer: [u8; HASH_BUFFER_LEN], + buflen: usize, + algo: Algorithm, + format: DataType, + imr: u32, + str: u32, + cr: u32, + csr: [u32; NUM_CONTEXT_REGS], +} + +/// HASH driver. +pub struct Hash<'d> { + _peripheral: PeripheralRef<'d, HASH>, +} + +impl<'d> Hash<'d> { + /// Instantiates, resets, and enables the HASH peripheral. + pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { + HASH::enable_and_reset(); + into_ref!(peripheral); + let instance = Self { + _peripheral: peripheral, + }; + instance + } + + /// Starts computation of a new hash and returns the saved peripheral state. + pub fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { + // Define a context for this new computation. + let mut ctx = Context { + first_word_sent: false, + buffer: [0; 68], + buflen: 0, + algo: algorithm, + format: format, + imr: 0, + str: 0, + cr: 0, + csr: [0; NUM_CONTEXT_REGS], + }; + + // Set the data type in the peripheral. + PAC_HASH.cr().modify(|w| w.set_datatype(ctx.format as u8)); + + // Select the algorithm. + let mut algo0 = false; + let mut algo1 = false; + if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 { + algo0 = true; + } + if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { + algo1 = true; + } + PAC_HASH.cr().modify(|w| w.set_algo0(algo0)); + PAC_HASH.cr().modify(|w| w.set_algo1(algo1)); + PAC_HASH.cr().modify(|w| w.set_init(true)); + + // Store and return the state of the peripheral. + self.store_context(&mut ctx); + ctx + } + + /// Restores the peripheral state using the given context, + /// then updates the state with the provided data. + pub fn update(&mut self, ctx: &mut Context, input: &[u8]) { + let mut data_waiting = input.len() + ctx.buflen; + if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) { + // There isn't enough data to digest a block, so append it to the buffer. + ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); + ctx.buflen += input.len(); + return; + } + + //Restore the peripheral state. + self.load_context(&ctx); + + let mut ilen_remaining = input.len(); + let mut input_start = 0; + + // Handle first block. + if !ctx.first_word_sent { + let empty_len = ctx.buffer.len() - ctx.buflen; + let copy_len = min(empty_len, ilen_remaining); + // Fill the buffer. + if copy_len > 0 { + ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[0..copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; + } + assert_eq!(ctx.buflen, HASH_BUFFER_LEN); + self.accumulate(ctx.buffer.as_slice()); + data_waiting -= ctx.buflen; + ctx.buflen = 0; + ctx.first_word_sent = true; + } + + if data_waiting < 64 { + // There isn't enough data remaining to process another block, so store it. + assert_eq!(ctx.buflen, 0); + ctx.buffer[0..ilen_remaining].copy_from_slice(&input[input_start..input_start + ilen_remaining]); + ctx.buflen += ilen_remaining; + } else { + let mut total_data_sent = 0; + // First ingest the data in the buffer. + let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; + if empty_len > 0 { + let copy_len = min(empty_len, ilen_remaining); + ctx.buffer[ctx.buflen..ctx.buflen + copy_len] + .copy_from_slice(&input[input_start..input_start + copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; + } + assert_eq!(ctx.buflen % 64, 0); + self.accumulate(&ctx.buffer[0..64]); + total_data_sent += ctx.buflen; + ctx.buflen = 0; + + // Move any extra data to the now-empty buffer. + let leftovers = ilen_remaining % 64; + if leftovers > 0 { + assert!(ilen_remaining >= leftovers); + ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); + ctx.buflen += leftovers; + ilen_remaining -= leftovers; + } + assert_eq!(ilen_remaining % 64, 0); + + // Hash the remaining data. + self.accumulate(&input[input_start..input_start + ilen_remaining]); + + total_data_sent += ilen_remaining; + assert_eq!(total_data_sent % 64, 0); + assert!(total_data_sent >= 64); + } + + // Save the peripheral context. + self.store_context(ctx); + } + + /// Computes a digest for the given context. A slice of the provided digest buffer is returned. + /// The length of the returned slice is dependent on the digest length of the selected algorithm. + pub fn finish<'a>(&mut self, mut ctx: Context, digest: &'a mut [u8; 32]) -> &'a [u8] { + // Restore the peripheral state. + self.load_context(&ctx); + // Hash the leftover bytes, if any. + self.accumulate(&ctx.buffer[0..ctx.buflen]); + ctx.buflen = 0; + + //Start the digest calculation. + PAC_HASH.str().write(|w| w.set_dcal(true)); + + //Wait for completion. + while !PAC_HASH.sr().read().dcis() {} + + //Return the digest. + let digest_words = match ctx.algo { + Algorithm::SHA1 => 5, + Algorithm::MD5 => 4, + Algorithm::SHA224 => 7, + Algorithm::SHA256 => 8, + }; + let mut i = 0; + while i < digest_words { + let word = PAC_HASH.hr(i).read(); + digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); + i += 1; + } + &digest[0..digest_words * 4] + } + + fn accumulate(&mut self, input: &[u8]) { + //Set the number of valid bits. + let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; + PAC_HASH.str().modify(|w| w.set_nblw(num_valid_bits)); + + let mut i = 0; + while i < input.len() { + let mut word: [u8; 4] = [0; 4]; + let copy_idx = min(i + 4, input.len()); + word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); + PAC_HASH.din().write_value(u32::from_ne_bytes(word)); + i += 4; + } + } + + /// Save the peripheral state to a context. + fn store_context(&mut self, ctx: &mut Context) { + while !PAC_HASH.sr().read().dinis() {} + ctx.imr = PAC_HASH.imr().read().0; + ctx.str = PAC_HASH.str().read().0; + ctx.cr = PAC_HASH.cr().read().0; + let mut i = 0; + while i < NUM_CONTEXT_REGS { + ctx.csr[i] = PAC_HASH.csr(i).read(); + i += 1; + } + } + + /// Restore the peripheral state from a context. + fn load_context(&mut self, ctx: &Context) { + // Restore the peripheral state from the context. + PAC_HASH.imr().write_value(Imr { 0: ctx.imr }); + PAC_HASH.str().write_value(Str { 0: ctx.str }); + PAC_HASH.cr().write_value(Cr { 0: ctx.cr }); + PAC_HASH.cr().modify(|w| w.set_init(true)); + let mut i = 0; + while i < NUM_CONTEXT_REGS { + PAC_HASH.csr(i).write_value(ctx.csr[i]); + i += 1; + } + } +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index a465fccd8..cd1ede0fa 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -45,6 +45,8 @@ pub mod exti; pub mod flash; #[cfg(fmc)] pub mod fmc; +#[cfg(hash)] +pub mod hash; #[cfg(hrtim)] pub mod hrtim; #[cfg(i2c)] diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 941ba38cd..a612c2554 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -# Change stm32f767zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } +# Change stm32f777zi to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "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"] } @@ -28,6 +28,7 @@ rand_core = "0.6.3" critical-section = "1.1" embedded-storage = "0.3.1" static_cell = "2" +sha2 = { version = "0.10.8", default-features = false } [profile.release] debug = 2 diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs new file mode 100644 index 000000000..1fd0e87eb --- /dev/null +++ b/examples/stm32f7/src/bin/hash.rs @@ -0,0 +1,49 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::Config; +use embassy_time::{Duration, Instant}; +use {defmt_rtt as _, panic_probe as _}; + +use embassy_stm32::hash::*; +use sha2::{Digest, Sha256}; + +const TEST_STRING_1: &[u8] = b"hello world"; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let config = Config::default(); + let p = embassy_stm32::init(config); + + let hw_start_time = Instant::now(); + + // Compute a digest in hardware. + let mut hw_hasher = Hash::new(p.HASH); + let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); + hw_hasher.update(&mut context, TEST_STRING_1); + let mut buffer: [u8; 32] = [0; 32]; + let hw_digest = hw_hasher.finish(context, &mut buffer); + + let hw_end_time = Instant::now(); + let hw_execution_time = hw_end_time - hw_start_time; + + let sw_start_time = Instant::now(); + + // Compute a digest in software. + let mut sw_hasher = Sha256::new(); + sw_hasher.update(TEST_STRING_1); + let sw_digest = sw_hasher.finalize(); + + let sw_end_time = Instant::now(); + let sw_execution_time = sw_end_time - sw_start_time; + + info!("Hardware Digest: {:?}", hw_digest); + info!("Software Digest: {:?}", sw_digest[..]); + info!("Hardware Execution Time: {:?}", hw_execution_time); + info!("Software Execution Time: {:?}", sw_execution_time); + assert_eq!(*hw_digest, sw_digest[..]); + + loop {} +} From 15e9b60abbceb8843781b6eec398dafb45cc111d Mon Sep 17 00:00:00 2001 From: Sam Lakerveld Date: Thu, 1 Feb 2024 13:47:07 +0100 Subject: [PATCH 349/760] sync/pipe: be able to be zero-initialized --- embassy-sync/src/ring_buffer.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/embassy-sync/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs index d95ffa7c9..81e60c42b 100644 --- a/embassy-sync/src/ring_buffer.rs +++ b/embassy-sync/src/ring_buffer.rs @@ -3,7 +3,7 @@ use core::ops::Range; pub struct RingBuffer { start: usize, end: usize, - empty: bool, + full: bool, } impl RingBuffer { @@ -11,13 +11,13 @@ impl RingBuffer { Self { start: 0, end: 0, - empty: true, + full: false, } } pub fn push_buf(&mut self) -> Range { - if self.start == self.end && !self.empty { - trace!(" ringbuf: push_buf empty"); + if self.is_full() { + trace!(" ringbuf: push_buf full"); return 0..0; } @@ -38,11 +38,11 @@ impl RingBuffer { } self.end = self.wrap(self.end + n); - self.empty = false; + self.full = self.start == self.end; } pub fn pop_buf(&mut self) -> Range { - if self.empty { + if self.is_empty() { trace!(" ringbuf: pop_buf empty"); return 0..0; } @@ -64,20 +64,20 @@ impl RingBuffer { } self.start = self.wrap(self.start + n); - self.empty = self.start == self.end; + self.full = false; } pub fn is_full(&self) -> bool { - self.start == self.end && !self.empty + self.full } pub fn is_empty(&self) -> bool { - self.empty + self.start == self.end && !self.full } #[allow(unused)] pub fn len(&self) -> usize { - if self.empty { + if self.is_empty() { 0 } else if self.start < self.end { self.end - self.start @@ -89,7 +89,7 @@ impl RingBuffer { pub fn clear(&mut self) { self.start = 0; self.end = 0; - self.empty = true; + self.full = false; } fn wrap(&self, n: usize) -> usize { From 1dbfa5ab72e3596932ccb6bd258fac70d2efa563 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:28:12 -0500 Subject: [PATCH 350/760] Added hash v1/v2 configs. --- embassy-stm32/src/hash/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index e3d2d7b16..622777b02 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -9,7 +9,11 @@ use crate::peripherals::HASH; use crate::rcc::sealed::RccPeripheral; use crate::Peripheral; +#[cfg(hash_v1)] +const NUM_CONTEXT_REGS: usize = 51; +#[cfg(hash_v2)] const NUM_CONTEXT_REGS: usize = 54; + const HASH_BUFFER_LEN: usize = 68; const DIGEST_BLOCK_SIZE: usize = 64; @@ -20,8 +24,10 @@ pub enum Algorithm { SHA1 = 0, /// MD5 Algorithm MD5 = 1, + #[cfg(hash_v2)] /// SHA-224 Algorithm SHA224 = 2, + #[cfg(hash_v2)] /// SHA-256 Algorithm SHA256 = 3, } From 72ca5a022b44fe621fbae52a33ac7e45b9cc66a2 Mon Sep 17 00:00:00 2001 From: Taylor Carpenter Date: Thu, 1 Feb 2024 10:41:41 -0500 Subject: [PATCH 351/760] Add scatter memory files for extended BLE stack Build script chooses the 'x.in' to copy over to 'tl_mbox.x' based on features --- embassy-stm32-wpan/Cargo.toml | 2 ++ embassy-stm32-wpan/build.rs | 17 +++++++++++++++-- embassy-stm32-wpan/tl_mbox_extended_wb1.x.in | 16 ++++++++++++++++ embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in | 16 ++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 embassy-stm32-wpan/tl_mbox_extended_wb1.x.in create mode 100644 embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 4f53a400a..360ca5f4b 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -44,6 +44,8 @@ defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embas ble = ["dep:stm32wb-hci"] mac = ["dep:bitflags", "dep:embassy-net-driver" ] +extended = [] + stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ] diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs index 94aac070d..7ab458bf2 100644 --- a/embassy-stm32-wpan/build.rs +++ b/embassy-stm32-wpan/build.rs @@ -18,9 +18,22 @@ fn main() { // stm32wb tl_mbox link sections let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string(); - fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap(); + let in_file; + if env::var_os("CARGO_FEATURE_EXTENDED").is_some() { + if env::vars() + .map(|(a, _)| a) + .any(|x| x.starts_with("CARGO_FEATURE_STM32WB1")) + { + in_file = "tl_mbox_extended_wb1.x.in"; + } else { + in_file = "tl_mbox_extended_wbx5.x.in"; + } + } else { + in_file = "tl_mbox.x.in"; + } + fs::write(out_file, fs::read_to_string(in_file).unwrap()).unwrap(); println!("cargo:rustc-link-search={}", out_dir.display()); - println!("cargo:rerun-if-changed=tl_mbox.x.in"); + println!("cargo:rerun-if-changed={}", in_file); } enum GetOneError { diff --git a/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in b/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in new file mode 100644 index 000000000..4cffdaddd --- /dev/null +++ b/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in @@ -0,0 +1,16 @@ +MEMORY +{ + RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 4K + RAMB_SHARED (xrw) : ORIGIN = 0x20030028, LENGTH = 4K +} + +/* + * Scatter the mailbox interface memory sections in shared memory + */ +SECTIONS +{ + TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED + + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAMB_SHARED + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAMB_SHARED +} diff --git a/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in b/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in new file mode 100644 index 000000000..281d637a9 --- /dev/null +++ b/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in @@ -0,0 +1,16 @@ +MEMORY +{ + RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 2K + RAMB_SHARED (xrw) : ORIGIN = 0x20038000, LENGTH = 10K +} + +/* + * Scatter the mailbox interface memory sections in shared memory + */ +SECTIONS +{ + TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED + + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAMB_SHARED + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAMB_SHARED +} From aa767272a87bddc9ac7fbce3962989342390d689 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 1 Feb 2024 13:39:14 -0500 Subject: [PATCH 352/760] STM32WBA's high speed external clock has to run at 32 MHz --- embassy-stm32/src/rcc/wba.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index c0cd91507..1d04d480a 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -6,26 +6,28 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(16_000_000); +// HSE speed +pub const HSE_FREQ: Hertz = Hertz(32_000_000); pub use crate::pac::pwr::vals::Vos as VoltageScale; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; #[derive(Copy, Clone)] pub enum ClockSrc { - HSE(Hertz), + HSE, HSI, } #[derive(Clone, Copy, Debug)] pub enum PllSource { - HSE(Hertz), + HSE, HSI, } impl Into for PllSource { fn into(self) -> Pllsrc { match self { - PllSource::HSE(..) => Pllsrc::HSE, + PllSource::HSE => Pllsrc::HSE, PllSource::HSI => Pllsrc::HSI, } } @@ -34,7 +36,7 @@ impl Into for PllSource { impl Into for ClockSrc { fn into(self) -> Sw { match self { - ClockSrc::HSE(..) => Sw::HSE, + ClockSrc::HSE => Sw::HSE, ClockSrc::HSI => Sw::HSI, } } @@ -64,11 +66,11 @@ impl Default for Config { pub(crate) unsafe fn init(config: Config) { let sys_clk = match config.mux { - ClockSrc::HSE(freq) => { + ClockSrc::HSE => { RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - freq + HSE_FREQ } ClockSrc::HSI => { RCC.cr().write(|w| w.set_hsion(true)); From 21024e863820d4a3ddb9e72041251c72d10ee5a6 Mon Sep 17 00:00:00 2001 From: Joonas Javanainen Date: Thu, 1 Feb 2024 21:48:29 +0200 Subject: [PATCH 353/760] Fix F2 temperature sensor ADC channel On all F2 devices (F205/207/215/217) the sensor is connected to ADC1_IN16, and is not shared with VBAT which is connected to ADC1_IN18. --- embassy-stm32/src/adc/v2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 4622b40a9..036a4ec37 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -34,7 +34,7 @@ impl AdcPin for Temperature {} impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { cfg_if::cfg_if! { - if #[cfg(any(stm32f40, stm32f41))] { + if #[cfg(any(stm32f2, stm32f40, stm32f41))] { 16 } else { 18 From 7e0f287431f7e5bdfc562164bf67afb214ac4700 Mon Sep 17 00:00:00 2001 From: Joonas Javanainen Date: Thu, 1 Feb 2024 21:58:36 +0200 Subject: [PATCH 354/760] Fix ADC max frequency for F2 --- embassy-stm32/src/adc/v2.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 036a4ec37..b37ac5a5d 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -67,7 +67,11 @@ enum Prescaler { impl Prescaler { fn from_pclk2(freq: Hertz) -> Self { + // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). + #[cfg(stm32f2)] + const MAX_FREQUENCY: Hertz = Hertz(30_000_000); // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. + #[cfg(not(stm32f2))] const MAX_FREQUENCY: Hertz = Hertz(36_000_000); let raw_div = freq.0 / MAX_FREQUENCY.0; match raw_div { From e7d1119750dff876e76adbb04f57ac274e913772 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 1 Feb 2024 23:15:17 +0100 Subject: [PATCH 355/760] stm32: automatically use refcounting for rcc bits used multiple times. --- embassy-stm32/build.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 69848762a..74cc3f8b9 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -449,7 +449,16 @@ fn main() { // ======== // Generate RccPeripheral impls - let refcounted_peripherals = HashSet::from(["usart", "adc", "can"]); + // count how many times each xxENR field is used, to enable refcounting if used more than once. + let mut rcc_field_count: HashMap<_, usize> = HashMap::new(); + for p in METADATA.peripherals { + if let Some(rcc) = &p.rcc { + let en = rcc.enable.as_ref().unwrap(); + *rcc_field_count.entry((en.register, en.field)).or_insert(0) += 1; + } + } + + let force_refcount = HashSet::from(["usart"]); let mut refcount_statics = BTreeSet::new(); for p in METADATA.peripherals { @@ -487,7 +496,9 @@ fn main() { let en_reg = format_ident!("{}", en.register); let set_en_field = format_ident!("set_{}", en.field); - let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) { + let refcount = + force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; + let (before_enable, before_disable) = if refcount { let refcount_static = format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); From 10275309021d933d5dfe4c0a96928432e11cd8b4 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:27:25 -0500 Subject: [PATCH 356/760] Added hash interrupts for async. --- embassy-stm32/src/hash/mod.rs | 171 ++++++++++++++++++++++++++-------- 1 file changed, 134 insertions(+), 37 deletions(-) diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 622777b02..4e37e60e1 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -1,22 +1,47 @@ //! Hash generator (HASH) use core::cmp::min; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::peripherals::HASH; use stm32_metapac::hash::regs::*; -use crate::pac::HASH as PAC_HASH; -use crate::peripherals::HASH; +use crate::interrupt::typelevel::Interrupt; use crate::rcc::sealed::RccPeripheral; -use crate::Peripheral; +use crate::{interrupt, pac, peripherals, Peripheral}; #[cfg(hash_v1)] const NUM_CONTEXT_REGS: usize = 51; #[cfg(hash_v2)] const NUM_CONTEXT_REGS: usize = 54; - const HASH_BUFFER_LEN: usize = 68; const DIGEST_BLOCK_SIZE: usize = 64; +static HASH_WAKER: AtomicWaker = AtomicWaker::new(); + +/// HASH interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let bits = T::regs().sr().read(); + if bits.dinis() { + T::regs().imr().modify(|reg| reg.set_dinie(false)); + HASH_WAKER.wake(); + } + if bits.dcis() { + T::regs().imr().modify(|reg| reg.set_dcie(false)); + HASH_WAKER.wake(); + } + } +} + ///Hash algorithm selection #[derive(PartialEq)] pub enum Algorithm { @@ -61,23 +86,27 @@ pub struct Context { } /// HASH driver. -pub struct Hash<'d> { - _peripheral: PeripheralRef<'d, HASH>, +pub struct Hash<'d, T: Instance> { + _peripheral: PeripheralRef<'d, T>, } -impl<'d> Hash<'d> { +impl<'d, T: Instance> Hash<'d, T> { /// Instantiates, resets, and enables the HASH peripheral. - pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { + pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { HASH::enable_and_reset(); into_ref!(peripheral); let instance = Self { _peripheral: peripheral, }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + instance } /// Starts computation of a new hash and returns the saved peripheral state. - pub fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { + pub async fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { // Define a context for this new computation. let mut ctx = Context { first_word_sent: false, @@ -92,7 +121,7 @@ impl<'d> Hash<'d> { }; // Set the data type in the peripheral. - PAC_HASH.cr().modify(|w| w.set_datatype(ctx.format as u8)); + T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); // Select the algorithm. let mut algo0 = false; @@ -103,18 +132,19 @@ impl<'d> Hash<'d> { if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { algo1 = true; } - PAC_HASH.cr().modify(|w| w.set_algo0(algo0)); - PAC_HASH.cr().modify(|w| w.set_algo1(algo1)); - PAC_HASH.cr().modify(|w| w.set_init(true)); + T::regs().cr().modify(|w| w.set_algo0(algo0)); + T::regs().cr().modify(|w| w.set_algo1(algo1)); + T::regs().cr().modify(|w| w.set_init(true)); // Store and return the state of the peripheral. - self.store_context(&mut ctx); + self.store_context(&mut ctx).await; ctx } /// Restores the peripheral state using the given context, /// then updates the state with the provided data. - pub fn update(&mut self, ctx: &mut Context, input: &[u8]) { + /// Peripheral state is saved upon return. + pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) { let mut data_waiting = input.len() + ctx.buflen; if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) { // There isn't enough data to digest a block, so append it to the buffer. @@ -123,7 +153,7 @@ impl<'d> Hash<'d> { return; } - //Restore the peripheral state. + // Restore the peripheral state. self.load_context(&ctx); let mut ilen_remaining = input.len(); @@ -154,6 +184,7 @@ impl<'d> Hash<'d> { ctx.buflen += ilen_remaining; } else { let mut total_data_sent = 0; + // First ingest the data in the buffer. let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; if empty_len > 0 { @@ -188,25 +219,43 @@ impl<'d> Hash<'d> { } // Save the peripheral context. - self.store_context(ctx); + self.store_context(ctx).await; } /// Computes a digest for the given context. A slice of the provided digest buffer is returned. /// The length of the returned slice is dependent on the digest length of the selected algorithm. - pub fn finish<'a>(&mut self, mut ctx: Context, digest: &'a mut [u8; 32]) -> &'a [u8] { + pub async fn finish<'a>(&mut self, mut ctx: Context, digest: &'a mut [u8; 32]) -> &'a [u8] { // Restore the peripheral state. self.load_context(&ctx); + // Hash the leftover bytes, if any. self.accumulate(&ctx.buffer[0..ctx.buflen]); ctx.buflen = 0; //Start the digest calculation. - PAC_HASH.str().write(|w| w.set_dcal(true)); + T::regs().str().write(|w| w.set_dcal(true)); - //Wait for completion. - while !PAC_HASH.sr().read().dcis() {} + // Wait for completion. + poll_fn(|cx| { + // Check if already done. + let bits = T::regs().sr().read(); + if bits.dcis() { + return Poll::Ready(()); + } + // Register waker, then enable interrupts. + HASH_WAKER.register(cx.waker()); + T::regs().imr().modify(|reg| reg.set_dinie(true)); + // Check for completion. + let bits = T::regs().sr().read(); + if bits.dcis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; - //Return the digest. + // Return the digest. let digest_words = match ctx.algo { Algorithm::SHA1 => 5, Algorithm::MD5 => 4, @@ -215,37 +264,57 @@ impl<'d> Hash<'d> { }; let mut i = 0; while i < digest_words { - let word = PAC_HASH.hr(i).read(); + let word = T::regs().hr(i).read(); digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); i += 1; } &digest[0..digest_words * 4] } + /// Push data into the hash core. fn accumulate(&mut self, input: &[u8]) { - //Set the number of valid bits. + // Set the number of valid bits. let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; - PAC_HASH.str().modify(|w| w.set_nblw(num_valid_bits)); + T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); let mut i = 0; while i < input.len() { let mut word: [u8; 4] = [0; 4]; let copy_idx = min(i + 4, input.len()); word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); - PAC_HASH.din().write_value(u32::from_ne_bytes(word)); + T::regs().din().write_value(u32::from_ne_bytes(word)); i += 4; } } /// Save the peripheral state to a context. - fn store_context(&mut self, ctx: &mut Context) { - while !PAC_HASH.sr().read().dinis() {} - ctx.imr = PAC_HASH.imr().read().0; - ctx.str = PAC_HASH.str().read().0; - ctx.cr = PAC_HASH.cr().read().0; + async fn store_context(&mut self, ctx: &mut Context) { + // Wait for interrupt. + poll_fn(|cx| { + // Check if already done. + let bits = T::regs().sr().read(); + if bits.dinis() { + return Poll::Ready(()); + } + // Register waker, then enable interrupts. + HASH_WAKER.register(cx.waker()); + T::regs().imr().modify(|reg| reg.set_dinie(true)); + // Check for completion. + let bits = T::regs().sr().read(); + if bits.dinis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + ctx.imr = T::regs().imr().read().0; + ctx.str = T::regs().str().read().0; + ctx.cr = T::regs().cr().read().0; let mut i = 0; while i < NUM_CONTEXT_REGS { - ctx.csr[i] = PAC_HASH.csr(i).read(); + ctx.csr[i] = T::regs().csr(i).read(); i += 1; } } @@ -253,14 +322,42 @@ impl<'d> Hash<'d> { /// Restore the peripheral state from a context. fn load_context(&mut self, ctx: &Context) { // Restore the peripheral state from the context. - PAC_HASH.imr().write_value(Imr { 0: ctx.imr }); - PAC_HASH.str().write_value(Str { 0: ctx.str }); - PAC_HASH.cr().write_value(Cr { 0: ctx.cr }); - PAC_HASH.cr().modify(|w| w.set_init(true)); + T::regs().imr().write_value(Imr { 0: ctx.imr }); + T::regs().str().write_value(Str { 0: ctx.str }); + T::regs().cr().write_value(Cr { 0: ctx.cr }); + T::regs().cr().modify(|w| w.set_init(true)); let mut i = 0; while i < NUM_CONTEXT_REGS { - PAC_HASH.csr(i).write_value(ctx.csr[i]); + T::regs().csr(i).write_value(ctx.csr[i]); i += 1; } } } + +pub(crate) mod sealed { + use super::*; + + pub trait Instance { + fn regs() -> pac::hash::Hash; + } +} + +/// HASH instance trait. +pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { + /// Interrupt for this HASH instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +foreach_interrupt!( + ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => { + impl Instance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + + impl sealed::Instance for peripherals::$inst { + fn regs() -> crate::pac::hash::Hash { + crate::pac::$inst + } + } + }; +); From e05c8e2f44d3b210affa10a6e7fc7e9a3c991683 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 1 Feb 2024 23:47:30 +0100 Subject: [PATCH 357/760] stm32/dac: use autogenerated RCC impls. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/dac/mod.rs | 23 ----------------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 698febf71..aed9f7a46 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-0cb3a4fcaec702c93b3700715de796636d562b15" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-768b3e8e3199e03de0acd0d4590d06f51eebb7dd" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-0cb3a4fcaec702c93b3700715de796636d562b15", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-768b3e8e3199e03de0acd0d4590d06f51eebb7dd", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 31dedf06e..60f9404c2 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -504,29 +504,6 @@ pub trait DacPin: crate::gpio::Pin + 'static {} foreach_peripheral!( (dac, $inst:ident) => { - // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented - #[cfg(any(rcc_h7, rcc_h7rm0433))] - impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 }) - } - - fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { - // TODO: Increment refcount? - crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); - crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); - crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); - } - - fn disable_with_cs(_cs: critical_section::CriticalSection) { - // TODO: Decrement refcount? - crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)) - } - } - - #[cfg(any(rcc_h7, rcc_h7rm0433))] - impl crate::rcc::RccPeripheral for peripherals::$inst {} - impl crate::dac::sealed::Instance for peripherals::$inst { fn regs() -> &'static crate::pac::dac::Dac { &crate::pac::$inst From 92690d8590301360cca8889fe9d118eb3cc30202 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 2 Feb 2024 13:53:16 -0500 Subject: [PATCH 358/760] Migrate STM32WBA to RCCv3 --- embassy-stm32/src/rcc/wba.rs | 195 +++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 91 deletions(-) diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 1d04d480a..dfa236484 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -1,5 +1,8 @@ -use stm32_metapac::rcc::vals::{Pllsrc, Sw}; - +pub use crate::pac::pwr::vals::Vos as VoltageScale; +use crate::pac::rcc::regs::Cfgr1; +pub use crate::pac::rcc::vals::{ + Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as ClockSrc, +}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -9,82 +12,108 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); // HSE speed pub const HSE_FREQ: Hertz = Hertz(32_000_000); -pub use crate::pac::pwr::vals::Vos as VoltageScale; -pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; - -#[derive(Copy, Clone)] -pub enum ClockSrc { - HSE, - HSI, -} - -#[derive(Clone, Copy, Debug)] -pub enum PllSource { - HSE, - HSI, -} - -impl Into for PllSource { - fn into(self) -> Pllsrc { - match self { - PllSource::HSE => Pllsrc::HSE, - PllSource::HSI => Pllsrc::HSI, - } - } -} - -impl Into for ClockSrc { - fn into(self) -> Sw { - match self { - ClockSrc::HSE => Sw::HSE, - ClockSrc::HSI => Sw::HSI, - } - } +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + pub prescaler: HsePrescaler, } +/// Clocks configuration pub struct Config { + // base clock sources + pub hsi: bool, + pub hse: Option, + + // sysclk, buses. pub mux: ClockSrc, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, pub apb7_pre: APBPrescaler, + + // low speed LSI/LSE/RTC pub ls: super::LsConfig, + + pub adc_clock_source: AdcClockSource, + + pub voltage_scale: VoltageScale, } impl Default for Config { - fn default() -> Self { - Self { + #[inline] + fn default() -> Config { + Config { + hse: None, + hsi: true, mux: ClockSrc::HSI, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1, ls: Default::default(), + adc_clock_source: AdcClockSource::HCLK1, + voltage_scale: VoltageScale::RANGE2, } } } +fn hsi_enable() { + RCC.cr().modify(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} +} + pub(crate) unsafe fn init(config: Config) { + // Switch to HSI to prevent problems with PLL configuration. + if !RCC.cr().read().hsion() { + hsi_enable() + } + if RCC.cfgr1().read().sws() != ClockSrc::HSI { + // Set HSI as a clock source, reset prescalers. + RCC.cfgr1().write_value(Cfgr1::default()); + // Wait for clock switch status bits to change. + while RCC.cfgr1().read().sws() != ClockSrc::HSI {} + } + + // Set voltage scale + crate::pac::PWR.vosr().write(|w| w.set_vos(config.voltage_scale)); + while !crate::pac::PWR.vosr().read().vosrdy() {} + + let rtc = config.ls.init(); + + let hsi = config.hsi.then(|| { + hsi_enable(); + + HSI_FREQ + }); + + let hse = config.hse.map(|hse| { + RCC.cr().write(|w| { + w.set_hseon(true); + w.set_hsepre(hse.prescaler); + }); + while !RCC.cr().read().hserdy() {} + + HSE_FREQ + }); + let sys_clk = match config.mux { - ClockSrc::HSE => { - RCC.cr().write(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - - HSE_FREQ - } - ClockSrc::HSI => { - RCC.cr().write(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - - HSI_FREQ - } + ClockSrc::HSE => hse.unwrap(), + ClockSrc::HSI => hsi.unwrap(), + ClockSrc::_RESERVED_1 => unreachable!(), + ClockSrc::PLL1_R => todo!(), }; - // TODO make configurable - let power_vos = VoltageScale::RANGE1; + assert!(sys_clk.0 <= 100_000_000); - // states and programming delay - let wait_states = match power_vos { + let hclk1 = sys_clk / config.ahb_pre; + let hclk2 = hclk1; + let hclk4 = hclk1; + // TODO: hclk5 + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre); + let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre); + let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre); + + // Set flash wait states + let flash_latency = match config.voltage_scale { VoltageScale::RANGE1 => match sys_clk.0 { ..=32_000_000 => 0, ..=64_000_000 => 1, @@ -99,13 +128,24 @@ pub(crate) unsafe fn init(config: Config) { }, }; - FLASH.acr().modify(|w| { - w.set_latency(wait_states); - }); + FLASH.acr().modify(|w| w.set_latency(flash_latency)); + while FLASH.acr().read().latency() != flash_latency {} + + // Set sram wait states + let _sram_latency = match config.voltage_scale { + VoltageScale::RANGE1 => 0, + VoltageScale::RANGE2 => match sys_clk.0 { + ..=12_000_000 => 0, + ..=16_000_000 => 1, + _ => 2, + }, + }; + // TODO: Set the SRAM wait states RCC.cfgr1().modify(|w| { - w.set_sw(config.mux.into()); + w.set_sw(config.mux); }); + while RCC.cfgr1().read().sws() != config.mux {} RCC.cfgr2().modify(|w| { w.set_hpre(config.ahb_pre); @@ -113,45 +153,18 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre); }); - RCC.cfgr3().modify(|w| { - w.set_ppre7(config.apb7_pre); - }); - - let ahb_freq = sys_clk / config.ahb_pre; - let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } - }; - let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } - }; - let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } - }; - - let rtc = config.ls.init(); + RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source)); set_freqs(Clocks { sys: sys_clk, - hclk1: ahb_freq, - hclk2: ahb_freq, - hclk4: ahb_freq, - pclk1: apb1_freq, - pclk2: apb2_freq, - pclk7: apb7_freq, - pclk1_tim: apb1_tim_freq, - pclk2_tim: apb2_tim_freq, + hclk1, + hclk2, + hclk4, + pclk1, + pclk2, + pclk7, + pclk1_tim, + pclk2_tim, rtc, }); } From 98668473756b144cb5e5d7bb2be4b54b947412ff Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 2 Feb 2024 22:42:32 +0100 Subject: [PATCH 359/760] stm32: autogenerate clocks struct, enable mux for all chips. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/build.rs | 69 ++++++++----- embassy-stm32/src/adc/f1.rs | 3 +- embassy-stm32/src/adc/f3.rs | 2 +- embassy-stm32/src/adc/mod.rs | 7 -- embassy-stm32/src/eth/mod.rs | 3 +- embassy-stm32/src/eth/v1/mod.rs | 4 +- embassy-stm32/src/eth/v2/mod.rs | 4 +- embassy-stm32/src/hrtim/mod.rs | 4 +- embassy-stm32/src/hrtim/traits.rs | 16 +-- embassy-stm32/src/i2s.rs | 9 +- embassy-stm32/src/rcc/c0.rs | 15 ++- embassy-stm32/src/rcc/f.rs | 57 ++++++----- embassy-stm32/src/rcc/f0.rs | 21 ++-- embassy-stm32/src/rcc/f1.rs | 19 ++-- embassy-stm32/src/rcc/f3.rs | 22 +++-- embassy-stm32/src/rcc/g0.rs | 15 ++- embassy-stm32/src/rcc/g4.rs | 23 +++-- embassy-stm32/src/rcc/h.rs | 59 ++++------- embassy-stm32/src/rcc/l.rs | 75 ++++++++------ embassy-stm32/src/rcc/mod.rs | 159 +----------------------------- embassy-stm32/src/rcc/u5.rs | 46 ++++++--- embassy-stm32/src/rcc/wba.rs | 32 +++--- embassy-stm32/src/sdmmc/mod.rs | 64 +----------- embassy-stm32/src/usb/usb.rs | 2 +- 25 files changed, 284 insertions(+), 450 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index aed9f7a46..c412e13d5 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-768b3e8e3199e03de0acd0d4590d06f51eebb7dd" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3e3b53df78b4c90ae9c44a58b4f9f93c93a415b7" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-768b3e8e3199e03de0acd0d4590d06f51eebb7dd", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3e3b53df78b4c90ae9c44a58b4f9f93c93a415b7", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 74cc3f8b9..3885c5d18 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -461,6 +461,8 @@ fn main() { let force_refcount = HashSet::from(["usart"]); let mut refcount_statics = BTreeSet::new(); + let mut clock_names = BTreeSet::new(); + for p in METADATA.peripherals { if !singletons.contains(&p.name.to_string()) { continue; @@ -492,7 +494,6 @@ fn main() { let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; let pname = format_ident!("{}", p.name); - let clk = format_ident!("{}", rcc.clock); let en_reg = format_ident!("{}", en.register); let set_en_field = format_ident!("set_{}", en.field); @@ -522,14 +523,7 @@ fn main() { (TokenStream::new(), TokenStream::new()) }; - let mux_supported = HashSet::from(["c0", "h5", "h50", "h7", "h7ab", "h7rm0433", "g0", "g4", "l4"]) - .contains(rcc_registers.version); let mux_for = |mux: Option<&'static PeripheralRccRegister>| { - // restrict mux implementation to supported versions - if !mux_supported { - return None; - } - let mux = mux?; let fieldset = rcc_enum_map.get(mux.register)?; let enumm = fieldset.get(mux.field)?; @@ -550,15 +544,9 @@ fn main() { .map(|v| { let variant_name = format_ident!("{}", v.name); let clock_name = format_ident!("{}", v.name.to_ascii_lowercase()); - - if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" { - quote! { - #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name }, - } - } else { - quote! { - #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }, - } + clock_names.insert(v.name.to_ascii_lowercase()); + quote! { + #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }, } }) .collect(); @@ -569,19 +557,21 @@ fn main() { #[allow(unreachable_patterns)] match crate::pac::RCC.#fieldset_name().read().#field_name() { #match_arms - _ => unreachable!(), } } } - None => quote! { - unsafe { crate::rcc::get_freqs().#clk } - }, + None => { + let clock_name = format_ident!("{}", rcc.clock); + clock_names.insert(rcc.clock.to_string()); + quote! { + unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } + } + } }; /* A refcount leak can result if the same field is shared by peripherals with different stop modes - This condition should be checked in stm32-data */ let stop_refcount = match rcc.stop_mode { @@ -628,6 +618,39 @@ fn main() { } } + // Generate RCC + clock_names.insert("sys".to_string()); + clock_names.insert("rtc".to_string()); + let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect(); + g.extend(quote! { + #[derive(Clone, Copy, Debug)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub struct Clocks { + #( + pub #clock_idents: Option, + )* + } + }); + + let clocks_macro = quote!( + macro_rules! set_clocks { + ($($(#[$m:meta])* $k:ident: $v:expr,)*) => { + { + #[allow(unused)] + struct Temp { + $($(#[$m])* $k: Option,)* + } + let all = Temp { + $($(#[$m])* $k: $v,)* + }; + crate::rcc::set_freqs(crate::rcc::Clocks { + #( #clock_idents: all.#clock_idents, )* + }); + } + }; + } + ); + let refcount_mod: TokenStream = refcount_statics .iter() .map(|refcount_static| { @@ -1349,7 +1372,7 @@ fn main() { } } - let mut m = String::new(); + let mut m = clocks_macro.to_string(); // DO NOT ADD more macros like these. // These turned to be a bad idea! diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index fb27bb87b..c896d8e3a 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -6,7 +6,6 @@ use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; -use crate::rcc::get_freqs; use crate::time::Hertz; use crate::{interrupt, Peripheral}; @@ -80,7 +79,7 @@ impl<'d, T: Instance> Adc<'d, T> { } fn freq() -> Hertz { - unsafe { get_freqs() }.adc.unwrap() + T::frequency() } pub fn sample_time_for_us(&self, us: u32) -> SampleTime { diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 6f59c230f..6606a2b9c 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -102,7 +102,7 @@ impl<'d, T: Instance> Adc<'d, T> { } fn freq() -> Hertz { - ::frequency() + ::frequency() } pub fn sample_time_for_us(&self, us: u32) -> SampleTime { diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e4dd35c34..d21c3053f 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -61,8 +61,6 @@ pub(crate) mod sealed { fn regs() -> crate::pac::adc::Adc; #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon; - #[cfg(adc_f3)] - fn frequency() -> crate::time::Hertz; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] fn state() -> &'static State; } @@ -103,11 +101,6 @@ foreach_adc!( return crate::pac::$common_inst } - #[cfg(adc_f3)] - fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.$clock.unwrap() - } - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] fn state() -> &'static sealed::State { static STATE: sealed::State = sealed::State::new(); diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index fbcdd7fae..71fe09c3f 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -13,6 +13,7 @@ use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; use embassy_sync::waitqueue::AtomicWaker; pub use self::_version::{InterruptHandler, *}; +use crate::rcc::RccPeripheral; #[allow(unused)] const MTU: usize = 1514; @@ -183,7 +184,7 @@ pub(crate) mod sealed { } /// Ethernet instance. -pub trait Instance: sealed::Instance + Send + 'static {} +pub trait Instance: sealed::Instance + RccPeripheral + Send + 'static {} impl sealed::Instance for crate::peripherals::ETH { fn regs() -> crate::pac::eth::Eth { diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 2ce5b3927..e5b7b0452 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -20,6 +20,7 @@ use crate::pac::AFIO; #[cfg(any(eth_v1b, eth_v1c))] use crate::pac::SYSCFG; use crate::pac::{ETH, RCC}; +use crate::rcc::sealed::RccPeripheral; use crate::{interrupt, Peripheral}; /// Interrupt handler. @@ -191,8 +192,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // TODO MTU size setting not found for v1 ethernet, check if correct - // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called - let hclk = unsafe { crate::rcc::get_freqs() }.hclk1; + let hclk = ::frequency(); let hclk_mhz = hclk.0 / 1_000_000; // Set the MDC clock frequency in the range 1MHz - 2.5MHz diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 4b22d1d21..8d69561d4 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -11,6 +11,7 @@ use crate::gpio::sealed::{AFType, Pin as _}; use crate::gpio::{AnyPin, Speed}; use crate::interrupt::InterruptExt; use crate::pac::ETH; +use crate::rcc::sealed::RccPeripheral; use crate::{interrupt, Peripheral}; /// Interrupt handler. @@ -264,8 +265,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_rbsz(RX_BUFFER_SIZE as u16); }); - // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called - let hclk = unsafe { crate::rcc::get_freqs() }.hclk1; + let hclk = ::frequency(); let hclk_mhz = hclk.0 / 1_000_000; // Set the MDC clock frequency in the range 1MHz - 2.5MHz diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index faefaabbc..3ec646fc3 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -10,8 +10,6 @@ pub use traits::Instance; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::AnyPin; -#[cfg(stm32f334)] -use crate::rcc::get_freqs; use crate::time::Hertz; use crate::Peripheral; @@ -182,7 +180,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { T::enable_and_reset(); #[cfg(stm32f334)] - if unsafe { get_freqs() }.hrtim.is_some() { + if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P { // Enable and and stabilize the DLL T::regs().dllcr().modify(|w| { w.set_cal(true); diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index cfd31c47c..dcc2b9ef4 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -80,10 +80,12 @@ pub(crate) mod sealed { fn set_master_frequency(frequency: Hertz) { let f = frequency.0; - #[cfg(not(stm32f334))] + + // TODO: wire up HRTIM to the RCC mux infra. + //#[cfg(stm32f334)] + //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; + //#[cfg(not(stm32f334))] let timer_f = Self::frequency().0; - #[cfg(stm32f334)] - let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); let psc = if Self::regs().isr().read().dllrdy() { @@ -103,10 +105,12 @@ pub(crate) mod sealed { fn set_channel_frequency(channel: usize, frequency: Hertz) { let f = frequency.0; - #[cfg(not(stm32f334))] + + // TODO: wire up HRTIM to the RCC mux infra. + //#[cfg(stm32f334)] + //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; + //#[cfg(not(stm32f334))] let timer_f = Self::frequency().0; - #[cfg(stm32f334)] - let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); let psc = if Self::regs().isr().read().dllrdy() { diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 1f85c0bc5..e9065dce6 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -4,7 +4,6 @@ use embassy_hal_internal::into_ref; use crate::gpio::sealed::{AFType, Pin as _}; use crate::gpio::AnyPin; use crate::pac::spi::vals; -use crate::rcc::get_freqs; use crate::spi::{Config as SpiConfig, *}; use crate::time::Hertz; use crate::{Peripheral, PeripheralRef}; @@ -193,10 +192,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { spi_cfg.frequency = freq; let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg); - #[cfg(all(rcc_f4, not(stm32f410)))] - let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap(); - - #[cfg(stm32f410)] + // TODO move i2s to the new mux infra. + //#[cfg(all(rcc_f4, not(stm32f410)))] + //let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap(); + //#[cfg(stm32f410)] let pclk = T::frequency(); let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 68f029ca0..ca1222185 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -2,7 +2,6 @@ use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::Sw; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler}; use crate::pac::{FLASH, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed @@ -133,13 +132,13 @@ pub(crate) unsafe fn init(config: Config) { } }; - set_freqs(Clocks { + set_clocks!( hsi: None, lse: None, - sys: sys_clk, - hclk1: ahb_freq, - pclk1: apb_freq, - pclk1_tim: apb_tim_freq, - rtc, - }); + sys: Some(sys_clk), + hclk1: Some(ahb_freq), + pclk1: Some(apb_freq), + pclk1_tim: Some(apb_tim_freq), + rtc: rtc, + ); } diff --git a/embassy-stm32/src/rcc/f.rs b/embassy-stm32/src/rcc/f.rs index 36d9f178f..e306d478d 100644 --- a/embassy-stm32/src/rcc/f.rs +++ b/embassy-stm32/src/rcc/f.rs @@ -7,7 +7,6 @@ pub use crate::pac::rcc::vals::{ #[cfg(any(stm32f4, stm32f7))] use crate::pac::PWR; use crate::pac::{FLASH, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; // TODO: on some F4s, PLLM is shared between all PLLs. Enforce that. @@ -183,9 +182,9 @@ pub(crate) unsafe fn init(config: Config) { }; let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] - let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); + let plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] - let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); + let pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); // Configure sysclk let sys = match config.sys { @@ -257,27 +256,41 @@ pub(crate) unsafe fn init(config: Config) { }); while RCC.cfgr().read().sws() != config.sys {} - set_freqs(Clocks { - sys, - hclk1: hclk, - hclk2: hclk, - hclk3: hclk, - pclk1, - pclk2, - pclk1_tim, - pclk2_tim, - rtc, + set_clocks!( + hsi: hsi, + hse: hse, + lse: None, // TODO + lsi: None, // TODO + sys: Some(sys), + hclk1: Some(hclk), + hclk2: Some(hclk), + hclk3: Some(hclk), + pclk1: Some(pclk1), + pclk2: Some(pclk2), + pclk1_tim: Some(pclk1_tim), + pclk2_tim: Some(pclk2_tim), + rtc: rtc, pll1_q: pll.q, - #[cfg(all(rcc_f4, not(stm32f410)))] - plli2s1_q: _plli2s.q, - #[cfg(all(rcc_f4, not(stm32f410)))] - plli2s1_r: _plli2s.r, - #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] - pllsai1_q: _pllsai.q, - #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] - pllsai1_r: _pllsai.r, - }); + #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] + plli2s1_p: plli2s.p, + #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] + plli2s1_q: plli2s.q, + #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] + plli2s1_r: plli2s.r, + + #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] + pllsai1_p: pllsai.p, + #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] + pllsai1_q: pllsai.q, + #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] + pllsai1_r: pllsai.r, + + clk48: pll.q, + + hsi_hse: None, + afif: None, + ); } struct PllInput { diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index feaa2f4c0..a6b627887 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs @@ -1,6 +1,5 @@ use stm32_metapac::flash::vals::Latency; -use super::{set_freqs, Clocks}; use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -160,13 +159,15 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); - set_freqs(Clocks { - sys: Hertz(real_sysclk), - pclk1: Hertz(pclk), - pclk2: Hertz(pclk), - pclk1_tim: Hertz(pclk * timer_mul), - pclk2_tim: Hertz(pclk * timer_mul), - hclk1: Hertz(hclk), - rtc, - }); + set_clocks!( + hsi: None, + lse: None, + sys: Some(Hertz(real_sysclk)), + pclk1: Some(Hertz(pclk)), + pclk2: Some(Hertz(pclk)), + pclk1_tim: Some(Hertz(pclk * timer_mul)), + pclk2_tim: Some(Hertz(pclk * timer_mul)), + hclk1: Some(Hertz(hclk)), + rtc: rtc, + ); } diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index 169551e45..7f0adab27 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -1,6 +1,5 @@ use core::convert::TryFrom; -use super::{set_freqs, Clocks}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::*; use crate::pac::{FLASH, RCC}; @@ -179,14 +178,14 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); - set_freqs(Clocks { - sys: Hertz(real_sysclk), - pclk1: Hertz(pclk1), - pclk2: Hertz(pclk2), - pclk1_tim: Hertz(pclk1 * timer_mul1), - pclk2_tim: Hertz(pclk2 * timer_mul2), - hclk1: Hertz(hclk), + set_clocks!( + sys: Some(Hertz(real_sysclk)), + pclk1: Some(Hertz(pclk1)), + pclk2: Some(Hertz(pclk2)), + pclk1_tim: Some(Hertz(pclk1 * timer_mul1)), + pclk2_tim: Some(Hertz(pclk2 * timer_mul2)), + hclk1: Some(Hertz(hclk)), adc: Some(Hertz(adcclk)), - rtc, - }); + rtc: rtc, + ); } diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index bf035fd25..25866e446 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -4,7 +4,6 @@ use crate::pac::flash::vals::Latency; pub use crate::pac::rcc::vals::Adcpres; use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; use crate::pac::{FLASH, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed @@ -279,13 +278,16 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); - set_freqs(Clocks { - sys: sysclk, - pclk1: pclk1, - pclk2: pclk2, - pclk1_tim: pclk1 * timer_mul1, - pclk2_tim: pclk2 * timer_mul2, - hclk1: hclk, + set_clocks!( + hsi: None, + lse: None, + pll1_p: None, + sys: Some(sysclk), + pclk1: Some(pclk1), + pclk2: Some(pclk2), + pclk1_tim: Some(pclk1 * timer_mul1), + pclk2_tim: Some(pclk2 * timer_mul2), + hclk1: Some(hclk), #[cfg(rcc_f3)] adc: adc, #[cfg(all(rcc_f3, adc3_common))] @@ -294,8 +296,8 @@ pub(crate) unsafe fn init(config: Config) { adc34: None, #[cfg(stm32f334)] hrtim: hrtim, - rtc, - }); + rtc: rtc, + ); } #[inline] diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index b38fe1dcc..e3cd46fb9 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -4,7 +4,6 @@ pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler, }; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed @@ -352,11 +351,11 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))] let hsi48_freq: Option = None; - set_freqs(Clocks { - sys: sys_clk, - hclk1: ahb_freq, - pclk1: apb_freq, - pclk1_tim: apb_tim_freq, + set_clocks!( + sys: Some(sys_clk), + hclk1: Some(ahb_freq), + pclk1: Some(apb_freq), + pclk1_tim: Some(apb_tim_freq), hsi: hsi_freq, hsi48: hsi48_freq, hsi_div_8: hsi_div_8_freq, @@ -365,6 +364,6 @@ pub(crate) unsafe fn init(config: Config) { lsi: lsi_freq, pll1_q: pll1_q_freq, pll1_p: pll1_p_freq, - rtc, - }); + rtc: rtc, + ); } diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 891f0490b..3e20bf6af 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -7,7 +7,6 @@ pub use crate::pac::rcc::vals::{ Pllp as PllP, Pllq as PllQ, Pllr as PllR, Ppre as APBPrescaler, }; use crate::pac::{PWR, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed @@ -307,20 +306,20 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); - set_freqs(Clocks { - sys: sys_clk, - hclk1: ahb_freq, - hclk2: ahb_freq, - hclk3: ahb_freq, - pclk1: apb1_freq, - pclk1_tim: apb1_tim_freq, - pclk2: apb2_freq, - pclk2_tim: apb2_tim_freq, + set_clocks!( + sys: Some(sys_clk), + hclk1: Some(ahb_freq), + hclk2: Some(ahb_freq), + hclk3: Some(ahb_freq), + pclk1: Some(apb1_freq), + pclk1_tim: Some(apb1_tim_freq), + pclk2: Some(apb2_freq), + pclk2_tim: Some(apb2_tim_freq), adc: adc12_ck, adc34: adc345_ck, pll1_p: None, pll1_q: None, // TODO hse: None, // TODO - rtc, - }); + rtc: rtc, + ); } diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index dcaf2dced..9ac2115f0 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -12,7 +12,6 @@ pub use crate::pac::rcc::vals::{ }; use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed @@ -430,7 +429,7 @@ pub(crate) unsafe fn init(config: Config) { }; // Configure HSI48. - let _hsi48 = config.hsi48.map(super::init_hsi48); + let hsi48 = config.hsi48.map(super::init_hsi48); // Configure CSI. RCC.cr().modify(|w| w.set_csion(config.csi)); @@ -614,45 +613,33 @@ pub(crate) unsafe fn init(config: Config) { while !pac::SYSCFG.cccsr().read().ready() {} } - set_freqs(Clocks { - sys, - hclk1: hclk, - hclk2: hclk, - hclk3: hclk, - hclk4: hclk, - pclk1: apb1, - pclk2: apb2, - pclk3: apb3, + set_clocks!( + sys: Some(sys), + hclk1: Some(hclk), + hclk2: Some(hclk), + hclk3: Some(hclk), + hclk4: Some(hclk), + pclk1: Some(apb1), + pclk2: Some(apb2), + pclk3: Some(apb3), #[cfg(stm32h7)] - pclk4: apb4, - #[cfg(stm32h5)] - pclk4: Hertz(1), - pclk1_tim: apb1_tim, - pclk2_tim: apb2_tim, - adc, - rtc, + pclk4: Some(apb4), + pclk1_tim: Some(apb1_tim), + pclk2_tim: Some(apb2_tim), + adc: adc, + rtc: rtc, - #[cfg(any(stm32h5, stm32h7))] - hsi: None, - #[cfg(stm32h5)] - hsi48: None, - #[cfg(stm32h5)] - lsi: None, - #[cfg(any(stm32h5, stm32h7))] - csi: None, + hsi: hsi, + hsi48: hsi48, + csi: csi, + hse: hse, - #[cfg(any(stm32h5, stm32h7))] lse: None, - #[cfg(any(stm32h5, stm32h7))] - hse: None, + lsi: None, - #[cfg(any(stm32h5, stm32h7))] pll1_q: pll1.q, - #[cfg(any(stm32h5, stm32h7))] pll2_p: pll2.p, - #[cfg(any(stm32h5, stm32h7))] pll2_q: pll2.q, - #[cfg(any(stm32h5, stm32h7))] pll2_r: pll2.r, #[cfg(any(rcc_h5, stm32h7))] pll3_p: pll3.p, @@ -670,12 +657,8 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h5)] audioclk: None, - #[cfg(any(stm32h5, stm32h7))] per: None, - - #[cfg(stm32h7)] - rcc_pclk_d3: None, - }); + ); } struct PllInput { diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 257fd83fe..ab1681dd4 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -9,7 +9,6 @@ pub use crate::pac::rcc::vals::Clk48sel as Clk48Src; pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as ClockSrc}; use crate::pac::{FLASH, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed @@ -262,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32l4, stm32l5, stm32wb))] let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input); #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] - let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input); + let pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input); let sys_clk = match config.mux { ClockSrc::HSE => hse.unwrap(), @@ -274,12 +273,12 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src)); #[cfg(any(rcc_l0_v2))] - let _clk48 = match config.clk48_src { + let clk48 = match config.clk48_src { Clk48Src::HSI48 => _hsi48, Clk48Src::PLL1_VCO_DIV_2 => pll.clk48, }; #[cfg(any(stm32l4, stm32l5, stm32wb))] - let _clk48 = match config.clk48_src { + let clk48 = match config.clk48_src { Clk48Src::HSI48 => _hsi48, Clk48Src::MSI => msi, Clk48Src::PLLSAI1_Q => pllsai1.q, @@ -376,37 +375,53 @@ pub(crate) unsafe fn init(config: Config) { while !RCC.extcfgr().read().c2hpref() {} } - set_freqs(Clocks { - sys: sys_clk, - hclk1, + set_clocks!( + sys: Some(sys_clk), + hclk1: Some(hclk1), #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - hclk2, + hclk2: Some(hclk2), #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - hclk3, - pclk1, - pclk2, - pclk1_tim, - pclk2_tim, + hclk3: Some(hclk3), + pclk1: Some(pclk1), + pclk2: Some(pclk2), + pclk1_tim: Some(pclk1_tim), + pclk2_tim: Some(pclk2_tim), #[cfg(stm32wl)] - pclk3: hclk3, - #[cfg(rcc_l4)] - hsi: None, - #[cfg(rcc_l4)] - lse: None, - #[cfg(rcc_l4)] - pllsai1_p: None, - #[cfg(rcc_l4)] - pllsai2_p: None, - #[cfg(rcc_l4)] - pll1_p: None, - #[cfg(rcc_l4)] - pll1_q: None, - #[cfg(rcc_l4)] + pclk3: Some(hclk3), + hsi: hsi, + hse: hse, + msi: msi, + #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] + clk48: clk48, + + #[cfg(not(any(stm32l0, stm32l1)))] + pll1_p: pll.p, + #[cfg(not(any(stm32l0, stm32l1)))] + pll1_q: pll.q, + pll1_r: pll.r, + + #[cfg(any(stm32l4, stm32l5, stm32wb))] + pllsai1_p: pllsai1.p, + #[cfg(any(stm32l4, stm32l5, stm32wb))] + pllsai1_q: pllsai1.q, + #[cfg(any(stm32l4, stm32l5, stm32wb))] + pllsai1_r: pllsai1.r, + + #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] + pllsai2_p: pllsai2.p, + #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] + pllsai2_q: pllsai2.q, + #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] + pllsai2_r: pllsai2.r, + + rtc: rtc, + + // TODO sai1_extclk: None, - #[cfg(rcc_l4)] sai2_extclk: None, - rtc, - }); + lsi: None, + lse: None, + ); } #[cfg(any(stm32l0, stm32l1))] diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 240ffc6d2..280da7ae3 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -5,8 +5,6 @@ use core::mem::MaybeUninit; -use crate::time::Hertz; - mod bd; mod mco; pub use bd::*; @@ -32,162 +30,7 @@ mod _version; pub use _version::*; -// Model Clock Configuration -// -// pub struct Clocks { -// hse: Option, -// hsi: bool, -// lse: Option, -// lsi: bool, -// rtc: RtcSource, -// } - -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Clocks { - pub sys: Hertz, - - // APB - pub pclk1: Hertz, - pub pclk1_tim: Hertz, - #[cfg(not(any(rcc_c0, rcc_g0)))] - pub pclk2: Hertz, - #[cfg(not(any(rcc_c0, rcc_g0)))] - pub pclk2_tim: Hertz, - #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))] - pub pclk3: Hertz, - #[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab, stm32h5))] - pub pclk4: Hertz, - #[cfg(any(rcc_wba))] - pub pclk7: Hertz, - - // AHB - pub hclk1: Hertz, - #[cfg(any( - rcc_l4, - rcc_l4plus, - rcc_l5, - rcc_f2, - rcc_f4, - rcc_f410, - rcc_f7, - rcc_h5, - rcc_h50, - rcc_h7, - rcc_h7rm0433, - rcc_h7ab, - rcc_g4, - rcc_u5, - rcc_wb, - rcc_wba, - rcc_wl5, - rcc_wle - ))] - pub hclk2: Hertz, - #[cfg(any( - rcc_l4, - rcc_l4plus, - rcc_l5, - rcc_f2, - rcc_f4, - rcc_f410, - rcc_f7, - rcc_h5, - rcc_h50, - rcc_h7, - rcc_h7rm0433, - rcc_h7ab, - rcc_u5, - rcc_g4, - rcc_wb, - rcc_wl5, - rcc_wle - ))] - pub hclk3: Hertz, - #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))] - pub hclk4: Hertz, - - #[cfg(all(rcc_f4, not(stm32f410)))] - pub plli2s1_q: Option, - #[cfg(all(rcc_f4, not(stm32f410)))] - pub plli2s1_r: Option, - - #[cfg(rcc_l4)] - pub pllsai1_p: Option, - #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] - pub pllsai1_q: Option, - #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] - pub pllsai1_r: Option, - #[cfg(rcc_l4)] - pub pllsai2_p: Option, - - #[cfg(any(stm32g0, stm32g4, rcc_l4))] - pub pll1_p: Option, - #[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g0, stm32g4))] - pub pll1_q: Option, - #[cfg(any(stm32h5, stm32h7))] - pub pll2_p: Option, - #[cfg(any(stm32h5, stm32h7))] - pub pll2_q: Option, - #[cfg(any(stm32h5, stm32h7))] - pub pll2_r: Option, - #[cfg(any(stm32h5, stm32h7))] - pub pll3_p: Option, - #[cfg(any(stm32h5, stm32h7))] - pub pll3_q: Option, - #[cfg(any(stm32h5, stm32h7))] - pub pll3_r: Option, - - #[cfg(any( - rcc_f1, - rcc_f100, - rcc_f1cl, - rcc_h5, - rcc_h50, - rcc_h7, - rcc_h7rm0433, - rcc_h7ab, - rcc_f3, - rcc_g4 - ))] - pub adc: Option, - - #[cfg(any(rcc_f3, rcc_g4))] - pub adc34: Option, - - #[cfg(stm32f334)] - pub hrtim: Option, - - pub rtc: Option, - - #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))] - pub hsi: Option, - #[cfg(any(stm32h5, stm32g0))] - pub hsi48: Option, - #[cfg(stm32g0)] - pub hsi_div_8: Option, - #[cfg(any(stm32g0, stm32h5))] - pub lsi: Option, - #[cfg(any(stm32h5, stm32h7))] - pub csi: Option, - - #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))] - pub lse: Option, - #[cfg(any(stm32h5, stm32h7, stm32g0, stm32g4))] - pub hse: Option, - - #[cfg(stm32h5)] - pub audioclk: Option, - #[cfg(any(stm32h5, stm32h7))] - pub per: Option, - - #[cfg(stm32h7)] - pub rcc_pclk_d3: Option, - #[cfg(rcc_l4)] - pub sai1_extclk: Option, - #[cfg(rcc_l4)] - pub sai2_extclk: Option, -} +pub use crate::_generated::Clocks; #[cfg(feature = "low-power")] /// Must be written within a critical section diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index dff08dc9b..9cec6c96c 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -1,7 +1,6 @@ pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed @@ -338,7 +337,7 @@ pub(crate) unsafe fn init(config: Config) { } }; - let _hsi48 = config.hsi48.map(super::init_hsi48); + let hsi48 = config.hsi48.map(super::init_hsi48); // The clock source is ready // Calculate and set the flash wait states @@ -448,18 +447,37 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); - set_freqs(Clocks { - sys: sys_clk, - hclk1: ahb_freq, - hclk2: ahb_freq, - hclk3: ahb_freq, - pclk1: apb1_freq, - pclk2: apb2_freq, - pclk3: apb3_freq, - pclk1_tim: apb1_tim_freq, - pclk2_tim: apb2_tim_freq, - rtc, - }); + set_clocks!( + sys: Some(sys_clk), + hclk1: Some(ahb_freq), + hclk2: Some(ahb_freq), + hclk3: Some(ahb_freq), + pclk1: Some(apb1_freq), + pclk2: Some(apb2_freq), + pclk3: Some(apb3_freq), + pclk1_tim: Some(apb1_tim_freq), + pclk2_tim: Some(apb2_tim_freq), + hsi48: hsi48, + rtc: rtc, + + // TODO + hse: None, + hsi: None, + audioclk: None, + hsi48_div_2: None, + lse: None, + lsi: None, + msik: None, + pll1_p: None, + pll1_q: None, + pll1_r: None, + pll2_p: None, + pll2_q: None, + pll2_r: None, + pll3_p: None, + pll3_q: None, + pll3_r: None, + ); } fn msirange_to_hertz(range: Msirange) -> Hertz { diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index dfa236484..47ce4783c 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -4,7 +4,6 @@ pub use crate::pac::rcc::vals::{ Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as ClockSrc, }; use crate::pac::{FLASH, RCC}; -use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed @@ -155,16 +154,23 @@ pub(crate) unsafe fn init(config: Config) { RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source)); - set_freqs(Clocks { - sys: sys_clk, - hclk1, - hclk2, - hclk4, - pclk1, - pclk2, - pclk7, - pclk1_tim, - pclk2_tim, - rtc, - }); + set_clocks!( + sys: Some(sys_clk), + hclk1: Some(hclk1), + hclk2: Some(hclk2), + hclk4: Some(hclk4), + pclk1: Some(pclk1), + pclk2: Some(pclk2), + pclk7: Some(pclk7), + pclk1_tim: Some(pclk1_tim), + pclk2_tim: Some(pclk2_tim), + rtc: rtc, + hse: hse, + hsi: hsi, + + // TODO + lse: None, + lsi: None, + pll1_q: None, + ); } diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index debe26c88..61589a215 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -670,7 +670,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { _ => panic!("Invalid Bus Width"), }; - let ker_ck = T::kernel_clk(); + let ker_ck = T::frequency(); let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 @@ -1023,7 +1023,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// specified frequency. pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { let regs = T::regs(); - let ker_ck = T::kernel_clk(); + let ker_ck = T::frequency(); let bus_width = match self.d3.is_some() { true => BusWidth::Four, @@ -1429,7 +1429,6 @@ pub(crate) mod sealed { fn regs() -> RegBlock; fn state() -> &'static AtomicWaker; - fn kernel_clk() -> Hertz; } pub trait Pins {} @@ -1461,61 +1460,6 @@ pub trait SdmmcDma {} #[cfg(sdmmc_v2)] impl SdmmcDma for NoDma {} -cfg_if::cfg_if! { - // TODO, these could not be implemented, because required clocks are not exposed in RCC: - // - H7 uses pll1_q_ck or pll2_r_ck depending on SDMMCSEL - // - L1 uses pll48 - // - L4 uses clk48(pll48) - // - L4+, L5, U5 uses clk48(pll48) or PLLSAI3CLK(PLLP) depending on SDMMCSEL - if #[cfg(stm32f1)] { - // F1 uses AHB1(HCLK), which is correct in PAC - macro_rules! kernel_clk { - ($inst:ident) => { - ::frequency() - } - } - } else if #[cfg(any(stm32f2, stm32f4))] { - // F2, F4 always use pll48 - macro_rules! kernel_clk { - ($inst:ident) => { - critical_section::with(|_| unsafe { - unwrap!(crate::rcc::get_freqs().pll1_q) - }) - } - } - } else if #[cfg(stm32f7)] { - macro_rules! kernel_clk { - (SDMMC1) => { - critical_section::with(|_| unsafe { - let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc1sel(); - if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYS { - crate::rcc::get_freqs().sys - } else { - unwrap!(crate::rcc::get_freqs().pll1_q) - } - }) - }; - (SDMMC2) => { - critical_section::with(|_| unsafe { - let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc2sel(); - if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYS { - crate::rcc::get_freqs().sys - } else { - unwrap!(crate::rcc::get_freqs().pll1_q) - } - }) - }; - } - } else { - // Use default peripheral clock and hope it works - macro_rules! kernel_clk { - ($inst:ident) => { - ::frequency() - } - } - } -} - foreach_peripheral!( (sdmmc, $inst:ident) => { impl sealed::Instance for peripherals::$inst { @@ -1529,10 +1473,6 @@ foreach_peripheral!( static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new(); &WAKER } - - fn kernel_clk() -> Hertz { - kernel_clk!($inst) - } } impl Instance for peripherals::$inst {} diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index f39915906..34d6b52fd 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -280,7 +280,7 @@ impl<'d, T: Instance> Driver<'d, T> { #[cfg(time)] embassy_time::block_for(embassy_time::Duration::from_millis(100)); #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10); + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10); #[cfg(not(usb_v4))] regs.btable().write(|w| w.set_btable(0)); From 4650a3566161ece4a743948129112402b9bb6e48 Mon Sep 17 00:00:00 2001 From: Matous Hybl Date: Sat, 3 Feb 2024 09:41:14 +0100 Subject: [PATCH 360/760] docs: Embassy in the wild - add air quality monitoring system --- docs/modules/ROOT/pages/embassy_in_the_wild.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc index a1c31bfc7..dfe9fd6e3 100644 --- a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc +++ b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc @@ -7,3 +7,5 @@ Here are known examples of real-world projects which make use of Embassy. Feel f * link:https://github.com/card-io-ecg/card-io-fw[Card/IO firmware] - firmware for an open source ECG device ** Targets the ESP32-S3 or ESP32-C6 MCU * The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL +** link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] +* Targets nRF52 and uses nrf-softdevice From b9d0069671b33107e35af6bdaa662e9c7be8e3f9 Mon Sep 17 00:00:00 2001 From: Stefan Gehr Date: Sat, 3 Feb 2024 14:56:31 +0100 Subject: [PATCH 361/760] correct spelling of the word "receive" --- embassy-net/src/tcp.rs | 4 ++-- embassy-stm32/src/eth/v2/descriptors.rs | 2 +- embassy-sync/src/priority_channel.rs | 2 +- examples/rp/src/bin/i2c_slave.rs | 6 +++--- tests/rp/src/bin/i2c.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 72b0677b4..c508ff97a 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -342,7 +342,7 @@ impl<'a> TcpSocket<'a> { self.io.with(|s, _| s.may_send()) } - /// return whether the recieve half of the full-duplex connection is open. + /// return whether the receive half of the full-duplex connection is open. /// This function returns true if it’s possible to receive data from the remote endpoint. /// It will return true while there is data in the receive buffer, and if there isn’t, /// as long as the remote endpoint has not closed the connection. @@ -471,7 +471,7 @@ impl<'d> TcpIo<'d> { s.register_recv_waker(cx.waker()); Poll::Pending } else { - // if we can't receive because the recieve half of the duplex connection is closed then return an error + // if we can't receive because the receive half of the duplex connection is closed then return an error Poll::Ready(Err(Error::ConnectionReset)) } } else { diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs index 01ea8e574..645bfdb14 100644 --- a/embassy-stm32/src/eth/v2/descriptors.rs +++ b/embassy-stm32/src/eth/v2/descriptors.rs @@ -129,7 +129,7 @@ impl<'a> TDesRing<'a> { /// Receive Descriptor representation /// -/// * rdes0: recieve buffer address +/// * rdes0: receive buffer address /// * rdes1: /// * rdes2: /// * rdes3: OWN and Status diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs index bd75c0135..e77678c24 100644 --- a/embassy-sync/src/priority_channel.rs +++ b/embassy-sync/src/priority_channel.rs @@ -325,7 +325,7 @@ where /// /// Sent data may be reordered based on their priorty within the channel. /// For example, in a [`Max`](heapless::binary_heap::Max) [`PriorityChannel`] -/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be recieved as `[3, 2, 1]`. +/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be received as `[3, 2, 1]`. pub struct PriorityChannel where T: Ord, diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs index 479f9a16a..ac470d2be 100644 --- a/examples/rp/src/bin/i2c_slave.rs +++ b/examples/rp/src/bin/i2c_slave.rs @@ -26,7 +26,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { loop { let mut buf = [0u8; 128]; match dev.listen(&mut buf).await { - Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device recieved general call write: {}", buf[..len]), + Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device received general call write: {}", buf[..len]), Ok(i2c_slave::Command::Read) => loop { match dev.respond_to_read(&[state]).await { Ok(x) => match x { @@ -40,9 +40,9 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { Err(e) => error!("error while responding {}", e), } }, - Ok(i2c_slave::Command::Write(len)) => info!("Device recieved write: {}", buf[..len]), + Ok(i2c_slave::Command::Write(len)) => info!("Device received write: {}", buf[..len]), Ok(i2c_slave::Command::WriteRead(len)) => { - info!("device recieved write read: {:x}", buf[..len]); + info!("device received write read: {:x}", buf[..len]); match buf[0] { // Set the state 0xC2 => { diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index 77d628cf6..a0aed1a42 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs @@ -80,7 +80,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { _ => panic!("Invalid write length {}", len), }, Ok(i2c_slave::Command::WriteRead(len)) => { - info!("device recieved write read: {:x}", buf[..len]); + info!("device received write read: {:x}", buf[..len]); match buf[0] { 0xC2 => { let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4]; From 72bbfec39d3f826c1a8dd485af2da4bcbdd32e35 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sat, 3 Feb 2024 16:10:00 -0500 Subject: [PATCH 362/760] Added hash DMA implementation. --- embassy-stm32/build.rs | 1 + embassy-stm32/src/hash/mod.rs | 143 ++++++++++++++----------------- examples/stm32f7/src/bin/hash.rs | 20 +++-- 3 files changed, 79 insertions(+), 85 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 948ce3aff..1a68dfc9d 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1015,6 +1015,7 @@ fn main() { (("dac", "CH1"), quote!(crate::dac::DacDma1)), (("dac", "CH2"), quote!(crate::dac::DacDma2)), (("timer", "UP"), quote!(crate::timer::UpDma)), + (("hash", "IN"), quote!(crate::hash::Dma)), ] .into(); diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 4e37e60e1..ac4854f80 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -2,11 +2,13 @@ use core::cmp::min; use core::future::poll_fn; use core::marker::PhantomData; +use core::ptr; use core::task::Poll; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +use crate::dma::Transfer; use crate::peripherals::HASH; use stm32_metapac::hash::regs::*; @@ -18,7 +20,6 @@ use crate::{interrupt, pac, peripherals, Peripheral}; const NUM_CONTEXT_REGS: usize = 51; #[cfg(hash_v2)] const NUM_CONTEXT_REGS: usize = 54; -const HASH_BUFFER_LEN: usize = 68; const DIGEST_BLOCK_SIZE: usize = 64; static HASH_WAKER: AtomicWaker = AtomicWaker::new(); @@ -74,8 +75,7 @@ pub enum DataType { /// Stores the state of the HASH peripheral for suspending/resuming /// digest calculation. pub struct Context { - first_word_sent: bool, - buffer: [u8; HASH_BUFFER_LEN], + buffer: [u8; DIGEST_BLOCK_SIZE], buflen: usize, algo: Algorithm, format: DataType, @@ -86,17 +86,19 @@ pub struct Context { } /// HASH driver. -pub struct Hash<'d, T: Instance> { +pub struct Hash<'d, T: Instance, D: Dma> { _peripheral: PeripheralRef<'d, T>, + dma: PeripheralRef<'d, D>, } -impl<'d, T: Instance> Hash<'d, T> { +impl<'d, T: Instance, D: Dma> Hash<'d, T, D> { /// Instantiates, resets, and enables the HASH peripheral. - pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { + pub fn new(peripheral: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { HASH::enable_and_reset(); - into_ref!(peripheral); + into_ref!(peripheral, dma); let instance = Self { _peripheral: peripheral, + dma: dma, }; T::Interrupt::unpend(); @@ -109,8 +111,7 @@ impl<'d, T: Instance> Hash<'d, T> { pub async fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { // Define a context for this new computation. let mut ctx = Context { - first_word_sent: false, - buffer: [0; 68], + buffer: [0; DIGEST_BLOCK_SIZE], buflen: 0, algo: algorithm, format: format, @@ -134,6 +135,11 @@ impl<'d, T: Instance> Hash<'d, T> { } T::regs().cr().modify(|w| w.set_algo0(algo0)); T::regs().cr().modify(|w| w.set_algo1(algo1)); + + // Enable multiple DMA transfers. + T::regs().cr().modify(|w| w.set_mdmat(true)); + + // Set init to load the context registers. Necessary before storing context. T::regs().cr().modify(|w| w.set_init(true)); // Store and return the state of the peripheral. @@ -145,8 +151,8 @@ impl<'d, T: Instance> Hash<'d, T> { /// then updates the state with the provided data. /// Peripheral state is saved upon return. pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) { - let mut data_waiting = input.len() + ctx.buflen; - if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) { + let data_waiting = input.len() + ctx.buflen; + if data_waiting < DIGEST_BLOCK_SIZE { // There isn't enough data to digest a block, so append it to the buffer. ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); ctx.buflen += input.len(); @@ -159,65 +165,35 @@ impl<'d, T: Instance> Hash<'d, T> { let mut ilen_remaining = input.len(); let mut input_start = 0; - // Handle first block. - if !ctx.first_word_sent { - let empty_len = ctx.buffer.len() - ctx.buflen; + // First ingest the data in the buffer. + let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; + if empty_len > 0 { let copy_len = min(empty_len, ilen_remaining); - // Fill the buffer. - if copy_len > 0 { - ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[0..copy_len]); - ctx.buflen += copy_len; - ilen_remaining -= copy_len; - input_start += copy_len; - } - assert_eq!(ctx.buflen, HASH_BUFFER_LEN); - self.accumulate(ctx.buffer.as_slice()); - data_waiting -= ctx.buflen; - ctx.buflen = 0; - ctx.first_word_sent = true; + ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[input_start..input_start + copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; } + self.accumulate(&ctx.buffer).await; + ctx.buflen = 0; - if data_waiting < 64 { - // There isn't enough data remaining to process another block, so store it. - assert_eq!(ctx.buflen, 0); - ctx.buffer[0..ilen_remaining].copy_from_slice(&input[input_start..input_start + ilen_remaining]); - ctx.buflen += ilen_remaining; + // Move any extra data to the now-empty buffer. + let leftovers = ilen_remaining % DIGEST_BLOCK_SIZE; + if leftovers > 0 { + assert!(ilen_remaining >= leftovers); + ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); + ctx.buflen += leftovers; + ilen_remaining -= leftovers; } else { - let mut total_data_sent = 0; - - // First ingest the data in the buffer. - let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; - if empty_len > 0 { - let copy_len = min(empty_len, ilen_remaining); - ctx.buffer[ctx.buflen..ctx.buflen + copy_len] - .copy_from_slice(&input[input_start..input_start + copy_len]); - ctx.buflen += copy_len; - ilen_remaining -= copy_len; - input_start += copy_len; - } - assert_eq!(ctx.buflen % 64, 0); - self.accumulate(&ctx.buffer[0..64]); - total_data_sent += ctx.buflen; - ctx.buflen = 0; - - // Move any extra data to the now-empty buffer. - let leftovers = ilen_remaining % 64; - if leftovers > 0 { - assert!(ilen_remaining >= leftovers); - ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); - ctx.buflen += leftovers; - ilen_remaining -= leftovers; - } - assert_eq!(ilen_remaining % 64, 0); - - // Hash the remaining data. - self.accumulate(&input[input_start..input_start + ilen_remaining]); - - total_data_sent += ilen_remaining; - assert_eq!(total_data_sent % 64, 0); - assert!(total_data_sent >= 64); + ctx.buffer + .copy_from_slice(&input[input.len() - DIGEST_BLOCK_SIZE..input.len()]); + ctx.buflen += DIGEST_BLOCK_SIZE; + ilen_remaining -= DIGEST_BLOCK_SIZE; } + // Hash the remaining data. + self.accumulate(&input[input_start..input_start + ilen_remaining]).await; + // Save the peripheral context. self.store_context(ctx).await; } @@ -228,12 +204,12 @@ impl<'d, T: Instance> Hash<'d, T> { // Restore the peripheral state. self.load_context(&ctx); - // Hash the leftover bytes, if any. - self.accumulate(&ctx.buffer[0..ctx.buflen]); - ctx.buflen = 0; + // Must be cleared prior to the last DMA transfer. + T::regs().cr().modify(|w| w.set_mdmat(false)); - //Start the digest calculation. - T::regs().str().write(|w| w.set_dcal(true)); + // Hash the leftover bytes, if any. + self.accumulate(&ctx.buffer[0..ctx.buflen]).await; + ctx.buflen = 0; // Wait for completion. poll_fn(|cx| { @@ -272,19 +248,30 @@ impl<'d, T: Instance> Hash<'d, T> { } /// Push data into the hash core. - fn accumulate(&mut self, input: &[u8]) { + async fn accumulate(&mut self, input: &[u8]) { + // Ignore an input length of 0. + if input.len() == 0 { + return; + } + // Set the number of valid bits. let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); - let mut i = 0; - while i < input.len() { - let mut word: [u8; 4] = [0; 4]; - let copy_idx = min(i + 4, input.len()); - word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); - T::regs().din().write_value(u32::from_ne_bytes(word)); - i += 4; + // Configure DMA to transfer input to hash core. + let dma_request = self.dma.request(); + let dst_ptr = T::regs().din().as_ptr(); + let mut num_words = input.len() / 4; + if input.len() % 4 > 0 { + num_words += 1; } + let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); + let dma_transfer = + unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) }; + T::regs().cr().modify(|w| w.set_dmae(true)); + + // Wait for the transfer to complete. + dma_transfer.await; } /// Save the peripheral state to a context. @@ -361,3 +348,5 @@ foreach_interrupt!( } }; ); + +dma_trait!(Dma, Instance); diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index 1fd0e87eb..a9f5aa197 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -4,27 +4,30 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::Config; -use embassy_time::{Duration, Instant}; +use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; use embassy_stm32::hash::*; use sha2::{Digest, Sha256}; -const TEST_STRING_1: &[u8] = b"hello world"; - #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let config = Config::default(); let p = embassy_stm32::init(config); + let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; + let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr"; + + let mut hw_hasher = Hash::new(p.HASH, p.DMA2_CH7); + let hw_start_time = Instant::now(); // Compute a digest in hardware. - let mut hw_hasher = Hash::new(p.HASH); - let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); - hw_hasher.update(&mut context, TEST_STRING_1); + let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8).await; + hw_hasher.update(&mut context, test_1).await; + hw_hasher.update(&mut context, test_2).await; let mut buffer: [u8; 32] = [0; 32]; - let hw_digest = hw_hasher.finish(context, &mut buffer); + let hw_digest = hw_hasher.finish(context, &mut buffer).await; let hw_end_time = Instant::now(); let hw_execution_time = hw_end_time - hw_start_time; @@ -33,7 +36,8 @@ async fn main(_spawner: Spawner) -> ! { // Compute a digest in software. let mut sw_hasher = Sha256::new(); - sw_hasher.update(TEST_STRING_1); + sw_hasher.update(test_1); + sw_hasher.update(test_2); let sw_digest = sw_hasher.finalize(); let sw_end_time = Instant::now(); From 87a52f5eadbff91ff4fe2df807aa4e7bb3b29d79 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Sat, 3 Feb 2024 17:04:20 -0600 Subject: [PATCH 363/760] stm32/usart: Add doc links to buffered uarts --- embassy-stm32/src/usart/buffered.rs | 4 ++++ embassy-stm32/src/usart/ringbuffered.rs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index c78752883..c11e3382f 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -140,11 +140,15 @@ pub struct BufferedUart<'d, T: BasicInstance> { } /// Tx-only buffered UART +/// +/// Created with [BufferedUart::split] pub struct BufferedUartTx<'d, T: BasicInstance> { phantom: PhantomData<&'d mut T>, } /// Rx-only buffered UART +/// +/// Created with [BufferedUart::split] pub struct BufferedUartRx<'d, T: BasicInstance> { phantom: PhantomData<&'d mut T>, } diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 4391bfef7..a0ab060a3 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -12,6 +12,8 @@ use crate::dma::ReadableRingBuffer; use crate::usart::{Regs, Sr}; /// Rx-only Ring-buffered UART Driver +/// +/// Created with [UartRx::into_ring_buffered] pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma> { _peri: PeripheralRef<'d, T>, ring_buf: ReadableRingBuffer<'d, RxDma, u8>, From d5d86b866fd5ceb8081cbfcce832be4c68b82691 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 4 Feb 2024 21:36:19 +0100 Subject: [PATCH 364/760] nrf/gpiote: add support for nrf51. --- ci.sh | 1 + embassy-nrf/src/gpiote.rs | 56 +++++++++++++++++++++++++------- examples/nrf51/Cargo.toml | 2 +- tests/nrf51422/Cargo.toml | 3 +- tests/nrf51422/src/bin/gpiote.rs | 47 +++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 tests/nrf51422/src/bin/gpiote.rs diff --git a/ci.sh b/ci.sh index 6a5e6e3f5..ba250fa67 100755 --- a/ci.sh +++ b/ci.sh @@ -47,6 +47,7 @@ cargo batch \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time,time-driver-rtc1 \ diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index a459446a2..12f4ed0a0 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -13,6 +13,10 @@ use crate::interrupt::InterruptExt; use crate::ppi::{Event, Task}; use crate::{interrupt, pac, peripherals}; +#[cfg(feature = "nrf51")] +/// Amount of GPIOTE channels in the chip. +const CHANNEL_COUNT: usize = 4; +#[cfg(not(feature = "_nrf51"))] /// Amount of GPIOTE channels in the chip. const CHANNEL_COUNT: usize = 8; @@ -61,16 +65,20 @@ fn regs() -> &'static pac::gpiote::RegisterBlock { } pub(crate) fn init(irq_prio: crate::interrupt::Priority) { - #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] - let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; - #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] - let ports = unsafe { &[&*pac::P0::ptr()] }; + // no latched GPIO detect in nrf51. + #[cfg(not(feature = "_nrf51"))] + { + #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] + let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; + #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840")))] + let ports = unsafe { &[&*pac::P0::ptr()] }; - for &p in ports { - // Enable latched detection - p.detectmode.write(|w| w.detectmode().ldetect()); - // Clear latch - p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) + for &p in ports { + // Enable latched detection + p.detectmode.write(|w| w.detectmode().ldetect()); + // Clear latch + p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) + } } // Enable interrupts @@ -78,7 +86,7 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { let irq = interrupt::GPIOTE0; #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] let irq = interrupt::GPIOTE1; - #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] + #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] let irq = interrupt::GPIOTE; irq.unpend(); @@ -103,7 +111,7 @@ fn GPIOTE1() { unsafe { handle_gpiote_interrupt() }; } -#[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] +#[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] #[cfg(feature = "rt")] #[interrupt] fn GPIOTE() { @@ -125,9 +133,29 @@ unsafe fn handle_gpiote_interrupt() { #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; - #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] + #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840")))] let ports = &[&*pac::P0::ptr()]; + #[cfg(feature = "_nrf51")] + let ports = unsafe { &[&*pac::GPIO::ptr()] }; + #[cfg(feature = "_nrf51")] + for (port, &p) in ports.iter().enumerate() { + let inp = p.in_.read().bits(); + for pin in 0..32 { + let fired = match p.pin_cnf[pin as usize].read().sense().variant() { + Some(pac::gpio::pin_cnf::SENSE_A::HIGH) => inp & (1 << pin) != 0, + Some(pac::gpio::pin_cnf::SENSE_A::LOW) => inp & (1 << pin) == 0, + _ => false, + }; + + if fired { + PORT_WAKERS[port * 32 + pin as usize].wake(); + p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); + } + } + } + + #[cfg(not(feature = "_nrf51"))] for (port, &p) in ports.iter().enumerate() { let bits = p.latch.read().bits(); for pin in BitIter(bits) { @@ -476,9 +504,13 @@ impl_channel!(GPIOTE_CH0, 0); impl_channel!(GPIOTE_CH1, 1); impl_channel!(GPIOTE_CH2, 2); impl_channel!(GPIOTE_CH3, 3); +#[cfg(not(feature = "nrf51"))] impl_channel!(GPIOTE_CH4, 4); +#[cfg(not(feature = "nrf51"))] impl_channel!(GPIOTE_CH5, 5); +#[cfg(not(feature = "nrf51"))] impl_channel!(GPIOTE_CH6, 6); +#[cfg(not(feature = "nrf51"))] impl_channel!(GPIOTE_CH7, 7); // ==================== diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index d1e919a33..06c3d20cb 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time", "rt"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf51422/Cargo.toml b/tests/nrf51422/Cargo.toml index 2cab20ac0..07236987b 100644 --- a/tests/nrf51422/Cargo.toml +++ b/tests/nrf51422/Cargo.toml @@ -7,10 +7,11 @@ license = "MIT OR Apache-2.0" [dependencies] teleprobe-meta = "1" +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 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", "task-arena-size-128", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time", "gpiote"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-hal-async = { version = "1.0" } diff --git a/tests/nrf51422/src/bin/gpiote.rs b/tests/nrf51422/src/bin/gpiote.rs new file mode 100644 index 000000000..330fe993e --- /dev/null +++ b/tests/nrf51422/src/bin/gpiote.rs @@ -0,0 +1,47 @@ +#![no_std] +#![no_main] +teleprobe_meta::target!(b"nrf51-dk"); + +use defmt::{assert, info}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + let mut input = Input::new(p.P0_13, Pull::Up); + let mut output = Output::new(p.P0_14, Level::Low, OutputDrive::Standard); + + let fut1 = async { + Timer::after_millis(100).await; + output.set_high(); + }; + let fut2 = async { + let start = Instant::now(); + input.wait_for_high().await; + let dur = Instant::now() - start; + assert!((Duration::from_millis(90)..Duration::from_millis(110)).contains(&dur)); + }; + + join(fut1, fut2).await; + + let fut1 = async { + Timer::after_millis(100).await; + output.set_low(); + }; + let fut2 = async { + let start = Instant::now(); + input.wait_for_low().await; + let dur = Instant::now() - start; + assert!((Duration::from_millis(90)..Duration::from_millis(110)).contains(&dur)); + }; + + join(fut1, fut2).await; + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From e3fe08428f3728e8273fcb184776a762955bb376 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 4 Feb 2024 22:07:17 +0100 Subject: [PATCH 365/760] stm32/rcc: fix build for some f0 and l4 chips. Fixes #2531 --- ci.sh | 2 ++ embassy-stm32/src/rcc/f0.rs | 32 +++++++++++++++++++++++++++----- embassy-stm32/src/rcc/l.rs | 19 ++++++++++++------- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/ci.sh b/ci.sh index 6a5e6e3f5..aa0d98d34 100755 --- a/ci.sh +++ b/ci.sh @@ -84,6 +84,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f072c8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f407zg,defmt,exti,time-driver-any \ @@ -110,6 +111,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb15cc,defmt,exti,time-driver-any,time \ diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index a6b627887..d99fd0476 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs @@ -11,14 +11,13 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000); /// /// hse takes precedence over hsi48 if both are enabled #[non_exhaustive] -#[derive(Default)] pub struct Config { pub hse: Option, pub bypass_hse: bool, pub usb_pll: bool, - #[cfg(not(stm32f0x0))] - pub hsi48: bool, + #[cfg(crs)] + pub hsi48: Option, pub sys_ck: Option, pub hclk: Option, @@ -27,12 +26,31 @@ pub struct Config { pub ls: super::LsConfig, } +impl Default for Config { + fn default() -> Self { + Self { + hse: Default::default(), + bypass_hse: Default::default(), + usb_pll: Default::default(), + hsi48: Some(Default::default()), + sys_ck: Default::default(), + hclk: Default::default(), + pclk: Default::default(), + ls: Default::default(), + } + } +} + pub(crate) unsafe fn init(config: Config) { let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI_FREQ.0); + #[cfg(crs)] + let hsi48 = config.hsi48.map(|config| super::init_hsi48(config)); + #[cfg(not(crs))] + let hsi48: Option = None; + let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| { - #[cfg(not(stm32f0x0))] - if config.hsi48 { + if hsi48.is_some() { return (48_000_000, true); } (HSI_FREQ.0, false) @@ -169,5 +187,9 @@ pub(crate) unsafe fn init(config: Config) { pclk2_tim: Some(Hertz(pclk * timer_mul)), hclk1: Some(Hertz(hclk)), rtc: rtc, + hsi48: hsi48, + + // TODO: + pll1_p: None, ); } diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index ab1681dd4..04ea81ec4 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -215,12 +215,9 @@ pub(crate) unsafe fn init(config: Config) { }); #[cfg(crs)] - let _hsi48 = config.hsi48.map(|config| { - // - super::init_hsi48(config) - }); + let hsi48 = config.hsi48.map(|config| super::init_hsi48(config)); #[cfg(not(crs))] - let _hsi48: Option = None; + let hsi48: Option = None; let _plls = [ &config.pll, @@ -274,12 +271,12 @@ pub(crate) unsafe fn init(config: Config) { RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src)); #[cfg(any(rcc_l0_v2))] let clk48 = match config.clk48_src { - Clk48Src::HSI48 => _hsi48, + Clk48Src::HSI48 => hsi48, Clk48Src::PLL1_VCO_DIV_2 => pll.clk48, }; #[cfg(any(stm32l4, stm32l5, stm32wb))] let clk48 = match config.clk48_src { - Clk48Src::HSI48 => _hsi48, + Clk48Src::HSI48 => hsi48, Clk48Src::MSI => msi, Clk48Src::PLLSAI1_Q => pllsai1.q, Clk48Src::PLL1_Q => pll.q, @@ -393,6 +390,7 @@ pub(crate) unsafe fn init(config: Config) { msi: msi, #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] clk48: clk48, + hsi48: hsi48, #[cfg(not(any(stm32l0, stm32l1)))] pll1_p: pll.p, @@ -407,6 +405,13 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32l4, stm32l5, stm32wb))] pllsai1_r: pllsai1.r, + #[cfg(not(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5)))] + pllsai2_p: None, + #[cfg(not(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5)))] + pllsai2_q: None, + #[cfg(not(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5)))] + pllsai2_r: None, + #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] pllsai2_p: pllsai2.p, #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] From 6c72638ed0c94df0b8f19ff4d6cefde8b61dfe23 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 4 Feb 2024 22:47:15 +0100 Subject: [PATCH 366/760] stm32/rcc: fix more build failures. --- ci.sh | 3 +++ embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/rcc/f0.rs | 1 + embassy-stm32/src/rcc/mod.rs | 5 ++++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index 4dc76cb69..df9e09848 100755 --- a/ci.sh +++ b/ci.sh @@ -85,6 +85,8 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f042g4,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f072c8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any \ @@ -135,6 +137,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32h503rb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32h562ag,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32wb35ce,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 c412e13d5..8f0fc1c59 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-3e3b53df78b4c90ae9c44a58b4f9f93c93a415b7" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-3e3b53df78b4c90ae9c44a58b4f9f93c93a415b7", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index d99fd0476..1042a1cb2 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs @@ -32,6 +32,7 @@ impl Default for Config { hse: Default::default(), bypass_hse: Default::default(), usb_pll: Default::default(), + #[cfg(crs)] hsi48: Some(Default::default()), sys_ck: Default::default(), hclk: Default::default(), diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 280da7ae3..05937cc5d 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -6,8 +6,11 @@ use core::mem::MaybeUninit; mod bd; -mod mco; pub use bd::*; + +#[cfg(any(mco, mco1, mco2))] +mod mco; +#[cfg(any(mco, mco1, mco2))] pub use mco::*; #[cfg(crs)] From 66f44b95d70547be8e32daac1ab611eec5fbe28a Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:16:33 -0500 Subject: [PATCH 367/760] Addressed hash CI build issues. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/hash/mod.rs | 357 +--------------------------- embassy-stm32/src/hash/v1.rs | 334 +++++++++++++++++++++++++++ embassy-stm32/src/hash/v2v3.rs | 385 +++++++++++++++++++++++++++++++ examples/stm32f7/src/bin/eth.rs | 2 +- examples/stm32f7/src/bin/hash.rs | 6 +- 6 files changed, 731 insertions(+), 357 deletions(-) create mode 100644 embassy-stm32/src/hash/v1.rs create mode 100644 embassy-stm32/src/hash/v2v3.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d8a4c65fa..00d8a5f63 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-0cb3a4fcaec702c93b3700715de796636d562b15" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-aa5dbf859fae743306f5d816905f166de824241f" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -87,7 +87,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-0cb3a4fcaec702c93b3700715de796636d562b15", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-aa5dbf859fae743306f5d816905f166de824241f", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index ac4854f80..6b23f3b55 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -1,352 +1,7 @@ -//! Hash generator (HASH) -use core::cmp::min; -use core::future::poll_fn; -use core::marker::PhantomData; -use core::ptr; -use core::task::Poll; +//! Hash Accelerator (HASH) +#[cfg_attr(hash_v1, path = "v1.rs")] +#[cfg_attr(hash_v2, path = "v2v3.rs")] +#[cfg_attr(hash_v3, path = "v2v3.rs")] +mod _version; -use embassy_hal_internal::{into_ref, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; - -use crate::dma::Transfer; -use crate::peripherals::HASH; -use stm32_metapac::hash::regs::*; - -use crate::interrupt::typelevel::Interrupt; -use crate::rcc::sealed::RccPeripheral; -use crate::{interrupt, pac, peripherals, Peripheral}; - -#[cfg(hash_v1)] -const NUM_CONTEXT_REGS: usize = 51; -#[cfg(hash_v2)] -const NUM_CONTEXT_REGS: usize = 54; -const DIGEST_BLOCK_SIZE: usize = 64; - -static HASH_WAKER: AtomicWaker = AtomicWaker::new(); - -/// HASH interrupt handler. -pub struct InterruptHandler { - _phantom: PhantomData, -} - -impl interrupt::typelevel::Handler for InterruptHandler { - unsafe fn on_interrupt() { - let bits = T::regs().sr().read(); - if bits.dinis() { - T::regs().imr().modify(|reg| reg.set_dinie(false)); - HASH_WAKER.wake(); - } - if bits.dcis() { - T::regs().imr().modify(|reg| reg.set_dcie(false)); - HASH_WAKER.wake(); - } - } -} - -///Hash algorithm selection -#[derive(PartialEq)] -pub enum Algorithm { - /// SHA-1 Algorithm - SHA1 = 0, - /// MD5 Algorithm - MD5 = 1, - #[cfg(hash_v2)] - /// SHA-224 Algorithm - SHA224 = 2, - #[cfg(hash_v2)] - /// SHA-256 Algorithm - SHA256 = 3, -} - -/// Input data width selection -#[repr(u8)] -#[derive(Clone, Copy)] -pub enum DataType { - ///32-bit data, no data is swapped. - Width32 = 0, - ///16-bit data, each half-word is swapped. - Width16 = 1, - ///8-bit data, all bytes are swapped. - Width8 = 2, - ///1-bit data, all bits are swapped. - Width1 = 3, -} - -/// Stores the state of the HASH peripheral for suspending/resuming -/// digest calculation. -pub struct Context { - buffer: [u8; DIGEST_BLOCK_SIZE], - buflen: usize, - algo: Algorithm, - format: DataType, - imr: u32, - str: u32, - cr: u32, - csr: [u32; NUM_CONTEXT_REGS], -} - -/// HASH driver. -pub struct Hash<'d, T: Instance, D: Dma> { - _peripheral: PeripheralRef<'d, T>, - dma: PeripheralRef<'d, D>, -} - -impl<'d, T: Instance, D: Dma> Hash<'d, T, D> { - /// Instantiates, resets, and enables the HASH peripheral. - pub fn new(peripheral: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { - HASH::enable_and_reset(); - into_ref!(peripheral, dma); - let instance = Self { - _peripheral: peripheral, - dma: dma, - }; - - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - instance - } - - /// Starts computation of a new hash and returns the saved peripheral state. - pub async fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { - // Define a context for this new computation. - let mut ctx = Context { - buffer: [0; DIGEST_BLOCK_SIZE], - buflen: 0, - algo: algorithm, - format: format, - imr: 0, - str: 0, - cr: 0, - csr: [0; NUM_CONTEXT_REGS], - }; - - // Set the data type in the peripheral. - T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); - - // Select the algorithm. - let mut algo0 = false; - let mut algo1 = false; - if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 { - algo0 = true; - } - if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { - algo1 = true; - } - T::regs().cr().modify(|w| w.set_algo0(algo0)); - T::regs().cr().modify(|w| w.set_algo1(algo1)); - - // Enable multiple DMA transfers. - T::regs().cr().modify(|w| w.set_mdmat(true)); - - // Set init to load the context registers. Necessary before storing context. - T::regs().cr().modify(|w| w.set_init(true)); - - // Store and return the state of the peripheral. - self.store_context(&mut ctx).await; - ctx - } - - /// Restores the peripheral state using the given context, - /// then updates the state with the provided data. - /// Peripheral state is saved upon return. - pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) { - let data_waiting = input.len() + ctx.buflen; - if data_waiting < DIGEST_BLOCK_SIZE { - // There isn't enough data to digest a block, so append it to the buffer. - ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); - ctx.buflen += input.len(); - return; - } - - // Restore the peripheral state. - self.load_context(&ctx); - - let mut ilen_remaining = input.len(); - let mut input_start = 0; - - // First ingest the data in the buffer. - let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; - if empty_len > 0 { - let copy_len = min(empty_len, ilen_remaining); - ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[input_start..input_start + copy_len]); - ctx.buflen += copy_len; - ilen_remaining -= copy_len; - input_start += copy_len; - } - self.accumulate(&ctx.buffer).await; - ctx.buflen = 0; - - // Move any extra data to the now-empty buffer. - let leftovers = ilen_remaining % DIGEST_BLOCK_SIZE; - if leftovers > 0 { - assert!(ilen_remaining >= leftovers); - ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); - ctx.buflen += leftovers; - ilen_remaining -= leftovers; - } else { - ctx.buffer - .copy_from_slice(&input[input.len() - DIGEST_BLOCK_SIZE..input.len()]); - ctx.buflen += DIGEST_BLOCK_SIZE; - ilen_remaining -= DIGEST_BLOCK_SIZE; - } - - // Hash the remaining data. - self.accumulate(&input[input_start..input_start + ilen_remaining]).await; - - // Save the peripheral context. - self.store_context(ctx).await; - } - - /// Computes a digest for the given context. A slice of the provided digest buffer is returned. - /// The length of the returned slice is dependent on the digest length of the selected algorithm. - pub async fn finish<'a>(&mut self, mut ctx: Context, digest: &'a mut [u8; 32]) -> &'a [u8] { - // Restore the peripheral state. - self.load_context(&ctx); - - // Must be cleared prior to the last DMA transfer. - T::regs().cr().modify(|w| w.set_mdmat(false)); - - // Hash the leftover bytes, if any. - self.accumulate(&ctx.buffer[0..ctx.buflen]).await; - ctx.buflen = 0; - - // Wait for completion. - poll_fn(|cx| { - // Check if already done. - let bits = T::regs().sr().read(); - if bits.dcis() { - return Poll::Ready(()); - } - // Register waker, then enable interrupts. - HASH_WAKER.register(cx.waker()); - T::regs().imr().modify(|reg| reg.set_dinie(true)); - // Check for completion. - let bits = T::regs().sr().read(); - if bits.dcis() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - - // Return the digest. - let digest_words = match ctx.algo { - Algorithm::SHA1 => 5, - Algorithm::MD5 => 4, - Algorithm::SHA224 => 7, - Algorithm::SHA256 => 8, - }; - let mut i = 0; - while i < digest_words { - let word = T::regs().hr(i).read(); - digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); - i += 1; - } - &digest[0..digest_words * 4] - } - - /// Push data into the hash core. - async fn accumulate(&mut self, input: &[u8]) { - // Ignore an input length of 0. - if input.len() == 0 { - return; - } - - // Set the number of valid bits. - let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; - T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); - - // Configure DMA to transfer input to hash core. - let dma_request = self.dma.request(); - let dst_ptr = T::regs().din().as_ptr(); - let mut num_words = input.len() / 4; - if input.len() % 4 > 0 { - num_words += 1; - } - let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); - let dma_transfer = - unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) }; - T::regs().cr().modify(|w| w.set_dmae(true)); - - // Wait for the transfer to complete. - dma_transfer.await; - } - - /// Save the peripheral state to a context. - async fn store_context(&mut self, ctx: &mut Context) { - // Wait for interrupt. - poll_fn(|cx| { - // Check if already done. - let bits = T::regs().sr().read(); - if bits.dinis() { - return Poll::Ready(()); - } - // Register waker, then enable interrupts. - HASH_WAKER.register(cx.waker()); - T::regs().imr().modify(|reg| reg.set_dinie(true)); - // Check for completion. - let bits = T::regs().sr().read(); - if bits.dinis() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - - ctx.imr = T::regs().imr().read().0; - ctx.str = T::regs().str().read().0; - ctx.cr = T::regs().cr().read().0; - let mut i = 0; - while i < NUM_CONTEXT_REGS { - ctx.csr[i] = T::regs().csr(i).read(); - i += 1; - } - } - - /// Restore the peripheral state from a context. - fn load_context(&mut self, ctx: &Context) { - // Restore the peripheral state from the context. - T::regs().imr().write_value(Imr { 0: ctx.imr }); - T::regs().str().write_value(Str { 0: ctx.str }); - T::regs().cr().write_value(Cr { 0: ctx.cr }); - T::regs().cr().modify(|w| w.set_init(true)); - let mut i = 0; - while i < NUM_CONTEXT_REGS { - T::regs().csr(i).write_value(ctx.csr[i]); - i += 1; - } - } -} - -pub(crate) mod sealed { - use super::*; - - pub trait Instance { - fn regs() -> pac::hash::Hash; - } -} - -/// HASH instance trait. -pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { - /// Interrupt for this HASH instance. - type Interrupt: interrupt::typelevel::Interrupt; -} - -foreach_interrupt!( - ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => { - impl Instance for peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$irq; - } - - impl sealed::Instance for peripherals::$inst { - fn regs() -> crate::pac::hash::Hash { - crate::pac::$inst - } - } - }; -); - -dma_trait!(Dma, Instance); +pub use _version::*; diff --git a/embassy-stm32/src/hash/v1.rs b/embassy-stm32/src/hash/v1.rs new file mode 100644 index 000000000..50f9adc83 --- /dev/null +++ b/embassy-stm32/src/hash/v1.rs @@ -0,0 +1,334 @@ +//! Hash generator (HASH) +use core::cmp::min; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +use stm32_metapac::hash::regs::*; + +use crate::interrupt::typelevel::Interrupt; +use crate::peripherals::HASH; +use crate::rcc::sealed::RccPeripheral; +use crate::{interrupt, pac, peripherals, Peripheral}; + +const NUM_CONTEXT_REGS: usize = 51; +const HASH_BUFFER_LEN: usize = 68; +const DIGEST_BLOCK_SIZE: usize = 64; +const MAX_DIGEST_SIZE: usize = 20; + +static HASH_WAKER: AtomicWaker = AtomicWaker::new(); + +/// HASH interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let bits = T::regs().sr().read(); + if bits.dinis() { + T::regs().imr().modify(|reg| reg.set_dinie(false)); + HASH_WAKER.wake(); + } + if bits.dcis() { + T::regs().imr().modify(|reg| reg.set_dcie(false)); + HASH_WAKER.wake(); + } + } +} + +///Hash algorithm selection +#[derive(PartialEq)] +pub enum Algorithm { + /// SHA-1 Algorithm + SHA1 = 0, + /// MD5 Algorithm + MD5 = 1, +} + +/// Input data width selection +#[repr(u8)] +#[derive(Clone, Copy)] +pub enum DataType { + ///32-bit data, no data is swapped. + Width32 = 0, + ///16-bit data, each half-word is swapped. + Width16 = 1, + ///8-bit data, all bytes are swapped. + Width8 = 2, + ///1-bit data, all bits are swapped. + Width1 = 3, +} + +/// Stores the state of the HASH peripheral for suspending/resuming +/// digest calculation. +pub struct Context { + first_word_sent: bool, + buffer: [u8; HASH_BUFFER_LEN], + buflen: usize, + algo: Algorithm, + format: DataType, + imr: u32, + str: u32, + cr: u32, + csr: [u32; NUM_CONTEXT_REGS], +} + +/// HASH driver. +pub struct Hash<'d, T: Instance> { + _peripheral: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Hash<'d, T> { + /// Instantiates, resets, and enables the HASH peripheral. + pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { + HASH::enable_and_reset(); + into_ref!(peripheral); + let instance = Self { + _peripheral: peripheral, + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + instance + } + + /// Starts computation of a new hash and returns the saved peripheral state. + pub async fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { + // Define a context for this new computation. + let mut ctx = Context { + first_word_sent: false, + buffer: [0; HASH_BUFFER_LEN], + buflen: 0, + algo: algorithm, + format: format, + imr: 0, + str: 0, + cr: 0, + csr: [0; NUM_CONTEXT_REGS], + }; + + // Set the data type in the peripheral. + T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); + + // Select the algorithm. + if ctx.algo == Algorithm::MD5 { + T::regs().cr().modify(|w| w.set_algo(true)); + } + + // Store and return the state of the peripheral. + self.store_context(&mut ctx).await; + ctx + } + + /// Restores the peripheral state using the given context, + /// then updates the state with the provided data. + /// Peripheral state is saved upon return. + pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) { + let mut data_waiting = input.len() + ctx.buflen; + if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) { + // There isn't enough data to digest a block, so append it to the buffer. + ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); + ctx.buflen += input.len(); + return; + } + + // Restore the peripheral state. + self.load_context(&ctx); + + let mut ilen_remaining = input.len(); + let mut input_start = 0; + + // Handle first block. + if !ctx.first_word_sent { + let empty_len = ctx.buffer.len() - ctx.buflen; + let copy_len = min(empty_len, ilen_remaining); + // Fill the buffer. + if copy_len > 0 { + ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[0..copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; + } + self.accumulate(ctx.buffer.as_slice()); + data_waiting -= ctx.buflen; + ctx.buflen = 0; + ctx.first_word_sent = true; + } + + if data_waiting < DIGEST_BLOCK_SIZE { + // There isn't enough data remaining to process another block, so store it. + ctx.buffer[0..ilen_remaining].copy_from_slice(&input[input_start..input_start + ilen_remaining]); + ctx.buflen += ilen_remaining; + } else { + // First ingest the data in the buffer. + let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; + if empty_len > 0 { + let copy_len = min(empty_len, ilen_remaining); + ctx.buffer[ctx.buflen..ctx.buflen + copy_len] + .copy_from_slice(&input[input_start..input_start + copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; + } + self.accumulate(&ctx.buffer[0..64]); + ctx.buflen = 0; + + // Move any extra data to the now-empty buffer. + let leftovers = ilen_remaining % 64; + if leftovers > 0 { + ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); + ctx.buflen += leftovers; + ilen_remaining -= leftovers; + } + + // Hash the remaining data. + self.accumulate(&input[input_start..input_start + ilen_remaining]); + } + + // Save the peripheral context. + self.store_context(ctx).await; + } + + /// Computes a digest for the given context. A slice of the provided digest buffer is returned. + /// The length of the returned slice is dependent on the digest length of the selected algorithm. + pub async fn finish<'a>(&mut self, mut ctx: Context, digest: &'a mut [u8; MAX_DIGEST_SIZE]) -> &'a [u8] { + // Restore the peripheral state. + self.load_context(&ctx); + + // Hash the leftover bytes, if any. + self.accumulate(&ctx.buffer[0..ctx.buflen]); + ctx.buflen = 0; + + //Start the digest calculation. + T::regs().str().write(|w| w.set_dcal(true)); + + // Wait for completion. + poll_fn(|cx| { + // Check if already done. + let bits = T::regs().sr().read(); + if bits.dcis() { + return Poll::Ready(()); + } + // Register waker, then enable interrupts. + HASH_WAKER.register(cx.waker()); + T::regs().imr().modify(|reg| reg.set_dinie(true)); + // Check for completion. + let bits = T::regs().sr().read(); + if bits.dcis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + // Return the digest. + let digest_words = match ctx.algo { + Algorithm::SHA1 => 5, + Algorithm::MD5 => 4, + }; + let mut i = 0; + while i < digest_words { + let word = T::regs().hr(i).read(); + digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); + i += 1; + } + &digest[0..digest_words * 4] + } + + /// Push data into the hash core. + fn accumulate(&mut self, input: &[u8]) { + // Set the number of valid bits. + let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; + T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); + + let mut i = 0; + while i < input.len() { + let mut word: [u8; 4] = [0; 4]; + let copy_idx = min(i + 4, input.len()); + word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); + T::regs().din().write_value(u32::from_ne_bytes(word)); + i += 4; + } + } + + /// Save the peripheral state to a context. + async fn store_context(&mut self, ctx: &mut Context) { + // Wait for interrupt. + poll_fn(|cx| { + // Check if already done. + let bits = T::regs().sr().read(); + if bits.dinis() { + return Poll::Ready(()); + } + // Register waker, then enable interrupts. + HASH_WAKER.register(cx.waker()); + T::regs().imr().modify(|reg| reg.set_dinie(true)); + // Check for completion. + let bits = T::regs().sr().read(); + if bits.dinis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + ctx.imr = T::regs().imr().read().0; + ctx.str = T::regs().str().read().0; + ctx.cr = T::regs().cr().read().0; + let mut i = 0; + while i < NUM_CONTEXT_REGS { + ctx.csr[i] = T::regs().csr(i).read(); + i += 1; + } + } + + /// Restore the peripheral state from a context. + fn load_context(&mut self, ctx: &Context) { + // Restore the peripheral state from the context. + T::regs().imr().write_value(Imr { 0: ctx.imr }); + T::regs().str().write_value(Str { 0: ctx.str }); + T::regs().cr().write_value(Cr { 0: ctx.cr }); + T::regs().cr().modify(|w| w.set_init(true)); + let mut i = 0; + while i < NUM_CONTEXT_REGS { + T::regs().csr(i).write_value(ctx.csr[i]); + i += 1; + } + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Instance { + fn regs() -> pac::hash::Hash; + } +} + +/// HASH instance trait. +pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { + /// Interrupt for this HASH instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +foreach_interrupt!( + ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => { + impl Instance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + + impl sealed::Instance for peripherals::$inst { + fn regs() -> crate::pac::hash::Hash { + crate::pac::$inst + } + } + }; +); + +dma_trait!(Dma, Instance); diff --git a/embassy-stm32/src/hash/v2v3.rs b/embassy-stm32/src/hash/v2v3.rs new file mode 100644 index 000000000..058864568 --- /dev/null +++ b/embassy-stm32/src/hash/v2v3.rs @@ -0,0 +1,385 @@ +//! Hash generator (HASH) +use core::cmp::min; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::ptr; +use core::task::Poll; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +use stm32_metapac::hash::regs::*; + +use crate::dma::Transfer; +use crate::interrupt::typelevel::Interrupt; +use crate::peripherals::HASH; +use crate::rcc::sealed::RccPeripheral; +use crate::{interrupt, pac, peripherals, Peripheral}; + +#[cfg(hash_v2)] +const NUM_CONTEXT_REGS: usize = 54; +#[cfg(hash_v3)] +const NUM_CONTEXT_REGS: usize = 103; +const DIGEST_BLOCK_SIZE: usize = 64; +const MAX_DIGEST_SIZE: usize = 64; + +static HASH_WAKER: AtomicWaker = AtomicWaker::new(); + +/// HASH interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let bits = T::regs().sr().read(); + if bits.dinis() { + T::regs().imr().modify(|reg| reg.set_dinie(false)); + HASH_WAKER.wake(); + } + if bits.dcis() { + T::regs().imr().modify(|reg| reg.set_dcie(false)); + HASH_WAKER.wake(); + } + } +} + +///Hash algorithm selection +#[derive(Clone, Copy, PartialEq)] +pub enum Algorithm { + /// SHA-1 Algorithm + SHA1 = 0, + + #[cfg(hash_v2)] + /// MD5 Algorithm + MD5 = 1, + + /// SHA-224 Algorithm + SHA224 = 2, + + /// SHA-256 Algorithm + SHA256 = 3, + + #[cfg(hash_v3)] + /// SHA-384 Algorithm + SHA384 = 12, + + #[cfg(hash_v3)] + /// SHA-512/224 Algorithm + SHA512_224 = 13, + + #[cfg(hash_v3)] + /// SHA-512/256 Algorithm + SHA512_256 = 14, + + #[cfg(hash_v3)] + /// SHA-256 Algorithm + SHA512 = 15, +} + +/// Input data width selection +#[repr(u8)] +#[derive(Clone, Copy)] +pub enum DataType { + ///32-bit data, no data is swapped. + Width32 = 0, + ///16-bit data, each half-word is swapped. + Width16 = 1, + ///8-bit data, all bytes are swapped. + Width8 = 2, + ///1-bit data, all bits are swapped. + Width1 = 3, +} + +/// Stores the state of the HASH peripheral for suspending/resuming +/// digest calculation. +pub struct Context { + buffer: [u8; DIGEST_BLOCK_SIZE], + buflen: usize, + algo: Algorithm, + format: DataType, + imr: u32, + str: u32, + cr: u32, + csr: [u32; NUM_CONTEXT_REGS], +} + +/// HASH driver. +pub struct Hash<'d, T: Instance, D: Dma> { + _peripheral: PeripheralRef<'d, T>, + dma: PeripheralRef<'d, D>, +} + +impl<'d, T: Instance, D: Dma> Hash<'d, T, D> { + /// Instantiates, resets, and enables the HASH peripheral. + pub fn new(peripheral: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { + HASH::enable_and_reset(); + into_ref!(peripheral, dma); + let instance = Self { + _peripheral: peripheral, + dma: dma, + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + instance + } + + /// Starts computation of a new hash and returns the saved peripheral state. + pub async fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { + // Define a context for this new computation. + let mut ctx = Context { + buffer: [0; DIGEST_BLOCK_SIZE], + buflen: 0, + algo: algorithm, + format: format, + imr: 0, + str: 0, + cr: 0, + csr: [0; NUM_CONTEXT_REGS], + }; + + // Set the data type in the peripheral. + T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); + + #[cfg(hash_v2)] + { + // Select the algorithm. + let mut algo0 = false; + let mut algo1 = false; + if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 { + algo0 = true; + } + if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { + algo1 = true; + } + T::regs().cr().modify(|w| w.set_algo0(algo0)); + T::regs().cr().modify(|w| w.set_algo1(algo1)); + } + + #[cfg(hash_v3)] + T::regs().cr().modify(|w| w.set_algo(ctx.algo as u8)); + + // Enable multiple DMA transfers. + T::regs().cr().modify(|w| w.set_mdmat(true)); + + // Set init to load the context registers. Necessary before storing context. + T::regs().cr().modify(|w| w.set_init(true)); + + // Store and return the state of the peripheral. + self.store_context(&mut ctx).await; + ctx + } + + /// Restores the peripheral state using the given context, + /// then updates the state with the provided data. + /// Peripheral state is saved upon return. + pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) { + let data_waiting = input.len() + ctx.buflen; + if data_waiting < DIGEST_BLOCK_SIZE { + // There isn't enough data to digest a block, so append it to the buffer. + ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); + ctx.buflen += input.len(); + return; + } + + // Restore the peripheral state. + self.load_context(&ctx); + + let mut ilen_remaining = input.len(); + let mut input_start = 0; + + // First ingest the data in the buffer. + let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; + if empty_len > 0 { + let copy_len = min(empty_len, ilen_remaining); + ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[input_start..input_start + copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; + } + self.accumulate(&ctx.buffer).await; + ctx.buflen = 0; + + // Move any extra data to the now-empty buffer. + let leftovers = ilen_remaining % DIGEST_BLOCK_SIZE; + if leftovers > 0 { + assert!(ilen_remaining >= leftovers); + ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); + ctx.buflen += leftovers; + ilen_remaining -= leftovers; + } else { + ctx.buffer + .copy_from_slice(&input[input.len() - DIGEST_BLOCK_SIZE..input.len()]); + ctx.buflen += DIGEST_BLOCK_SIZE; + ilen_remaining -= DIGEST_BLOCK_SIZE; + } + + // Hash the remaining data. + self.accumulate(&input[input_start..input_start + ilen_remaining]).await; + + // Save the peripheral context. + self.store_context(ctx).await; + } + + /// Computes a digest for the given context. A slice of the provided digest buffer is returned. + /// The length of the returned slice is dependent on the digest length of the selected algorithm. + pub async fn finish<'a>(&mut self, mut ctx: Context, digest: &'a mut [u8; MAX_DIGEST_SIZE]) -> &'a [u8] { + // Restore the peripheral state. + self.load_context(&ctx); + + // Must be cleared prior to the last DMA transfer. + T::regs().cr().modify(|w| w.set_mdmat(false)); + + // Hash the leftover bytes, if any. + self.accumulate(&ctx.buffer[0..ctx.buflen]).await; + ctx.buflen = 0; + + // Wait for completion. + poll_fn(|cx| { + // Check if already done. + let bits = T::regs().sr().read(); + if bits.dcis() { + return Poll::Ready(()); + } + // Register waker, then enable interrupts. + HASH_WAKER.register(cx.waker()); + T::regs().imr().modify(|reg| reg.set_dinie(true)); + // Check for completion. + let bits = T::regs().sr().read(); + if bits.dcis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + // Return the digest. + let digest_words = match ctx.algo { + Algorithm::SHA1 => 5, + #[cfg(hash_v2)] + Algorithm::MD5 => 4, + Algorithm::SHA224 => 7, + Algorithm::SHA256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA384 => 12, + #[cfg(hash_v3)] + Algorithm::SHA512_224 => 7, + #[cfg(hash_v3)] + Algorithm::SHA512_256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA512 => 16, + }; + let mut i = 0; + while i < digest_words { + let word = T::regs().hr(i).read(); + digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); + i += 1; + } + &digest[0..digest_words * 4] + } + + /// Push data into the hash core. + async fn accumulate(&mut self, input: &[u8]) { + // Ignore an input length of 0. + if input.len() == 0 { + return; + } + + // Set the number of valid bits. + let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; + T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); + + // Configure DMA to transfer input to hash core. + let dma_request = self.dma.request(); + let dst_ptr = T::regs().din().as_ptr(); + let mut num_words = input.len() / 4; + if input.len() % 4 > 0 { + num_words += 1; + } + let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); + let dma_transfer = + unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) }; + T::regs().cr().modify(|w| w.set_dmae(true)); + + // Wait for the transfer to complete. + dma_transfer.await; + } + + /// Save the peripheral state to a context. + async fn store_context(&mut self, ctx: &mut Context) { + // Wait for interrupt. + poll_fn(|cx| { + // Check if already done. + let bits = T::regs().sr().read(); + if bits.dinis() { + return Poll::Ready(()); + } + // Register waker, then enable interrupts. + HASH_WAKER.register(cx.waker()); + T::regs().imr().modify(|reg| reg.set_dinie(true)); + // Check for completion. + let bits = T::regs().sr().read(); + if bits.dinis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + ctx.imr = T::regs().imr().read().0; + ctx.str = T::regs().str().read().0; + ctx.cr = T::regs().cr().read().0; + let mut i = 0; + while i < NUM_CONTEXT_REGS { + ctx.csr[i] = T::regs().csr(i).read(); + i += 1; + } + } + + /// Restore the peripheral state from a context. + fn load_context(&mut self, ctx: &Context) { + // Restore the peripheral state from the context. + T::regs().imr().write_value(Imr { 0: ctx.imr }); + T::regs().str().write_value(Str { 0: ctx.str }); + T::regs().cr().write_value(Cr { 0: ctx.cr }); + T::regs().cr().modify(|w| w.set_init(true)); + let mut i = 0; + while i < NUM_CONTEXT_REGS { + T::regs().csr(i).write_value(ctx.csr[i]); + i += 1; + } + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Instance { + fn regs() -> pac::hash::Hash; + } +} + +/// HASH instance trait. +pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { + /// Interrupt for this HASH instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +foreach_interrupt!( + ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => { + impl Instance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + + impl sealed::Instance for peripherals::$inst { + fn regs() -> crate::pac::hash::Hash { + crate::pac::$inst + } + } + }; +); + +dma_trait!(Dma, Instance); diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 5bff48197..9a608e909 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { ETH => eth::InterruptHandler; - RNG => rng::InterruptHandler; + HASH_RNG => rng::InterruptHandler; }); type Device = Ethernet<'static, ETH, GenericSMI>; diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index a9f5aa197..cf52cea5c 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -3,12 +3,12 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::hash::*; use embassy_stm32::Config; use embassy_time::Instant; -use {defmt_rtt as _, panic_probe as _}; -use embassy_stm32::hash::*; use sha2::{Digest, Sha256}; +use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { @@ -26,7 +26,7 @@ async fn main(_spawner: Spawner) -> ! { let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8).await; hw_hasher.update(&mut context, test_1).await; hw_hasher.update(&mut context, test_2).await; - let mut buffer: [u8; 32] = [0; 32]; + let mut buffer: [u8; 64] = [0; 64]; let hw_digest = hw_hasher.finish(context, &mut buffer).await; let hw_end_time = Instant::now(); From a260c0a701b0385691b57a22a19d86d7ce4788b8 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:21:16 -0500 Subject: [PATCH 368/760] Format hash example. --- examples/stm32f7/src/bin/hash.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index cf52cea5c..4bd9b4e2e 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -6,7 +6,6 @@ use embassy_executor::Spawner; use embassy_stm32::hash::*; use embassy_stm32::Config; use embassy_time::Instant; - use sha2::{Digest, Sha256}; use {defmt_rtt as _, panic_probe as _}; From 7817c8b17c2a65e799fb3f64e5e3a703ad4ace33 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 5 Feb 2024 09:10:53 +0100 Subject: [PATCH 369/760] docs: fix bullet point indentation --- docs/modules/ROOT/pages/embassy_in_the_wild.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc index dfe9fd6e3..85ad7f4a2 100644 --- a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc +++ b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc @@ -8,4 +8,4 @@ Here are known examples of real-world projects which make use of Embassy. Feel f ** Targets the ESP32-S3 or ESP32-C6 MCU * The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL ** link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] -* Targets nRF52 and uses nrf-softdevice +*** Targets nRF52 and uses nrf-softdevice From 079bb7b4901b3fa6787c2ca5d8c022de3533ad8c Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:36:02 -0500 Subject: [PATCH 370/760] Added STM32 hash test. --- tests/stm32/Cargo.toml | 23 ++++++++----- tests/stm32/src/bin/hash.rs | 66 +++++++++++++++++++++++++++++++++++++ tests/stm32/src/common.rs | 7 ++++ 3 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 tests/stm32/src/bin/hash.rs diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index cb1bd9a50..d02f1a253 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -15,22 +15,23 @@ stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma" stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] -stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] -stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"] -stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"] +stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] +stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash"] +stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash"] stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] -stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng"] +stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] -stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng"] -stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng"] -stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] +stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] +stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] +stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] -stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng"] +stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] +hash = [] eth = ["embassy-executor/task-arena-size-16384"] rng = [] sdmmc = [] @@ -74,6 +75,7 @@ static_cell = "2" portable-atomic = { version = "1.5", features = [] } chrono = { version = "^0.4", default-features = false, optional = true} +sha2 = { version = "0.10.8", default-features = false } # BEGIN TESTS # Generated by gen_test.py. DO NOT EDIT. @@ -107,6 +109,11 @@ name = "gpio" path = "src/bin/gpio.rs" required-features = [] +[[bin]] +name = "hash" +path = "src/bin/hash.rs" +required-features = [ "hash",] + [[bin]] name = "rng" path = "src/bin/rng.rs" diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs new file mode 100644 index 000000000..60a60b0f1 --- /dev/null +++ b/tests/stm32/src/bin/hash.rs @@ -0,0 +1,66 @@ +// required-features: hash +#![no_std] +#![no_main] + +#[path = "../common.rs"] +mod common; +use common::*; +use embassy_executor::Spawner; +use embassy_stm32::hash::*; +use embassy_stm32::{bind_interrupts, peripherals, hash}; +use sha2::{Digest, Sha224, Sha256}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + HASH_RNG => hash::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); + let dma = peri!(p, HASH_DMA); + let mut hw_hasher = Hash::new(p.HASH, dma); + + let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; + let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr"; + let test_3: &[u8] = b"a.ewtkluGWEBR.KAJRBTA,RMNRBG,FDMGB.kger.tkasjrbt.akrjtba.krjtba.ktmyna,nmbvtyliasd;gdrtba,sfvs.kgjzshd.gkbsr.tksejb.SDkfBSE.gkfgb>ESkfbSE>gkJSBESE>kbSE>fk"; + + // Start an SHA-256 digest. + let mut sha256context = hw_hasher.start(Algorithm::SHA256, DataType::Width8).await; + hw_hasher.update(&mut sha256context, test_1).await; + + // Interrupt the SHA-256 digest to compute an SHA-224 digest. + let mut sha224context = hw_hasher.start(Algorithm::SHA224, DataType::Width8).await; + hw_hasher.update(&mut sha224context, test_3).await; + let mut sha224_digest_buffer: [u8; 64] = [0; 64]; + let sha224_digest = hw_hasher.finish(sha224context, &mut sha224_digest_buffer).await; + + // Finish the SHA-256 digest. + hw_hasher.update(&mut sha256context, test_2).await; + let mut sha_256_digest_buffer: [u8; 64] = [0; 64]; + let sha256_digest = hw_hasher.finish(sha256context, &mut sha_256_digest_buffer).await; + + // Compute the SHA-256 digest in software. + let mut sw_sha256_hasher = Sha256::new(); + sw_sha256_hasher.update(test_1); + sw_sha256_hasher.update(test_2); + let sw_sha256_digest = sw_sha256_hasher.finalize(); + + //Compute the SHA-224 digest in software. + let mut sw_sha224_hasher = Sha224::new(); + sw_sha224_hasher.update(test_3); + let sw_sha224_digest = sw_sha224_hasher.finalize(); + + // Compare the SHA-256 digests. + info!("Hardware SHA-256 Digest: {:?}", sha256_digest); + info!("Software SHA-256 Digest: {:?}", sw_sha256_digest[..]); + defmt::assert!(*sha256_digest == sw_sha256_digest[..]); + + // Compare the SHA-224 digests. + info!("Hardware SHA-256 Digest: {:?}", sha224_digest); + info!("Software SHA-256 Digest: {:?}", sw_sha224_digest[..]); + defmt::assert!(*sha224_digest == sw_sha224_digest[..]); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index fefe72c86..7e7915b2e 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -128,6 +128,7 @@ define_peris!( ); #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] define_peris!( + HASH_DMA = DMA1_CH0, UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, ADC = ADC1, DAC = DAC1, DAC_PIN = PA4, @@ -141,18 +142,21 @@ define_peris!( ); #[cfg(feature = "stm32u585ai")] define_peris!( + HASH_DMA = GPDMA1_CH0, UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, SPI = SPI1, SPI_SCK = PE13, SPI_MOSI = PE15, SPI_MISO = PE14, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, ); #[cfg(feature = "stm32u5a5zj")] define_peris!( + HASH_DMA = GPDMA1_CH0, UART = LPUART1, UART_TX = PG7, UART_RX = PG8, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, ); #[cfg(feature = "stm32h563zi")] define_peris!( + HASH_DMA = GPDMA1_CH0, UART = LPUART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, SPI = SPI4, SPI_SCK = PE12, SPI_MOSI = PE14, SPI_MISO = PE13, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, @@ -171,6 +175,7 @@ define_peris!( ); #[cfg(feature = "stm32l4a6zg")] define_peris!( + HASH_DMA = DMA2_CH7, UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, @@ -196,6 +201,7 @@ define_peris!( ); #[cfg(feature = "stm32l552ze")] define_peris!( + HASH_DMA = DMA1_CH0, UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, @@ -226,6 +232,7 @@ define_peris!( ); #[cfg(feature = "stm32wba52cg")] define_peris!( + HASH_DMA = GPDMA1_CH0, UART = LPUART1, UART_TX = PB5, UART_RX = PA10, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, SPI = SPI1, SPI_SCK = PB4, SPI_MOSI = PA15, SPI_MISO = PB3, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, From 09973ad4827222251a46cb7b1f48841245b54709 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:44:50 -0500 Subject: [PATCH 371/760] Corrected hash CI build issues. --- tests/stm32/src/bin/hash.rs | 4 ++-- tests/stm32/src/common.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index 60a60b0f1..05b61a10c 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -7,7 +7,7 @@ mod common; use common::*; use embassy_executor::Spawner; use embassy_stm32::hash::*; -use embassy_stm32::{bind_interrupts, peripherals, hash}; +use embassy_stm32::{bind_interrupts, hash, peripherals}; use sha2::{Digest, Sha224, Sha256}; use {defmt_rtt as _, panic_probe as _}; @@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) { hw_hasher.update(&mut sha256context, test_2).await; let mut sha_256_digest_buffer: [u8; 64] = [0; 64]; let sha256_digest = hw_hasher.finish(sha256context, &mut sha_256_digest_buffer).await; - + // Compute the SHA-256 digest in software. let mut sw_sha256_hasher = Sha256::new(); sw_sha256_hasher.update(test_1); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 7e7915b2e..14d5b6d7b 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -201,7 +201,7 @@ define_peris!( ); #[cfg(feature = "stm32l552ze")] define_peris!( - HASH_DMA = DMA1_CH0, + HASH_DMA = DMA1_CH1, UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, From 0b70d67bf645708c6681220c4f1c2e3ffb69dc35 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:54:17 -0500 Subject: [PATCH 372/760] Separated hash interrupt bindings. --- tests/stm32/src/bin/hash.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index 05b61a10c..53dd0551f 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -11,10 +11,26 @@ use embassy_stm32::{bind_interrupts, hash, peripherals}; use sha2::{Digest, Sha224, Sha256}; use {defmt_rtt as _, panic_probe as _}; +#[cfg(any( + feature = "stm32l4a6zg", + feature = "stm32h755zi", + feature = "stm32h753zi" +))] bind_interrupts!(struct Irqs { HASH_RNG => hash::InterruptHandler; }); +#[cfg(any( + feature = "stm32wba52cg", + feature = "stm32l552ze", + feature = "stm32h563zi", + feature = "stm32u5a5zj", + feature = "stm32u585ai" +))] +bind_interrupts!(struct Irqs { + HASH => hash::InterruptHandler; + }); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); From 2575f597cc3aafeb9925511b12adf30f6a67bccb Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Mon, 5 Feb 2024 18:05:59 -0500 Subject: [PATCH 373/760] Address @Dirbaio's comments --- embassy-nrf/src/uarte.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index f29b5061b..de2966ba5 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -66,18 +66,16 @@ bitflags::bitflags! { } } -impl TryFrom for () { - type Error = Error; - +impl ErrorSource { #[inline] - fn try_from(errors: ErrorSource) -> Result { - if errors.contains(ErrorSource::OVERRUN) { + fn check(self) -> Result<(), Error> { + if self.contains(ErrorSource::OVERRUN) { Err(Error::Overrun) - } else if errors.contains(ErrorSource::PARITY) { + } else if self.contains(ErrorSource::PARITY) { Err(Error::Parity) - } else if errors.contains(ErrorSource::FRAMING) { + } else if self.contains(ErrorSource::FRAMING) { Err(Error::Framing) - } else if errors.contains(ErrorSource::BREAK) { + } else if self.contains(ErrorSource::BREAK) { Err(Error::Break) } else { Ok(()) @@ -539,7 +537,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { let r = T::regs(); let err_bits = r.errorsrc.read().bits(); r.errorsrc.write(|w| unsafe { w.bits(err_bits) }); - ErrorSource::from_bits_truncate(err_bits).try_into() + ErrorSource::from_bits_truncate(err_bits).check() } fn new_inner( @@ -677,6 +675,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { s.endrx_waker.register(cx.waker()); if let Err(e) = self.check_and_clear_errors() { + r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); return Poll::Ready(Err(e)); } if r.events_endrx.read().bits() != 0 { @@ -823,6 +822,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { s.endrx_waker.register(cx.waker()); if let Err(e) = self.rx.check_and_clear_errors() { + r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); return Poll::Ready(Err(e)); } if r.events_endrx.read().bits() != 0 { From e72cc9fb24340ddf1151078779b3f00de9bff3ab Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Tue, 23 Jan 2024 16:33:47 +0100 Subject: [PATCH 374/760] fix(stm32/h7): use correct unit in vco clock check --- embassy-stm32/src/rcc/h.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 9ac2115f0..352e10816 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -721,7 +721,7 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) { Pllvcosel::WIDEVCO } else { - panic!("pll vco_clk out of range: {} mhz", vco_clk.0) + panic!("pll vco_clk out of range: {} hz", vco_clk.0) }; let p = config.divp.map(|div| { From aab5da1d3bfe10966bef88217492870b4148b28f Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Tue, 6 Feb 2024 12:30:04 +0100 Subject: [PATCH 375/760] fix(stm32h7/flash): enhance resilience to program sequence errors (pgserr) --- embassy-stm32/src/flash/h7.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index ae395d568..743925e17 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -77,12 +77,12 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) } } - bank.cr().write(|w| w.set_pg(false)); - cortex_m::asm::isb(); cortex_m::asm::dsb(); fence(Ordering::SeqCst); + bank.cr().write(|w| w.set_pg(false)); + res.unwrap() } @@ -100,6 +100,10 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_start(true); }); + cortex_m::asm::isb(); + cortex_m::asm::dsb(); + fence(Ordering::SeqCst); + let ret: Result<(), Error> = blocking_wait_ready(bank); bank.cr().modify(|w| w.set_ser(false)); bank_clear_all_err(bank); From c267cb9ab764176bc8514535f4db8ac2331e30ce Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Tue, 6 Feb 2024 16:25:45 +0100 Subject: [PATCH 376/760] feat: enhance bootloader for multiple flash support --- embassy-boot/src/boot_loader.rs | 20 ++++--- embassy-boot/src/firmware_updater/asynch.rs | 13 +++-- embassy-boot/src/firmware_updater/blocking.rs | 14 +++-- .../bootloader/stm32-dual-bank/Cargo.toml | 57 +++++++++++++++++++ .../boot/bootloader/stm32-dual-bank/README.md | 44 ++++++++++++++ .../boot/bootloader/stm32-dual-bank/build.rs | 27 +++++++++ .../boot/bootloader/stm32-dual-bank/memory.x | 18 ++++++ .../bootloader/stm32-dual-bank/src/main.rs | 53 +++++++++++++++++ examples/boot/bootloader/stm32/src/main.rs | 2 +- .../boot/bootloader/stm32wb-dfu/src/main.rs | 4 +- 10 files changed, 231 insertions(+), 21 deletions(-) create mode 100644 examples/boot/bootloader/stm32-dual-bank/Cargo.toml create mode 100644 examples/boot/bootloader/stm32-dual-bank/README.md create mode 100644 examples/boot/bootloader/stm32-dual-bank/build.rs create mode 100644 examples/boot/bootloader/stm32-dual-bank/memory.x create mode 100644 examples/boot/bootloader/stm32-dual-bank/src/main.rs diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index e568001bc..54ae8a34b 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -49,16 +49,20 @@ pub struct BootLoaderConfig { pub state: STATE, } -impl<'a, FLASH: NorFlash> +impl<'a, ActiveFlash: NorFlash, DFUFlash: NorFlash, StateFlash: NorFlash> BootLoaderConfig< - BlockingPartition<'a, NoopRawMutex, FLASH>, - BlockingPartition<'a, NoopRawMutex, FLASH>, - BlockingPartition<'a, NoopRawMutex, FLASH>, + BlockingPartition<'a, NoopRawMutex, ActiveFlash>, + BlockingPartition<'a, NoopRawMutex, DFUFlash>, + BlockingPartition<'a, NoopRawMutex, StateFlash>, > { /// Create a bootloader config from the flash and address symbols defined in the linkerfile // #[cfg(target_os = "none")] - pub fn from_linkerfile_blocking(flash: &'a Mutex>) -> Self { + pub fn from_linkerfile_blocking( + active_flash: &'a Mutex>, + dfu_flash: &'a Mutex>, + state_flash: &'a Mutex>, + ) -> Self { extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; @@ -73,21 +77,21 @@ impl<'a, FLASH: NorFlash> let end = &__bootloader_active_end as *const u32 as u32; trace!("ACTIVE: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(active_flash, start, end - start) }; let dfu = unsafe { let start = &__bootloader_dfu_start as *const u32 as u32; let end = &__bootloader_dfu_end as *const u32 as u32; trace!("DFU: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(dfu_flash, start, end - start) }; let state = unsafe { let start = &__bootloader_state_start as *const u32 as u32; let end = &__bootloader_state_end as *const u32 as u32; trace!("STATE: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(state_flash, start, end - start) }; Self { active, dfu, state } diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 2e43e1cc1..5634b48d4 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -16,11 +16,14 @@ pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { } #[cfg(target_os = "none")] -impl<'a, FLASH: NorFlash> - FirmwareUpdaterConfig, Partition<'a, NoopRawMutex, FLASH>> +impl<'a, DFUFlash: NorFlash, StateFlash: NorFlash> + FirmwareUpdaterConfig, Partition<'a, NoopRawMutex, StateFlash>> { /// Create a firmware updater config from the flash and address symbols defined in the linkerfile - pub fn from_linkerfile(flash: &'a embassy_sync::mutex::Mutex) -> Self { + pub fn from_linkerfile( + dfu_flash: &'a embassy_sync::mutex::Mutex, + state_flash: &'a embassy_sync::mutex::Mutex, + ) -> Self { extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; @@ -33,14 +36,14 @@ impl<'a, FLASH: NorFlash> let end = &__bootloader_dfu_end as *const u32 as u32; trace!("DFU: 0x{:x} - 0x{:x}", start, end); - Partition::new(flash, start, end - start) + Partition::new(dfu_flash, start, end - start) }; let state = unsafe { let start = &__bootloader_state_start as *const u32 as u32; let end = &__bootloader_state_end as *const u32 as u32; trace!("STATE: 0x{:x} - 0x{:x}", start, end); - Partition::new(flash, start, end - start) + Partition::new(state_flash, start, end - start) }; Self { dfu, state } diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index f1368540d..3814b6c31 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -16,12 +16,16 @@ pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { } #[cfg(target_os = "none")] -impl<'a, FLASH: NorFlash> - FirmwareUpdaterConfig, BlockingPartition<'a, NoopRawMutex, FLASH>> +impl<'a, DFUFlash: NorFlash, StateFlash: NorFlash> + FirmwareUpdaterConfig< + BlockingPartition<'a, NoopRawMutex, DFUFlash>, + BlockingPartition<'a, NoopRawMutex, StateFlash>, + > { /// Create a firmware updater config from the flash and address symbols defined in the linkerfile pub fn from_linkerfile_blocking( - flash: &'a embassy_sync::blocking_mutex::Mutex>, + dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, + state_flash: &'a embassy_sync::blocking_mutex::Mutex>, ) -> Self { extern "C" { static __bootloader_state_start: u32; @@ -35,14 +39,14 @@ impl<'a, FLASH: NorFlash> let end = &__bootloader_dfu_end as *const u32 as u32; trace!("DFU: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(dfu_flash, start, end - start) }; let state = unsafe { let start = &__bootloader_state_start as *const u32 as u32; let end = &__bootloader_state_end as *const u32 as u32; trace!("STATE: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(state_flash, start, end - start) }; Self { dfu, state } diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml new file mode 100644 index 000000000..313187adc --- /dev/null +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml @@ -0,0 +1,57 @@ +[package] +edition = "2021" +name = "stm32-bootloader-dual-bank-flash-example" +version = "0.1.0" +description = "Example bootloader for dual-bank flash STM32 chips" +license = "MIT OR Apache-2.0" + +[dependencies] +defmt = { version = "0.3", optional = true } +defmt-rtt = { version = "0.4", optional = true } + +embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } +embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } +cortex-m = { version = "0.7.6", features = [ + "inline-asm", + "critical-section-single-core", +] } +embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +cortex-m-rt = { version = "0.7" } +embedded-storage = "0.3.1" +embedded-storage-async = "0.4.0" +cfg-if = "1.0.0" + +[features] +defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"] +debug = ["defmt-rtt", "defmt"] + +[profile.dev] +debug = 2 +debug-assertions = true +incremental = false +opt-level = 'z' +overflow-checks = true + +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 'z' +overflow-checks = false + +# do not optimize proc-macro crates = faster builds from scratch +[profile.dev.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +[profile.release.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md new file mode 100644 index 000000000..3de3171cd --- /dev/null +++ b/examples/boot/bootloader/stm32-dual-bank/README.md @@ -0,0 +1,44 @@ +# STM32 dual-bank flash Bootloader + +## 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. +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. + +### Symbol Definitions + +The bootloader's state and active symbols are anchored to the flash origin of **bank 1**: + +- `__bootloader_state_start` and `__bootloader_state_end` +- `__bootloader_active_start` and `__bootloader_active_end` + +In contrast, the Device Firmware Upgrade (DFU) symbols are aligned with the DFU flash origin in **bank 2**: + +- `__bootloader_dfu_start` and `__bootloader_dfu_end` + +```rust +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(**FLASH**); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(**FLASH**); + +__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(**FLASH**); +__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(**FLASH**); + +__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(**DFU**); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(**DFU**); +``` + +## Flashing the Bootloader + +To flash the bootloader onto your STM32H747XI device, use the following command: + +```bash +cargo flash --features embassy-stm32/stm32h747xi-cm7 --release --chip STM32H747XIHx +``` diff --git a/examples/boot/bootloader/stm32-dual-bank/build.rs b/examples/boot/bootloader/stm32-dual-bank/build.rs new file mode 100644 index 000000000..fd605991f --- /dev/null +++ b/examples/boot/bootloader/stm32-dual-bank/build.rs @@ -0,0 +1,27 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + } +} diff --git a/examples/boot/bootloader/stm32-dual-bank/memory.x b/examples/boot/bootloader/stm32-dual-bank/memory.x new file mode 100644 index 000000000..665da7139 --- /dev/null +++ b/examples/boot/bootloader/stm32-dual-bank/memory.x @@ -0,0 +1,18 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x08000000, LENGTH = 128K + BOOTLOADER_STATE : ORIGIN = 0x08020000, LENGTH = 128K + ACTIVE : ORIGIN = 0x08040000, LENGTH = 512K + DFU : ORIGIN = 0x08100000, LENGTH = 640K + RAM (rwx) : ORIGIN = 0x24000000, LENGTH = 512K +} + +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH); + +__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH); +__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH); + +__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(DFU); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(DFU); diff --git a/examples/boot/bootloader/stm32-dual-bank/src/main.rs b/examples/boot/bootloader/stm32-dual-bank/src/main.rs new file mode 100644 index 000000000..4d2e82d26 --- /dev/null +++ b/examples/boot/bootloader/stm32-dual-bank/src/main.rs @@ -0,0 +1,53 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use cortex_m_rt::{entry, exception}; +#[cfg(feature = "defmt")] +use defmt_rtt as _; +use embassy_boot_stm32::*; +use embassy_stm32::flash::{Flash, BANK1_REGION}; +use embassy_sync::blocking_mutex::Mutex; + +#[entry] +fn main() -> ! { + let p = embassy_stm32::init(Default::default()); + + // Uncomment this if you are debugging the bootloader with debugger/RTT attached, + // as it prevents a hard fault when accessing flash 'too early' after boot. + /* + for i in 0..10000000 { + cortex_m::asm::nop(); + } + */ + + let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); + let flash_bank1 = Mutex::new(RefCell::new(layout.bank1_region)); + let flash_bank2 = Mutex::new(RefCell::new(layout.bank2_region)); + + let config = BootLoaderConfig::from_linkerfile_blocking(&flash_bank1, &flash_bank2, &flash_bank1); + let active_offset = config.active.offset(); + let bl = BootLoader::prepare::<_, _, _, 2048>(config); + + unsafe { bl.load(BANK1_REGION.base + active_offset) } +} + +#[no_mangle] +#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +unsafe extern "C" fn HardFault() { + cortex_m::peripheral::SCB::sys_reset(); +} + +#[exception] +unsafe fn DefaultHandler(_: i16) -> ! { + const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; + let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + + panic!("DefaultHandler #{:?}", irqn); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + cortex_m::asm::udf(); +} diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs index 5fd9ea588..99a7a6a6b 100644 --- a/examples/boot/bootloader/stm32/src/main.rs +++ b/examples/boot/bootloader/stm32/src/main.rs @@ -25,7 +25,7 @@ fn main() -> ! { let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); let flash = Mutex::new(RefCell::new(layout.bank1_region)); - let config = BootLoaderConfig::from_linkerfile_blocking(&flash); + let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash); let active_offset = config.active.offset(); let bl = BootLoader::prepare::<_, _, _, 2048>(config); diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index a7ab813b6..d989fbfdf 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -35,7 +35,7 @@ fn main() -> ! { let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); let flash = Mutex::new(RefCell::new(layout.bank1_region)); - let config = BootLoaderConfig::from_linkerfile_blocking(&flash); + let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash); let active_offset = config.active.offset(); let bl = BootLoader::prepare::<_, _, _, 2048>(config); if bl.state == State::DfuDetach { @@ -45,7 +45,7 @@ fn main() -> ! { config.product = Some("USB-DFU Bootloader example"); config.serial_number = Some("1235678"); - let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); + let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash); let mut buffer = AlignedBuffer([0; WRITE_SIZE]); let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); From b7db75adff16eb0a4670e926dc664549433654fd Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 6 Feb 2024 10:44:52 -0500 Subject: [PATCH 377/760] Updated stm32-metapac. --- embassy-stm32/Cargo.toml | 4 ++-- tests/stm32/src/bin/hash.rs | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 63bc32197..ef6063656 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-aa5dbf859fae743306f5d816905f166de824241f" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5674011dd7db845c9d70d6a20a16129221026d25" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-aa5dbf859fae743306f5d816905f166de824241f", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5674011dd7db845c9d70d6a20a16129221026d25", default-features = false, features = ["metadata"]} [features] diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index 53dd0551f..2867115dc 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -11,11 +11,7 @@ use embassy_stm32::{bind_interrupts, hash, peripherals}; use sha2::{Digest, Sha224, Sha256}; use {defmt_rtt as _, panic_probe as _}; -#[cfg(any( - feature = "stm32l4a6zg", - feature = "stm32h755zi", - feature = "stm32h753zi" -))] +#[cfg(any(feature = "stm32l4a6zg", feature = "stm32h755zi", feature = "stm32h753zi"))] bind_interrupts!(struct Irqs { HASH_RNG => hash::InterruptHandler; }); @@ -29,7 +25,7 @@ bind_interrupts!(struct Irqs { ))] bind_interrupts!(struct Irqs { HASH => hash::InterruptHandler; - }); +}); #[embassy_executor::main] async fn main(_spawner: Spawner) { From 5f36108896d909ed990a587941d74e0488bcd190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xgroleau=F0=9F=90=A2?= Date: Tue, 6 Feb 2024 10:38:48 -0500 Subject: [PATCH 378/760] fix: rtos-usage time missing --- embassy-executor/Cargo.toml | 4 ++++ embassy-executor/src/raw/mod.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 409df0d75..0762e2434 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -34,6 +34,7 @@ log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" } +embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" @@ -71,6 +72,9 @@ turbowakers = [] ## Use the executor-integrated `embassy-time` timer queue. integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"] +# Support for rtos trace require time +rtos-trace = ["dep:rtos-trace", "dep:embassy-time"] + #! ### Architecture _arch = [] # some arch was picked ## std diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3f00be4a8..fbc0481c2 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -588,7 +588,7 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { } #[cfg(feature = "integrated-timers")] fn time() -> u64 { - Instant::now().as_micros() + embassy_time::Instant::now().as_millis() } #[cfg(not(feature = "integrated-timers"))] fn time() -> u64 { From bfa67c29932ba9b326da0c661b1b03dcee2ef3fe Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 6 Feb 2024 18:37:48 -0500 Subject: [PATCH 379/760] Fix digest interrupt enable. --- embassy-stm32/src/hash/v1.rs | 2 +- embassy-stm32/src/hash/v2v3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/hash/v1.rs b/embassy-stm32/src/hash/v1.rs index 50f9adc83..36beb7c3e 100644 --- a/embassy-stm32/src/hash/v1.rs +++ b/embassy-stm32/src/hash/v1.rs @@ -215,7 +215,7 @@ impl<'d, T: Instance> Hash<'d, T> { } // Register waker, then enable interrupts. HASH_WAKER.register(cx.waker()); - T::regs().imr().modify(|reg| reg.set_dinie(true)); + T::regs().imr().modify(|reg| reg.set_dcie(true)); // Check for completion. let bits = T::regs().sr().read(); if bits.dcis() { diff --git a/embassy-stm32/src/hash/v2v3.rs b/embassy-stm32/src/hash/v2v3.rs index 058864568..ba1e05f0c 100644 --- a/embassy-stm32/src/hash/v2v3.rs +++ b/embassy-stm32/src/hash/v2v3.rs @@ -244,7 +244,7 @@ impl<'d, T: Instance, D: Dma> Hash<'d, T, D> { } // Register waker, then enable interrupts. HASH_WAKER.register(cx.waker()); - T::regs().imr().modify(|reg| reg.set_dinie(true)); + T::regs().imr().modify(|reg| reg.set_dcie(true)); // Check for completion. let bits = T::regs().sr().read(); if bits.dcis() { From af2b4df833902fa8d42cb133c52733fe0b848bc7 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 11:32:13 +0100 Subject: [PATCH 380/760] refactor(boot): change generics name to match existing convention --- embassy-boot/src/boot_loader.rs | 14 +++++++------- embassy-boot/src/firmware_updater/asynch.rs | 8 ++++---- embassy-boot/src/firmware_updater/blocking.rs | 11 ++++------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 54ae8a34b..c433ce439 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -49,19 +49,19 @@ pub struct BootLoaderConfig { pub state: STATE, } -impl<'a, ActiveFlash: NorFlash, DFUFlash: NorFlash, StateFlash: NorFlash> +impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoaderConfig< - BlockingPartition<'a, NoopRawMutex, ActiveFlash>, - BlockingPartition<'a, NoopRawMutex, DFUFlash>, - BlockingPartition<'a, NoopRawMutex, StateFlash>, + BlockingPartition<'a, NoopRawMutex, ACTIVE>, + BlockingPartition<'a, NoopRawMutex, DFU>, + BlockingPartition<'a, NoopRawMutex, STATE>, > { /// Create a bootloader config from the flash and address symbols defined in the linkerfile // #[cfg(target_os = "none")] pub fn from_linkerfile_blocking( - active_flash: &'a Mutex>, - dfu_flash: &'a Mutex>, - state_flash: &'a Mutex>, + active_flash: &'a Mutex>, + dfu_flash: &'a Mutex>, + state_flash: &'a Mutex>, ) -> Self { extern "C" { static __bootloader_state_start: u32; diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 5634b48d4..668f16f16 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -16,13 +16,13 @@ pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { } #[cfg(target_os = "none")] -impl<'a, DFUFlash: NorFlash, StateFlash: NorFlash> - FirmwareUpdaterConfig, Partition<'a, NoopRawMutex, StateFlash>> +impl<'a, DFU: NorFlash, STATE: NorFlash> + FirmwareUpdaterConfig, Partition<'a, NoopRawMutex, STATE>> { /// Create a firmware updater config from the flash and address symbols defined in the linkerfile pub fn from_linkerfile( - dfu_flash: &'a embassy_sync::mutex::Mutex, - state_flash: &'a embassy_sync::mutex::Mutex, + dfu_flash: &'a embassy_sync::mutex::Mutex, + state_flash: &'a embassy_sync::mutex::Mutex, ) -> Self { extern "C" { static __bootloader_state_start: u32; diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 3814b6c31..cf850fce3 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -16,16 +16,13 @@ pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { } #[cfg(target_os = "none")] -impl<'a, DFUFlash: NorFlash, StateFlash: NorFlash> - FirmwareUpdaterConfig< - BlockingPartition<'a, NoopRawMutex, DFUFlash>, - BlockingPartition<'a, NoopRawMutex, StateFlash>, - > +impl<'a, DFU: NorFlash, STATE: NorFlash> + FirmwareUpdaterConfig, BlockingPartition<'a, NoopRawMutex, STATE>> { /// Create a firmware updater config from the flash and address symbols defined in the linkerfile pub fn from_linkerfile_blocking( - dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, - state_flash: &'a embassy_sync::blocking_mutex::Mutex>, + dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, + state_flash: &'a embassy_sync::blocking_mutex::Mutex>, ) -> Self { extern "C" { static __bootloader_state_start: u32; From 4a72f946e42dde3dbfbf46a676d5b40617e4c92f Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 11:38:05 +0100 Subject: [PATCH 381/760] fix(boot): update stm32wb-dfu example readme --- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 96635afa2..854f94d85 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } -embassy-stm32 = { path = "../../../../embassy-stm32", features = ["stm32wb55rg"] } +embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md index a82b730b9..d5c6ea57c 100644 --- a/examples/boot/bootloader/stm32wb-dfu/README.md +++ b/examples/boot/bootloader/stm32wb-dfu/README.md @@ -7,5 +7,5 @@ The bootloader uses `embassy-boot` to interact with the flash. Flash the bootloader ``` -cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx +cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx ``` From cfc3e966331310b7210c94339cf8f111a65d9e53 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 12:50:48 +0100 Subject: [PATCH 382/760] fix(boot): update examples --- examples/boot/application/nrf/src/bin/a.rs | 2 +- examples/boot/application/rp/src/bin/a.rs | 2 +- examples/boot/application/stm32f3/memory.x | 4 ++-- .../boot/application/stm32f3/src/bin/a.rs | 2 +- .../boot/application/stm32f7/src/bin/a.rs | 2 +- .../boot/application/stm32h7/src/bin/a.rs | 2 +- examples/boot/application/stm32l0/memory.x | 4 ++-- .../boot/application/stm32l0/src/bin/a.rs | 2 +- examples/boot/application/stm32l1/memory.x | 4 ++-- .../boot/application/stm32l1/src/bin/a.rs | 2 +- examples/boot/application/stm32l4/memory.x | 4 ++-- .../boot/application/stm32l4/src/bin/a.rs | 2 +- .../boot/application/stm32wb-dfu/README.md | 24 ++----------------- .../boot/application/stm32wb-dfu/src/main.rs | 2 +- examples/boot/application/stm32wl/memory.x | 4 ++-- .../boot/application/stm32wl/src/bin/a.rs | 2 +- examples/boot/bootloader/nrf/src/main.rs | 2 +- examples/boot/bootloader/rp/src/main.rs | 2 +- 18 files changed, 24 insertions(+), 44 deletions(-) diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index f3abfddbc..851a3d721 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -50,7 +50,7 @@ async fn main(_spawner: Spawner) { let nvmc = Nvmc::new(p.NVMC); let nvmc = Mutex::new(BlockingAsync::new(nvmc)); - let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc); + let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); let mut magic = [0; 4]; let mut updater = FirmwareUpdater::new(config, &mut magic); loop { diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs index 3f0bf90e2..ede0c07da 100644 --- a/examples/boot/application/rp/src/bin/a.rs +++ b/examples/boot/application/rp/src/bin/a.rs @@ -36,7 +36,7 @@ async fn main(_s: Spawner) { let flash = Flash::<_, _, FLASH_SIZE>::new_blocking(p.FLASH); let flash = Mutex::new(RefCell::new(flash)); - let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash); let mut aligned = AlignedBuffer([0; 1]); let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0); diff --git a/examples/boot/application/stm32f3/memory.x b/examples/boot/application/stm32f3/memory.x index f51875766..02ebe3ecf 100644 --- a/examples/boot/application/stm32f3/memory.x +++ b/examples/boot/application/stm32f3/memory.x @@ -3,8 +3,8 @@ MEMORY /* NOTE 1 K = 1 KiBi = 1024 bytes */ BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - FLASH : ORIGIN = 0x08008000, LENGTH = 32K - DFU : ORIGIN = 0x08010000, LENGTH = 36K + FLASH : ORIGIN = 0x08008000, LENGTH = 64K + DFU : ORIGIN = 0x08018000, LENGTH = 66K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs index 3f9ebe5c8..8858ae3da 100644 --- a/examples/boot/application/stm32f3/src/bin/a.rs +++ b/examples/boot/application/stm32f3/src/bin/a.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PA5, Level::Low, Speed::Low); led.set_high(); - let config = FirmwareUpdaterConfig::from_linkerfile(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); let mut updater = FirmwareUpdater::new(config, &mut magic.0); button.wait_for_falling_edge().await; diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs index c57c29263..d3df11fe4 100644 --- a/examples/boot/application/stm32f7/src/bin/a.rs +++ b/examples/boot/application/stm32f7/src/bin/a.rs @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PB7, Level::Low, Speed::Low); led.set_high(); - let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0); let writer = updater.prepare_update().unwrap(); diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs index a00d17408..f61ac1f71 100644 --- a/examples/boot/application/stm32h7/src/bin/a.rs +++ b/examples/boot/application/stm32h7/src/bin/a.rs @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PB14, Level::Low, Speed::Low); led.set_high(); - let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0); let writer = updater.prepare_update().unwrap(); diff --git a/examples/boot/application/stm32l0/memory.x b/examples/boot/application/stm32l0/memory.x index a99330145..8866506a8 100644 --- a/examples/boot/application/stm32l0/memory.x +++ b/examples/boot/application/stm32l0/memory.x @@ -3,8 +3,8 @@ MEMORY /* NOTE 1 K = 1 KiBi = 1024 bytes */ BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - FLASH : ORIGIN = 0x08008000, LENGTH = 32K - DFU : ORIGIN = 0x08010000, LENGTH = 36K + FLASH : ORIGIN = 0x08008000, LENGTH = 64K + DFU : ORIGIN = 0x08018000, LENGTH = 66K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K } diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs index dbec49d44..f066c1139 100644 --- a/examples/boot/application/stm32l0/src/bin/a.rs +++ b/examples/boot/application/stm32l0/src/bin/a.rs @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { led.set_high(); - let config = FirmwareUpdaterConfig::from_linkerfile(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); let mut updater = FirmwareUpdater::new(config, &mut magic.0); button.wait_for_falling_edge().await; diff --git a/examples/boot/application/stm32l1/memory.x b/examples/boot/application/stm32l1/memory.x index a99330145..caa525278 100644 --- a/examples/boot/application/stm32l1/memory.x +++ b/examples/boot/application/stm32l1/memory.x @@ -3,8 +3,8 @@ MEMORY /* NOTE 1 K = 1 KiBi = 1024 bytes */ BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - FLASH : ORIGIN = 0x08008000, LENGTH = 32K - DFU : ORIGIN = 0x08010000, LENGTH = 36K + FLASH : ORIGIN = 0x08008000, LENGTH = 46K + DFU : ORIGIN = 0x08013800, LENGTH = 54K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K } diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs index dbec49d44..f066c1139 100644 --- a/examples/boot/application/stm32l1/src/bin/a.rs +++ b/examples/boot/application/stm32l1/src/bin/a.rs @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { led.set_high(); - let config = FirmwareUpdaterConfig::from_linkerfile(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); let mut updater = FirmwareUpdater::new(config, &mut magic.0); button.wait_for_falling_edge().await; diff --git a/examples/boot/application/stm32l4/memory.x b/examples/boot/application/stm32l4/memory.x index f51875766..e1d4e7fa8 100644 --- a/examples/boot/application/stm32l4/memory.x +++ b/examples/boot/application/stm32l4/memory.x @@ -3,8 +3,8 @@ MEMORY /* NOTE 1 K = 1 KiBi = 1024 bytes */ BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - FLASH : ORIGIN = 0x08008000, LENGTH = 32K - DFU : ORIGIN = 0x08010000, LENGTH = 36K + FLASH : ORIGIN = 0x08008000, LENGTH = 64K + DFU : ORIGIN = 0x08018000, LENGTH = 68K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs index e946c3cdf..a0079ee33 100644 --- a/examples/boot/application/stm32l4/src/bin/a.rs +++ b/examples/boot/application/stm32l4/src/bin/a.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PB14, Level::Low, Speed::Low); led.set_high(); - let config = FirmwareUpdaterConfig::from_linkerfile(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); let mut updater = FirmwareUpdater::new(config, &mut magic.0); button.wait_for_falling_edge().await; diff --git a/examples/boot/application/stm32wb-dfu/README.md b/examples/boot/application/stm32wb-dfu/README.md index c8dce0387..7f656cde6 100644 --- a/examples/boot/application/stm32wb-dfu/README.md +++ b/examples/boot/application/stm32wb-dfu/README.md @@ -1,29 +1,9 @@ # Examples using bootloader -Example for STM32WL demonstrating the bootloader. The example consists of application binaries, 'a' -which allows you to press a button to start the DFU process, and 'b' which is the updated -application. - - -## Prerequisites - -* `cargo-binutils` -* `cargo-flash` -* `embassy-boot-stm32` +Example for STM32WB demonstrating the USB DFU application. ## Usage ``` -# Flash bootloader -cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32wl55jc-cm4 --chip STM32WLE5JCIx -# Build 'b' -cargo build --release --bin b -# Generate binary for 'b' -cargo objcopy --release --bin b -- -O binary b.bin -``` - -# Flash `a` (which includes b.bin) - -``` -cargo flash --release --bin a --chip STM32WLE5JCIx +cargo flash --release --chip STM32WB55RGVx ``` diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index b2ccb9e1a..37c3d7d90 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(RefCell::new(flash)); - let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); let mut firmware_state = BlockingFirmwareState::from_config(config, &mut magic.0); firmware_state.mark_booted().expect("Failed to mark booted"); diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x index f51875766..e1d4e7fa8 100644 --- a/examples/boot/application/stm32wl/memory.x +++ b/examples/boot/application/stm32wl/memory.x @@ -3,8 +3,8 @@ MEMORY /* NOTE 1 K = 1 KiBi = 1024 bytes */ BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - FLASH : ORIGIN = 0x08008000, LENGTH = 32K - DFU : ORIGIN = 0x08010000, LENGTH = 36K + FLASH : ORIGIN = 0x08008000, LENGTH = 64K + DFU : ORIGIN = 0x08018000, LENGTH = 68K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index b582d8b25..2fb16bdc4 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PB9, Level::Low, Speed::Low); led.set_high(); - let config = FirmwareUpdaterConfig::from_linkerfile(&flash); + let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash); let mut magic = AlignedBuffer([0; WRITE_SIZE]); let mut updater = FirmwareUpdater::new(config, &mut magic.0); button.wait_for_falling_edge().await; diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs index 74e2e293f..67c700437 100644 --- a/examples/boot/bootloader/nrf/src/main.rs +++ b/examples/boot/bootloader/nrf/src/main.rs @@ -31,7 +31,7 @@ fn main() -> ! { let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); let flash = Mutex::new(RefCell::new(flash)); - let config = BootLoaderConfig::from_linkerfile_blocking(&flash); + let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash); let active_offset = config.active.offset(); let bl: BootLoader = BootLoader::prepare(config); diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs index c0e75d1ea..25b1657b8 100644 --- a/examples/boot/bootloader/rp/src/main.rs +++ b/examples/boot/bootloader/rp/src/main.rs @@ -27,7 +27,7 @@ fn main() -> ! { let flash = WatchdogFlash::::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8)); let flash = Mutex::new(RefCell::new(flash)); - let config = BootLoaderConfig::from_linkerfile_blocking(&flash); + let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash); let active_offset = config.active.offset(); let bl: BootLoader = BootLoader::prepare(config); From 634c409c55c71ca2871cd05d4a7754654926db48 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 13:06:48 +0100 Subject: [PATCH 383/760] docs(boot): document from_linkerfile_blocking method --- embassy-boot/src/boot_loader.rs | 33 ++++++++++++++++++- embassy-boot/src/firmware_updater/blocking.rs | 32 +++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index c433ce439..2a5f024f6 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -56,7 +56,38 @@ impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BlockingPartition<'a, NoopRawMutex, STATE>, > { - /// Create a bootloader config from the flash and address symbols defined in the linkerfile + /// Constructs a `BootLoaderConfig` instance from flash memory and address symbols defined in the linker file. + /// + /// This method initializes `BlockingPartition` instances for the active, DFU (Device Firmware Update), + /// and state partitions, leveraging start and end addresses specified by the linker. These partitions + /// are critical for managing firmware updates, application state, and boot operations within the bootloader. + /// + /// # Parameters + /// - `active_flash`: A reference to a mutex-protected `RefCell` for the active partition's flash interface. + /// - `dfu_flash`: A reference to a mutex-protected `RefCell` for the DFU partition's flash interface. + /// - `state_flash`: A reference to a mutex-protected `RefCell` for the state partition's flash interface. + /// + /// # Safety + /// The method contains `unsafe` blocks for dereferencing raw pointers that represent the start and end addresses + /// of the bootloader's partitions in flash memory. It is crucial that these addresses are accurately defined + /// in the memory.x file to prevent undefined behavior. + /// + /// The caller must ensure that the memory regions defined by these symbols are valid and that the flash memory + /// interfaces provided are compatible with these regions. + /// + /// # Returns + /// A `BootLoaderConfig` instance with `BlockingPartition` instances for the active, DFU, and state partitions. + /// + /// # Example + /// ```no_run + /// // Assume `active_flash`, `dfu_flash`, and `state_flash` all share the same flash memory interface. + /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); + /// let flash = Mutex::new(RefCell::new(layout.bank1_region)); + /// + /// let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash); + /// // `config` can now be used to create a `BootLoader` instance for managing boot operations. + /// ``` + /// Working examples can be found in the bootloader examples folder. // #[cfg(target_os = "none")] pub fn from_linkerfile_blocking( active_flash: &'a Mutex>, diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index cf850fce3..a29efabf0 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -19,7 +19,37 @@ pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { impl<'a, DFU: NorFlash, STATE: NorFlash> FirmwareUpdaterConfig, BlockingPartition<'a, NoopRawMutex, STATE>> { - /// Create a firmware updater config from the flash and address symbols defined in the linkerfile + /// Constructs a `FirmwareUpdaterConfig` instance from flash memory and address symbols defined in the linker file. + /// + /// This method initializes `BlockingPartition` instances for the DFU (Device Firmware Update), and state + /// partitions, leveraging start and end addresses specified by the linker. These partitions are critical + /// for managing firmware updates, application state, and boot operations within the bootloader. + /// + /// # Parameters + /// - `dfu_flash`: A reference to a mutex-protected `RefCell` for the DFU partition's flash interface. + /// - `state_flash`: A reference to a mutex-protected `RefCell` for the state partition's flash interface. + /// + /// # Safety + /// The method contains `unsafe` blocks for dereferencing raw pointers that represent the start and end addresses + /// of the bootloader's partitions in flash memory. It is crucial that these addresses are accurately defined + /// in the memory.x file to prevent undefined behavior. + /// + /// The caller must ensure that the memory regions defined by these symbols are valid and that the flash memory + /// interfaces provided are compatible with these regions. + /// + /// # Returns + /// A `FirmwareUpdaterConfig` instance with `BlockingPartition` instances for the DFU, and state partitions. + /// + /// # Example + /// ```no_run + /// // Assume `dfu_flash`, and `state_flash` share the same flash memory interface. + /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); + /// let flash = Mutex::new(RefCell::new(layout.bank1_region)); + /// + /// let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash); + /// // `config` can now be used to create a `FirmwareUpdater` instance for managing boot operations. + /// ``` + /// Working examples can be found in the bootloader examples folder. pub fn from_linkerfile_blocking( dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, state_flash: &'a embassy_sync::blocking_mutex::Mutex>, From e391b9b74c95090548c50b6f05a859f0220c42f9 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 14:37:38 +0100 Subject: [PATCH 384/760] docs(boot): ignore partial non-compilable example in rustdoc --- embassy-boot/src/boot_loader.rs | 2 +- embassy-boot/src/firmware_updater/blocking.rs | 2 +- embassy-boot/src/firmware_updater/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 2a5f024f6..ca1a1b10c 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -79,7 +79,7 @@ impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> /// A `BootLoaderConfig` instance with `BlockingPartition` instances for the active, DFU, and state partitions. /// /// # Example - /// ```no_run + /// ```ignore /// // Assume `active_flash`, `dfu_flash`, and `state_flash` all share the same flash memory interface. /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); /// let flash = Mutex::new(RefCell::new(layout.bank1_region)); diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index a29efabf0..4044871f0 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -41,7 +41,7 @@ impl<'a, DFU: NorFlash, STATE: NorFlash> /// A `FirmwareUpdaterConfig` instance with `BlockingPartition` instances for the DFU, and state partitions. /// /// # Example - /// ```no_run + /// ```ignore /// // Assume `dfu_flash`, and `state_flash` share the same flash memory interface. /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); /// let flash = Mutex::new(RefCell::new(layout.bank1_region)); diff --git a/embassy-boot/src/firmware_updater/mod.rs b/embassy-boot/src/firmware_updater/mod.rs index 4814786bf..4c4f4f10b 100644 --- a/embassy-boot/src/firmware_updater/mod.rs +++ b/embassy-boot/src/firmware_updater/mod.rs @@ -8,7 +8,7 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; /// Firmware updater flash configuration holding the two flashes used by the updater /// /// If only a single flash is actually used, then that flash should be partitioned into two partitions before use. -/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition +/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile_blocking`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition /// the provided flash according to symbols defined in the linkerfile. pub struct FirmwareUpdaterConfig { /// The dfu flash partition From 74fbe27a87fc95f75f8c9251520a8dea889159cc Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 14:55:08 +0100 Subject: [PATCH 385/760] ci(boot): add new example and fix bootloader/stm32wb-dfu --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index df9e09848..f3742ad76 100755 --- a/ci.sh +++ b/ci.sh @@ -194,7 +194,8 @@ cargo batch \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ - --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf \ + --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf --features embassy-stm32/stm32wb55rg \ + --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabihf --features embassy-stm32/stm32h747xi-cm7 \ --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ From 847b8be81480b249a2e8b1ff502e6188d2dadf04 Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Wed, 7 Feb 2024 15:25:07 +0100 Subject: [PATCH 386/760] feat/implement ble radio on nrf --- embassy-nrf/Cargo.toml | 5 + embassy-nrf/src/chips/nrf52805.rs | 6 + embassy-nrf/src/chips/nrf52810.rs | 6 + embassy-nrf/src/chips/nrf52811.rs | 6 + embassy-nrf/src/chips/nrf52820.rs | 6 + embassy-nrf/src/chips/nrf52832.rs | 6 + embassy-nrf/src/chips/nrf52833.rs | 6 + embassy-nrf/src/chips/nrf52840.rs | 6 + embassy-nrf/src/chips/nrf5340_net.rs | 6 + embassy-nrf/src/lib.rs | 6 + embassy-nrf/src/radio/ble.rs | 432 ++++++++++++++++++ embassy-nrf/src/radio/mod.rs | 89 ++++ examples/nrf52840/Cargo.toml | 8 +- .../nrf52840/src/bin/radio_ble_advertising.rs | 42 ++ 14 files changed, 628 insertions(+), 2 deletions(-) create mode 100644 embassy-nrf/src/radio/ble.rs create mode 100644 embassy-nrf/src/radio/mod.rs create mode 100644 examples/nrf52840/src/bin/radio_ble_advertising.rs diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 7e161df9b..dcdc7f313 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -57,6 +57,9 @@ unstable-pac = [] ## Enable GPIO tasks and events gpiote = [] +## Enable radio driver +radio = ["dep:jewel"] + ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz time-driver-rtc1 = ["_time-driver"] @@ -150,6 +153,8 @@ embedded-storage-async = "0.4.0" cfg-if = "1.0.0" document-features = "0.2.7" +jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel", optional = true } + nrf51-pac = { version = "0.12.0", optional = true } nrf52805-pac = { version = "0.12.0", optional = true } nrf52810-pac = { version = "0.12.0", optional = true } diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 624d6613d..b97c85f9e 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -129,6 +129,9 @@ embassy_hal_internal::peripherals! { // QDEC QDEC, + + // RADIO + RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -209,6 +212,9 @@ impl_ppi_channel!(PPI_CH31, 31 => static); impl_saadc_input!(P0_04, ANALOG_INPUT2); impl_saadc_input!(P0_05, ANALOG_INPUT3); +#[cfg(feature = "radio")] +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 002feab3b..03548d03f 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -135,6 +135,9 @@ embassy_hal_internal::peripherals! { // PDM PDM, + + // Radio + RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -235,6 +238,9 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); impl_saadc_input!(P0_30, ANALOG_INPUT6); impl_saadc_input!(P0_31, ANALOG_INPUT7); +#[cfg(feature = "radio")] +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 5952907f8..992fbd129 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -135,6 +135,9 @@ embassy_hal_internal::peripherals! { // PDM PDM, + + // Radio + RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -237,6 +240,9 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); impl_saadc_input!(P0_30, ANALOG_INPUT6); impl_saadc_input!(P0_31, ANALOG_INPUT7); +#[cfg(feature = "radio")] +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index c2f792cb9..f241f4ea3 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -130,6 +130,9 @@ embassy_hal_internal::peripherals! { // QDEC QDEC, + + // Radio + RADIO, } impl_usb!(USBD, USBD, USBD); @@ -224,6 +227,9 @@ impl_ppi_channel!(PPI_CH29, 29 => static); impl_ppi_channel!(PPI_CH30, 30 => static); impl_ppi_channel!(PPI_CH31, 31 => static); +#[cfg(feature = "radio")] +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 65d52364d..6bbdd9a63 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -150,6 +150,9 @@ embassy_hal_internal::peripherals! { // PDM PDM, + + // Radio + RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -264,6 +267,9 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); +#[cfg(feature = "radio")] +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 7c9b66d69..e137e4dc6 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -170,6 +170,9 @@ embassy_hal_internal::peripherals! { // I2S I2S, + + // Radio + RADIO, } impl_usb!(USBD, USBD, USBD); @@ -306,6 +309,9 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); +#[cfg(feature = "radio")] +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 51c55cd4d..2d805f871 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -173,6 +173,9 @@ embassy_hal_internal::peripherals! { // I2S I2S, + + // Radio + RADIO, } impl_usb!(USBD, USBD, USBD); @@ -311,6 +314,9 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); +#[cfg(feature = "radio")] +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index a7cf82872..3248bde52 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -248,6 +248,9 @@ embassy_hal_internal::peripherals! { P1_13, P1_14, P1_15, + + // Radio + RADIO, } impl_uarte!(SERIAL0, UARTE0, SERIAL0); @@ -345,6 +348,9 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable); impl_ppi_channel!(PPI_CH30, 30 => configurable); impl_ppi_channel!(PPI_CH31, 31 => configurable); +#[cfg(feature = "radio")] +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 358a7cc27..961928d11 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -45,6 +45,12 @@ pub mod buffered_uarte; pub mod gpio; #[cfg(feature = "gpiote")] pub mod gpiote; + +#[cfg(feature = "radio")] +pub mod radio; +#[cfg(all(feature = "radio", feature = "_nrf9160"))] +compile_error!("feature `radio` is not valid for nRF91 series chips."); + #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] pub mod i2s; pub mod nvmc; diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs new file mode 100644 index 000000000..a5d9f447b --- /dev/null +++ b/embassy-nrf/src/radio/ble.rs @@ -0,0 +1,432 @@ +//! Radio driver implementation focused on Bluetooth Low-Energy transmission. +//! +//! The radio can calculate the CRC, perform data whitening, +//! automatically send the right preamble. +//! Most of the configuration is done automatically when you choose the mode and this driver. +//! +//! Some configuration can just be done when de device is disabled, +//! and the configuration varies depending if is a transmitter or a receiver. +//! Because of that we have a state machine to keep track of the state of the radio. +//! The Radio is the disable radio which configure the common parameters between +//! the bluetooth protocols, like the package format, the CRC and the whitening. +//! The TxRadio radio enable and configured as a transmitter with the specific parameters. + +use core::future::poll_fn; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::Poll; + +use embassy_hal_internal::drop::OnDrop; +use embassy_hal_internal::{into_ref, PeripheralRef}; +use jewel::phy::{ + AdvertisingChannel, Channel, ChannelTrait, HeaderSize, Mode, Radio as BleRadio, ADV_ADDRESS, ADV_CRC_INIT, + CRC_POLY, MAX_PDU_LENGTH, +}; +use pac::radio::mode::MODE_A as PacMode; +use pac::radio::pcnf0::PLEN_A as PreambleLength; +// Re-export SVD variants to allow user to directly set values. +pub use pac::radio::{state::STATE_A as RadioState, txpower::TXPOWER_A as TxPower}; + +use crate::interrupt::typelevel::Interrupt; +use crate::radio::*; +use crate::util::slice_in_ram_or; + +/// UART error. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// Buffer was too long. + BufferTooLong, + /// Buffer was to short. + BufferTooShort, + /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. + BufferNotInRAM, +} + +/// Radio driver. +pub struct Radio<'d, T: Instance> { + _p: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Radio<'d, T> { + /// Create a new radio driver. + pub fn new( + radio: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + // From 5.4.1 of the nRF52840 Product Specification: + // > The HFXO must be running to use the RADIO or the calibration mechanism associated with the 32.768 kHz RC oscillator. + // Currently the jewel crate don't implement the calibration mechanism, so we need to ensure that the HFXO is running + utils::check_xtal(); + + into_ref!(radio); + + let r = T::regs(); + + r.pcnf1.write(|w| unsafe { + // It is 0 bytes long in a standard BLE packet + w.statlen() + .bits(0) + // MaxLen configures the maximum packet payload plus add-on size in + // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure + // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means + // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a + // packet larger than MAXLEN, the payload will be truncated at MAXLEN + // + // To simplify the implementation, I'm setting the max length to the maximum value + // and I'm using only the length field to truncate the payload + .maxlen() + .bits(255) + // Configure the length of the address field in the packet + // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address + // The base address is truncated from the least significant byte if the BALEN is less than 4 + // + // BLE address is always 4 bytes long + .balen() + .bits(3) // 3 bytes base address (+ 1 prefix); + // Configure the endianess + // For BLE is always little endian (LSB first) + .endian() + .little() + // Data whitening is used to avoid long sequences of zeros or + // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream. + // The whitener and de-whitener are defined the same way, + // using a 7-bit linear feedback shift register with the + // polynomial x7 + x4 + 1. + // + // In BLE Whitening shall be applied on the PDU and CRC of all + // Link Layer packets and is performed after the CRC generation + // in the transmitter. No other parts of the packets are whitened. + // De-whitening is performed before the CRC checking in the receiver + // Before whitening or de-whitening, the shift register should be + // initialized based on the channel index. + .whiteen() + .set_bit() // Enable whitening + }); + + // Configure CRC + r.crccnf.write(|w| { + // In BLE the CRC shall be calculated on the PDU of all Link Layer + // packets (even if the packet is encrypted). + // So here we skip the address field + w.skipaddr() + .skip() + // In BLE 24-bit CRC = 3 bytes + .len() + .three() + }); + + r.crcpoly.write(|w| unsafe { + // Configure the CRC polynomial + // Each term in the CRC polynomial is mapped to a bit in this + // register which index corresponds to the term's exponent. + // The least significant term/bit is hard-wired internally to + // 1, and bit number 0 of the register content is ignored by + // the hardware. The following example is for an 8 bit CRC + // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 . + w.crcpoly().bits(CRC_POLY & 0xFFFFFF) + }); + // The CRC initial value varies depending of the PDU type + + // Ch map between 2400 MHZ .. 2500 MHz + // All modes use this range + r.frequency.write(|w| w.map().default()); + + // Configure shortcuts to simplify and speed up sending and receiving packets. + r.shorts.write(|w| { + // start transmission/recv immediately after ramp-up + // disable radio when transmission/recv is done + w.ready_start().enabled().end_disable().enabled() + }); + + // Enable NVIC interrupt + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + let mut radio = Self { _p: radio }; + + // set defaults + radio.set_mode(Mode::Ble1mbit); + radio.set_tx_power(0); + radio.set_header_size(HeaderSize::TwoBytes); + radio.set_access_address(ADV_ADDRESS); + radio.set_crc_init(ADV_CRC_INIT); + radio.set_channel(AdvertisingChannel::Ch39.into()); + + radio + } + + #[allow(dead_code)] + fn trace_state(&self) { + let r = T::regs(); + + match r.state.read().state().variant().unwrap() { + RadioState::DISABLED => trace!("radio:state:DISABLED"), + RadioState::RX_RU => trace!("radio:state:RX_RU"), + RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"), + RadioState::RX => trace!("radio:state:RX"), + RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"), + RadioState::TX_RU => trace!("radio:state:TX_RU"), + RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"), + RadioState::TX => trace!("radio:state:TX"), + RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"), + } + } + + async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce() -> ()) { + //self.trace_state(); + + let r = T::regs(); + let s = T::state(); + + // If the Future is dropped before the end of the transmission + // we need to disable the interrupt and stop the transmission + // to keep the state consistent + let drop = OnDrop::new(|| { + trace!("radio drop: stopping"); + + r.intenclr.write(|w| w.end().clear()); + r.events_end.reset(); + + r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + + // The docs don't explicitly mention any event to acknowledge the stop task + // So I guess it's the same as end + while r.events_end.read().events_end().bit_is_clear() {} + + trace!("radio drop: stopped"); + }); + + /* Config interrupt */ + // trace!("radio:enable interrupt"); + // Clear some remnant side-effects (I'm unsure if this is needed) + r.events_end.reset(); + + // Enable interrupt + r.intenset.write(|w| w.end().set()); + + compiler_fence(Ordering::SeqCst); + + // Trigger the transmission + trigger(); + // self.trace_state(); + + // On poll check if interrupt happen + poll_fn(|cx| { + s.end_waker.register(cx.waker()); + if r.events_end.read().events_end().bit_is_set() { + // trace!("radio:end"); + return core::task::Poll::Ready(()); + } + Poll::Pending + }) + .await; + + compiler_fence(Ordering::SeqCst); + r.events_disabled.reset(); // ACK + + // Everthing ends fine, so we can disable the drop + drop.defuse(); + } + + /// Disable the radio. + fn disable(&mut self) { + let r = T::regs(); + + compiler_fence(Ordering::SeqCst); + // If is already disabled, do nothing + if !r.state.read().state().is_disabled() { + trace!("radio:disable"); + // Trigger the disable task + r.tasks_disable.write(|w| w.tasks_disable().set_bit()); + + // Wait until the radio is disabled + while r.events_disabled.read().events_disabled().bit_is_clear() {} + + compiler_fence(Ordering::SeqCst); + + // Acknowledge it + r.events_disabled.reset(); + } + } +} + +impl<'d, T: Instance> BleRadio for Radio<'d, T> { + type Error = Error; + + fn set_mode(&mut self, mode: Mode) { + let r = T::regs(); + r.mode.write(|w| { + w.mode().variant(match mode { + Mode::Ble1mbit => PacMode::BLE_1MBIT, + //Mode::Ble2mbit => PacMode::BLE_2MBIT, + }) + }); + + r.pcnf0.write(|w| { + w.plen().variant(match mode { + Mode::Ble1mbit => PreambleLength::_8BIT, + //Mode::Ble2mbit => PreambleLength::_16BIT, + }) + }); + } + + fn set_header_size(&mut self, header_size: HeaderSize) { + let r = T::regs(); + + let s1len: u8 = match header_size { + HeaderSize::TwoBytes => 0, + HeaderSize::ThreeBytes => 8, // bits + }; + + r.pcnf0.write(|w| unsafe { + w + // Configure S0 to 1 byte length, this will represent the Data/Adv header flags + .s0len() + .set_bit() + // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload + // and also be used to know how many bytes to read/write from/to the buffer + .lflen() + .bits(8) + // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE. + .s1len() + .bits(s1len) + }); + } + + fn set_channel(&mut self, channel: Channel) { + let r = T::regs(); + + r.frequency + .write(|w| unsafe { w.frequency().bits((channel.central_frequency() - 2400) as u8) }); + r.datawhiteiv + .write(|w| unsafe { w.datawhiteiv().bits(channel.whitening_init()) }); + } + + fn set_access_address(&mut self, access_address: u32) { + let r = T::regs(); + + // Configure logical address + // The byte ordering on air is always least significant byte first for the address + // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA + // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA + r.prefix0 + .write(|w| unsafe { w.ap0().bits((access_address >> 24) as u8) }); + + // The base address is truncated from the least significant byte (because the BALEN is less than 4) + // So we need to shift the address to the right + r.base0.write(|w| unsafe { w.bits(access_address << 8) }); + + // Don't match tx address + r.txaddress.write(|w| unsafe { w.txaddress().bits(0) }); + + // Match on logical address + // For what I understand, this config only filter the packets + // by the address, so only packages send to the previous address + // will finish the reception + r.rxaddresses.write(|w| { + w.addr0() + .enabled() + .addr1() + .enabled() + .addr2() + .enabled() + .addr3() + .enabled() + .addr4() + .enabled() + }); + } + + fn set_crc_init(&mut self, crc_init: u32) { + let r = T::regs(); + + r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) }); + } + + fn set_tx_power(&mut self, power_db: i8) { + let r = T::regs(); + + let tx_power: TxPower = match power_db { + 8..=i8::MAX => TxPower::POS8D_BM, + 7 => TxPower::POS7D_BM, + 6 => TxPower::POS6D_BM, + 5 => TxPower::POS5D_BM, + 4 => TxPower::POS4D_BM, + 3 => TxPower::POS3D_BM, + 1..=2 => TxPower::POS2D_BM, + -3..=0 => TxPower::_0D_BM, + -7..=-4 => TxPower::NEG4D_BM, + -11..=-8 => TxPower::NEG8D_BM, + -15..=-12 => TxPower::NEG12D_BM, + -19..=-16 => TxPower::NEG16D_BM, + -29..=-20 => TxPower::NEG20D_BM, + -39..=-30 => TxPower::NEG30D_BM, + i8::MIN..=-40 => TxPower::NEG40D_BM, + }; + + r.txpower.write(|w| w.txpower().variant(tx_power)); + } + + fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + // Because we are serializing the buffer, we should always have the buffer in RAM + slice_in_ram_or(buffer, Error::BufferNotInRAM)?; + + if buffer.len() > MAX_PDU_LENGTH { + return Err(Error::BufferTooLong); + } + + let r = T::regs(); + + // Here we are considering that the length of the packet is + // correctly set in the buffer, otherwise we will sending + // unowned regions of memory + let ptr = buffer.as_ptr(); + + // Configure the payload + r.packetptr.write(|w| unsafe { w.bits(ptr as u32) }); + + Ok(()) + } + + /// Send packet + async fn transmit(&mut self) { + let r = T::regs(); + + self.trigger_and_wait_end(move || { + // Initialize the transmission + // trace!("txen"); + r.tasks_txen.write(|w| w.tasks_txen().set_bit()); + }) + .await; + } + + /// Send packet + async fn receive(&mut self) { + let r = T::regs(); + + self.trigger_and_wait_end(move || { + // Initialize the transmission + // trace!("rxen"); + r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()); + + // Await until ready + while r.events_ready.read().events_ready().bit_is_clear() {} + + compiler_fence(Ordering::SeqCst); + + // Acknowledge it + r.events_ready.reset(); + + // trace!("radio:start"); + r.tasks_start.write(|w| w.tasks_start().set_bit()); + }) + .await; + } +} + +impl<'d, T: Instance> Drop for Radio<'d, T> { + fn drop(&mut self) { + self.disable(); + } +} diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs new file mode 100644 index 000000000..91cc2c0a7 --- /dev/null +++ b/embassy-nrf/src/radio/mod.rs @@ -0,0 +1,89 @@ +//! Integrated 2.4 GHz Radio +//! +//! The 2.4 GHz radio transceiver is compatible with multiple radio standards +//! such as 1Mbps, 2Mbps and Long Range Bluetooth Low Energy. + +#![macro_use] + +/// Bluetooth Low Energy Radio driver. +pub mod ble; + +use core::marker::PhantomData; + +use crate::{interrupt, pac, Peripheral}; + +/// Interrupt handler +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let r = T::regs(); + let s = T::state(); + + if r.events_end.read().events_end().bit_is_set() { + s.end_waker.wake(); + r.intenclr.write(|w| w.end().clear()); + } + } +} + +pub(crate) mod utils { + use super::*; + + // Check if the HFCLK is XTAL is enabled + pub fn check_xtal() { + // safe: only reading the value + let is_xtal = unsafe { + let r = &*pac::CLOCK::ptr(); + r.hfclkstat.read().src().is_xtal() + }; + assert!(is_xtal, "HFCLK must be XTAL"); + } +} + +pub(crate) mod sealed { + use embassy_sync::waitqueue::AtomicWaker; + + pub struct State { + /// end packet transmission or reception + pub end_waker: AtomicWaker, + } + impl State { + pub const fn new() -> Self { + Self { + end_waker: AtomicWaker::new(), + } + } + } + + pub trait Instance { + fn regs() -> &'static crate::pac::radio::RegisterBlock; + fn state() -> &'static State; + } +} + +macro_rules! impl_radio { + ($type:ident, $pac_type:ident, $irq:ident) => { + impl crate::radio::sealed::Instance for peripherals::$type { + fn regs() -> &'static pac::radio::RegisterBlock { + unsafe { &*pac::$pac_type::ptr() } + } + + fn state() -> &'static crate::radio::sealed::State { + static STATE: crate::radio::sealed::State = crate::radio::sealed::State::new(); + &STATE + } + } + impl crate::radio::Instance for peripherals::$type { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; +} + +/// Radio peripheral instance. +pub trait Instance: Peripheral

+ sealed::Instance + 'static + Send { + /// Interrupt for this peripheral. + type Interrupt: interrupt::typelevel::Interrupt; +} diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index abb995be6..0239583cd 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-time = { version = "0.3.0", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "radio"]} embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } @@ -35,6 +35,10 @@ embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } num-integer = { version = "0.1.45", default-features = false } microfft = "0.5.0" +jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel"} + +[patch.crates-io] +embassy-time = { version = "0.3.0", path = "../../embassy-time"} [profile.release] debug = 2 diff --git a/examples/nrf52840/src/bin/radio_ble_advertising.rs b/examples/nrf52840/src/bin/radio_ble_advertising.rs new file mode 100644 index 000000000..8898c2418 --- /dev/null +++ b/examples/nrf52840/src/bin/radio_ble_advertising.rs @@ -0,0 +1,42 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_nrf::{bind_interrupts, peripherals, radio}; +use embassy_time::Timer; +use jewel::phy::Radio; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RADIO => radio::InterruptHandler; +}); + +// For a high-level API look on jewel examples +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = embassy_nrf::config::Config::default(); + config.hfclk_source = embassy_nrf::config::HfclkSource::ExternalXtal; + let p = embassy_nrf::init(config); + + info!("Starting BLE radio"); + let mut radio = radio::ble::Radio::new(p.RADIO, Irqs); + + let pdu = [ + 0x46u8, // ADV_NONCONN_IND, Random address, + 0x18, // Length of payload + 0x27, 0xdc, 0xd0, 0xe8, 0xe1, 0xff, // Adress + 0x02, 0x01, 0x06, // Flags + 0x03, 0x03, 0x09, 0x18, // Complete list of 16-bit UUIDs available + 0x0A, 0x09, // Length, Type: Device name + b'H', b'e', b'l', b'l', b'o', b'R', b'u', b's', b't', + ]; + + unwrap!(radio.set_buffer(pdu.as_ref())); + + loop { + info!("Sending packet"); + radio.transmit().await; + Timer::after_millis(500).await; + } +} From 2e8b7d259057a0cf345396b250cacfc04a0e64a0 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 16:40:24 +0100 Subject: [PATCH 387/760] feat(boot): introduce non-erase flash write method --- embassy-boot/src/firmware_updater/blocking.rs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index f1368540d..514070639 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -194,6 +194,41 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> Ok(()) } + /// Write data directly to a flash page without erasing it first. + /// + /// This function writes the provided data to the specified offset in the flash memory, + /// without performing an erase operation beforehand. It is crucial that the area being + /// written to is either already erased. + /// This method is intended to be used in conjunction with the `prepare_update` method. + /// + /// The buffer must follow the alignment requirements of the target flash and be a multiple of + /// the page size. This is essential to ensure data integrity and prevent corruption. + /// + /// # Safety + /// + /// This function requires careful management of the memory being written to. Writing to a + /// non-erased page or not adhering to alignment and size requirements may result in a panic. + /// + /// Ensure that the data being written is compatible with the current contents of the flash + /// memory, as no erase operation will be performed to reset the page content to a default state. + /// + /// # Parameters + /// + /// - `offset`: The offset within the DFU partition where the data will be written. Must be + /// aligned according to the flash's requirements and within the writable memory range. + /// - `data`: A reference to the slice of bytes to be written. The length of the data must not + /// exceed the partition size and must follow the flash's alignment requirements. + /// + /// # Returns + /// + /// A result indicating the success or failure of the write operation. On success, returns `Ok(())`. + /// On failure, returns an `Err` with a `FirmwareUpdaterError` detailing the cause of the failure. + pub fn write_firmware_without_erase(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { + self.dfu.write(offset as u32, data)?; + + Ok(()) + } + /// Prepare for an incoming DFU update by erasing the entire DFU area and /// returning its `Partition`. /// From c95bf6895adfcd33b5238c02620e83c6713205ce Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 16:41:58 +0100 Subject: [PATCH 388/760] feat(usb-dfu): change usb dfu chunks write mechanism --- embassy-usb-dfu/src/dfu.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index e99aa70c3..5f2c98684 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -60,6 +60,21 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha } Ok(Request::Dnload) if self.attrs.contains(DfuAttributes::CAN_DOWNLOAD) => { if req.value == 0 { + match self.updater.prepare_update() { + Ok(_) => { + self.status = Status::Ok; + } + Err(e) => { + self.state = State::Error; + match e { + embassy_boot::FirmwareUpdaterError::Flash(e) => match e { + NorFlashErrorKind::NotAligned => self.status = Status::ErrErase, + _ => self.status = Status::ErrUnknown, + }, + _ => self.status = Status::ErrUnknown, + } + } + } self.state = State::Download; self.offset = 0; } @@ -93,7 +108,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha self.state = State::Error; return Some(OutResponse::Rejected); } - match self.updater.write_firmware(self.offset, buf.as_ref()) { + match self.updater.write_firmware_without_erase(self.offset, buf.as_ref()) { Ok(_) => { self.status = Status::Ok; self.state = State::DlSync; From d408056a66be2183dbcde6840e69e53beb4a764b Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Wed, 7 Feb 2024 17:16:46 +0100 Subject: [PATCH 389/760] remove default on radio --- embassy-nrf/src/radio/ble.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index a5d9f447b..64428fff5 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -17,10 +17,7 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; -use jewel::phy::{ - AdvertisingChannel, Channel, ChannelTrait, HeaderSize, Mode, Radio as BleRadio, ADV_ADDRESS, ADV_CRC_INIT, - CRC_POLY, MAX_PDU_LENGTH, -}; +use jewel::phy::{Channel, ChannelTrait, HeaderSize, Mode, Radio as BleRadio, CRC_POLY, MAX_PDU_LENGTH}; use pac::radio::mode::MODE_A as PacMode; use pac::radio::pcnf0::PLEN_A as PreambleLength; // Re-export SVD variants to allow user to directly set values. @@ -145,14 +142,6 @@ impl<'d, T: Instance> Radio<'d, T> { let mut radio = Self { _p: radio }; - // set defaults - radio.set_mode(Mode::Ble1mbit); - radio.set_tx_power(0); - radio.set_header_size(HeaderSize::TwoBytes); - radio.set_access_address(ADV_ADDRESS); - radio.set_crc_init(ADV_CRC_INIT); - radio.set_channel(AdvertisingChannel::Ch39.into()); - radio } From 5f1b80d40b6d2ae1636fa46e8e5334c03adeb67d Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Wed, 7 Feb 2024 18:04:29 +0100 Subject: [PATCH 390/760] remove jewel dependency --- embassy-nrf/Cargo.toml | 4 +- embassy-nrf/src/radio/ble.rs | 160 ++++++++++-------- embassy-nrf/src/radio/mod.rs | 14 -- examples/nrf52840/Cargo.toml | 4 - .../nrf52840/src/bin/radio_ble_advertising.rs | 42 ----- 5 files changed, 86 insertions(+), 138 deletions(-) delete mode 100644 examples/nrf52840/src/bin/radio_ble_advertising.rs diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index dcdc7f313..9f35bd241 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -58,7 +58,7 @@ unstable-pac = [] gpiote = [] ## Enable radio driver -radio = ["dep:jewel"] +radio = [] ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz time-driver-rtc1 = ["_time-driver"] @@ -153,8 +153,6 @@ embedded-storage-async = "0.4.0" cfg-if = "1.0.0" document-features = "0.2.7" -jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel", optional = true } - nrf51-pac = { version = "0.12.0", optional = true } nrf52805-pac = { version = "0.12.0", optional = true } nrf52810-pac = { version = "0.12.0", optional = true } diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 64428fff5..def941796 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -17,11 +17,10 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; -use jewel::phy::{Channel, ChannelTrait, HeaderSize, Mode, Radio as BleRadio, CRC_POLY, MAX_PDU_LENGTH}; -use pac::radio::mode::MODE_A as PacMode; +pub use pac::radio::mode::MODE_A as Mode; use pac::radio::pcnf0::PLEN_A as PreambleLength; -// Re-export SVD variants to allow user to directly set values. -pub use pac::radio::{state::STATE_A as RadioState, txpower::TXPOWER_A as TxPower}; +use pac::radio::state::STATE_A as RadioState; +pub use pac::radio::txpower::TXPOWER_A as TxPower; use crate::interrupt::typelevel::Interrupt; use crate::radio::*; @@ -51,11 +50,6 @@ impl<'d, T: Instance> Radio<'d, T> { radio: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - // From 5.4.1 of the nRF52840 Product Specification: - // > The HFXO must be running to use the RADIO or the calibration mechanism associated with the 32.768 kHz RC oscillator. - // Currently the jewel crate don't implement the calibration mechanism, so we need to ensure that the HFXO is running - utils::check_xtal(); - into_ref!(radio); let r = T::regs(); @@ -113,18 +107,6 @@ impl<'d, T: Instance> Radio<'d, T> { .three() }); - r.crcpoly.write(|w| unsafe { - // Configure the CRC polynomial - // Each term in the CRC polynomial is mapped to a bit in this - // register which index corresponds to the term's exponent. - // The least significant term/bit is hard-wired internally to - // 1, and bit number 0 of the register content is ignored by - // the hardware. The following example is for an 8 bit CRC - // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 . - w.crcpoly().bits(CRC_POLY & 0xFFFFFF) - }); - // The CRC initial value varies depending of the PDU type - // Ch map between 2400 MHZ .. 2500 MHz // All modes use this range r.frequency.write(|w| w.map().default()); @@ -140,9 +122,7 @@ impl<'d, T: Instance> Radio<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - let mut radio = Self { _p: radio }; - - radio + Self { _p: radio } } #[allow(dead_code)] @@ -186,7 +166,6 @@ impl<'d, T: Instance> Radio<'d, T> { trace!("radio drop: stopped"); }); - /* Config interrupt */ // trace!("radio:enable interrupt"); // Clear some remnant side-effects (I'm unsure if this is needed) r.events_end.reset(); @@ -238,34 +217,34 @@ impl<'d, T: Instance> Radio<'d, T> { r.events_disabled.reset(); } } -} -impl<'d, T: Instance> BleRadio for Radio<'d, T> { - type Error = Error; - - fn set_mode(&mut self, mode: Mode) { + /// Set the radio mode + /// + /// The radio must be disabled before calling this function + pub fn set_mode(&mut self, mode: Mode) { let r = T::regs(); - r.mode.write(|w| { - w.mode().variant(match mode { - Mode::Ble1mbit => PacMode::BLE_1MBIT, - //Mode::Ble2mbit => PacMode::BLE_2MBIT, - }) - }); + r.mode.write(|w| w.mode().variant(mode)); r.pcnf0.write(|w| { w.plen().variant(match mode { - Mode::Ble1mbit => PreambleLength::_8BIT, - //Mode::Ble2mbit => PreambleLength::_16BIT, + Mode::BLE_1MBIT => PreambleLength::_8BIT, + Mode::BLE_2MBIT => PreambleLength::_16BIT, + Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE, + _ => unimplemented!(), }) }); } - fn set_header_size(&mut self, header_size: HeaderSize) { + /// Set the header size changing the S1 field + /// + /// The radio must be disabled before calling this function + pub fn set_header_expansion(&mut self, use_s1_field: bool) { let r = T::regs(); - let s1len: u8 = match header_size { - HeaderSize::TwoBytes => 0, - HeaderSize::ThreeBytes => 8, // bits + // s1 len in bits + let s1len: u8 = match use_s1_field { + false => 0, + true => 8, }; r.pcnf0.write(|w| unsafe { @@ -283,16 +262,36 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> { }); } - fn set_channel(&mut self, channel: Channel) { + /// Set initial data whitening value + /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream + /// On BLE the initial value is the channel index | 0x40 + /// + /// The radio must be disabled before calling this function + pub fn set_whitening_init(&mut self, whitening_init: u8) { + let r = T::regs(); + + r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) }); + } + + /// Set the central frequency to be used + /// It should be in the range 2400..2500 + /// + /// The radio must be disabled before calling this function + pub fn set_frequency(&mut self, frequency: u32) { + assert!(2400 <= frequency && frequency <= 2500); let r = T::regs(); r.frequency - .write(|w| unsafe { w.frequency().bits((channel.central_frequency() - 2400) as u8) }); - r.datawhiteiv - .write(|w| unsafe { w.datawhiteiv().bits(channel.whitening_init()) }); + .write(|w| unsafe { w.frequency().bits((frequency - 2400) as u8) }); } - fn set_access_address(&mut self, access_address: u32) { + /// Set the acess address + /// This address is always constants for advertising + /// And a random value generate on each connection + /// It is used to filter the packages + /// + /// The radio must be disabled before calling this function + pub fn set_access_address(&mut self, access_address: u32) { let r = T::regs(); // Configure logical address @@ -327,44 +326,55 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> { }); } - fn set_crc_init(&mut self, crc_init: u32) { + /// Set the CRC polynomial + /// It only uses the 24 least significant bits + /// + /// The radio must be disabled before calling this function + pub fn set_crc_poly(&mut self, crc_poly: u32) { + let r = T::regs(); + + r.crcpoly.write(|w| unsafe { + // Configure the CRC polynomial + // Each term in the CRC polynomial is mapped to a bit in this + // register which index corresponds to the term's exponent. + // The least significant term/bit is hard-wired internally to + // 1, and bit number 0 of the register content is ignored by + // the hardware. The following example is for an 8 bit CRC + // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 . + w.crcpoly().bits(crc_poly & 0xFFFFFF) + }); + } + + /// Set the CRC init value + /// It only uses the 24 least significant bits + /// The CRC initial value varies depending of the PDU type + /// + /// The radio must be disabled before calling this function + pub fn set_crc_init(&mut self, crc_init: u32) { let r = T::regs(); r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) }); } - fn set_tx_power(&mut self, power_db: i8) { + /// Set the radio tx power + /// + /// The radio must be disabled before calling this function + pub fn set_tx_power(&mut self, tx_power: TxPower) { let r = T::regs(); - let tx_power: TxPower = match power_db { - 8..=i8::MAX => TxPower::POS8D_BM, - 7 => TxPower::POS7D_BM, - 6 => TxPower::POS6D_BM, - 5 => TxPower::POS5D_BM, - 4 => TxPower::POS4D_BM, - 3 => TxPower::POS3D_BM, - 1..=2 => TxPower::POS2D_BM, - -3..=0 => TxPower::_0D_BM, - -7..=-4 => TxPower::NEG4D_BM, - -11..=-8 => TxPower::NEG8D_BM, - -15..=-12 => TxPower::NEG12D_BM, - -19..=-16 => TxPower::NEG16D_BM, - -29..=-20 => TxPower::NEG20D_BM, - -39..=-30 => TxPower::NEG30D_BM, - i8::MIN..=-40 => TxPower::NEG40D_BM, - }; - r.txpower.write(|w| w.txpower().variant(tx_power)); } - fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + /// Set buffer to read/write + /// + /// This method is unsound. You should guarantee that the buffer will live + /// for the life time of the transmission or if the buffer will be modified. + /// Also if the buffer is smaller than the packet length, the radio will + /// read/write memory out of the buffer bounds. + pub fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { // Because we are serializing the buffer, we should always have the buffer in RAM slice_in_ram_or(buffer, Error::BufferNotInRAM)?; - if buffer.len() > MAX_PDU_LENGTH { - return Err(Error::BufferTooLong); - } - let r = T::regs(); // Here we are considering that the length of the packet is @@ -379,7 +389,7 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> { } /// Send packet - async fn transmit(&mut self) { + pub async fn transmit(&mut self) { let r = T::regs(); self.trigger_and_wait_end(move || { @@ -390,8 +400,8 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> { .await; } - /// Send packet - async fn receive(&mut self) { + /// Receive packet + pub async fn receive(&mut self) { let r = T::regs(); self.trigger_and_wait_end(move || { diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 91cc2c0a7..03f967f87 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -29,20 +29,6 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -pub(crate) mod utils { - use super::*; - - // Check if the HFCLK is XTAL is enabled - pub fn check_xtal() { - // safe: only reading the value - let is_xtal = unsafe { - let r = &*pac::CLOCK::ptr(); - r.hfclkstat.read().src().is_xtal() - }; - assert!(is_xtal, "HFCLK must be XTAL"); - } -} - pub(crate) mod sealed { use embassy_sync::waitqueue::AtomicWaker; diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 0239583cd..78dabe347 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -35,10 +35,6 @@ embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } num-integer = { version = "0.1.45", default-features = false } microfft = "0.5.0" -jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel"} - -[patch.crates-io] -embassy-time = { version = "0.3.0", path = "../../embassy-time"} [profile.release] debug = 2 diff --git a/examples/nrf52840/src/bin/radio_ble_advertising.rs b/examples/nrf52840/src/bin/radio_ble_advertising.rs deleted file mode 100644 index 8898c2418..000000000 --- a/examples/nrf52840/src/bin/radio_ble_advertising.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![no_std] -#![no_main] - -use defmt::{info, unwrap}; -use embassy_executor::Spawner; -use embassy_nrf::{bind_interrupts, peripherals, radio}; -use embassy_time::Timer; -use jewel::phy::Radio; -use {defmt_rtt as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - RADIO => radio::InterruptHandler; -}); - -// For a high-level API look on jewel examples -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let mut config = embassy_nrf::config::Config::default(); - config.hfclk_source = embassy_nrf::config::HfclkSource::ExternalXtal; - let p = embassy_nrf::init(config); - - info!("Starting BLE radio"); - let mut radio = radio::ble::Radio::new(p.RADIO, Irqs); - - let pdu = [ - 0x46u8, // ADV_NONCONN_IND, Random address, - 0x18, // Length of payload - 0x27, 0xdc, 0xd0, 0xe8, 0xe1, 0xff, // Adress - 0x02, 0x01, 0x06, // Flags - 0x03, 0x03, 0x09, 0x18, // Complete list of 16-bit UUIDs available - 0x0A, 0x09, // Length, Type: Device name - b'H', b'e', b'l', b'l', b'o', b'R', b'u', b's', b't', - ]; - - unwrap!(radio.set_buffer(pdu.as_ref())); - - loop { - info!("Sending packet"); - radio.transmit().await; - Timer::after_millis(500).await; - } -} From add78943146cb929d51830c1f1c74c51dd3a5d57 Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Wed, 7 Feb 2024 18:09:10 +0100 Subject: [PATCH 391/760] remove radio feature --- embassy-nrf/Cargo.toml | 3 --- embassy-nrf/src/chips/nrf52805.rs | 1 - embassy-nrf/src/chips/nrf52810.rs | 1 - embassy-nrf/src/chips/nrf52811.rs | 1 - embassy-nrf/src/chips/nrf52820.rs | 1 - embassy-nrf/src/chips/nrf52832.rs | 1 - embassy-nrf/src/chips/nrf52833.rs | 1 - embassy-nrf/src/chips/nrf52840.rs | 1 - embassy-nrf/src/chips/nrf5340_net.rs | 1 - embassy-nrf/src/lib.rs | 13 ++++++++++--- examples/nrf52840/Cargo.toml | 4 ++-- 11 files changed, 12 insertions(+), 16 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 9f35bd241..7e161df9b 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -57,9 +57,6 @@ unstable-pac = [] ## Enable GPIO tasks and events gpiote = [] -## Enable radio driver -radio = [] - ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz time-driver-rtc1 = ["_time-driver"] diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index b97c85f9e..c172dd107 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -212,7 +212,6 @@ impl_ppi_channel!(PPI_CH31, 31 => static); impl_saadc_input!(P0_04, ANALOG_INPUT2); impl_saadc_input!(P0_05, ANALOG_INPUT3); -#[cfg(feature = "radio")] impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 03548d03f..c607586db 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -238,7 +238,6 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); impl_saadc_input!(P0_30, ANALOG_INPUT6); impl_saadc_input!(P0_31, ANALOG_INPUT7); -#[cfg(feature = "radio")] impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 992fbd129..5f70365b4 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -240,7 +240,6 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); impl_saadc_input!(P0_30, ANALOG_INPUT6); impl_saadc_input!(P0_31, ANALOG_INPUT7); -#[cfg(feature = "radio")] impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index f241f4ea3..82d097407 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -227,7 +227,6 @@ impl_ppi_channel!(PPI_CH29, 29 => static); impl_ppi_channel!(PPI_CH30, 30 => static); impl_ppi_channel!(PPI_CH31, 31 => static); -#[cfg(feature = "radio")] impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 6bbdd9a63..67b32fe5f 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -267,7 +267,6 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); -#[cfg(feature = "radio")] impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index e137e4dc6..20f14e2d6 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -309,7 +309,6 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); -#[cfg(feature = "radio")] impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 2d805f871..d3272b2e8 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -314,7 +314,6 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); -#[cfg(feature = "radio")] impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index 3248bde52..65e8f9653 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -348,7 +348,6 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable); impl_ppi_channel!(PPI_CH30, 30 => configurable); impl_ppi_channel!(PPI_CH31, 31 => configurable); -#[cfg(feature = "radio")] impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 961928d11..0f64f30f2 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -46,10 +46,17 @@ pub mod gpio; #[cfg(feature = "gpiote")] pub mod gpiote; -#[cfg(feature = "radio")] +#[cfg(any( + feature = "nrf52805", + feature = "nrf52810", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52832", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340-net" +))] pub mod radio; -#[cfg(all(feature = "radio", feature = "_nrf9160"))] -compile_error!("feature `radio` is not valid for nRF91 series chips."); #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] pub mod i2s; diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 78dabe347..abb995be6 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.0", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "radio"]} +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } From 3ad45655ecea36d54f8024b5fbdad461dc07ed69 Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Wed, 7 Feb 2024 18:22:47 +0100 Subject: [PATCH 392/760] ci rerun --- embassy-nrf/src/radio/ble.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index def941796..369b49c55 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -35,7 +35,7 @@ pub enum Error { BufferTooLong, /// Buffer was to short. BufferTooShort, - /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. + /// The buffer is not in data RAM. It is most likely in flash, and nRF's DMA cannot access flash. BufferNotInRAM, } From ea8bfb4f382bddda2ca5fbe5ce4c595cd0421bd1 Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Wed, 7 Feb 2024 18:25:06 +0100 Subject: [PATCH 393/760] remove some supports --- embassy-nrf/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 0f64f30f2..767293230 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -47,11 +47,11 @@ pub mod gpio; pub mod gpiote; #[cfg(any( - feature = "nrf52805", - feature = "nrf52810", + //feature = "nrf52805", + //feature = "nrf52810", feature = "nrf52811", feature = "nrf52820", - feature = "nrf52832", + //feature = "nrf52832", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340-net" From 9527d1d934a46a50bfc8f26bd942c6f6e5c5b31b Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Wed, 7 Feb 2024 18:31:05 +0100 Subject: [PATCH 394/760] remove radio implementation on chips not tested --- embassy-nrf/src/chips/nrf52805.rs | 5 ----- embassy-nrf/src/chips/nrf52810.rs | 5 ----- embassy-nrf/src/chips/nrf52811.rs | 5 ----- embassy-nrf/src/chips/nrf52820.rs | 5 ----- embassy-nrf/src/chips/nrf52832.rs | 5 ----- embassy-nrf/src/chips/nrf52833.rs | 5 ----- embassy-nrf/src/chips/nrf5340_net.rs | 5 ----- embassy-nrf/src/lib.rs | 11 +---------- 8 files changed, 1 insertion(+), 45 deletions(-) diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index c172dd107..624d6613d 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -129,9 +129,6 @@ embassy_hal_internal::peripherals! { // QDEC QDEC, - - // RADIO - RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -212,8 +209,6 @@ impl_ppi_channel!(PPI_CH31, 31 => static); impl_saadc_input!(P0_04, ANALOG_INPUT2); impl_saadc_input!(P0_05, ANALOG_INPUT3); -impl_radio!(RADIO, RADIO, RADIO); - embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index c607586db..002feab3b 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -135,9 +135,6 @@ embassy_hal_internal::peripherals! { // PDM PDM, - - // Radio - RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -238,8 +235,6 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); impl_saadc_input!(P0_30, ANALOG_INPUT6); impl_saadc_input!(P0_31, ANALOG_INPUT7); -impl_radio!(RADIO, RADIO, RADIO); - embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 5f70365b4..5952907f8 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -135,9 +135,6 @@ embassy_hal_internal::peripherals! { // PDM PDM, - - // Radio - RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -240,8 +237,6 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); impl_saadc_input!(P0_30, ANALOG_INPUT6); impl_saadc_input!(P0_31, ANALOG_INPUT7); -impl_radio!(RADIO, RADIO, RADIO); - embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 82d097407..c2f792cb9 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -130,9 +130,6 @@ embassy_hal_internal::peripherals! { // QDEC QDEC, - - // Radio - RADIO, } impl_usb!(USBD, USBD, USBD); @@ -227,8 +224,6 @@ impl_ppi_channel!(PPI_CH29, 29 => static); impl_ppi_channel!(PPI_CH30, 30 => static); impl_ppi_channel!(PPI_CH31, 31 => static); -impl_radio!(RADIO, RADIO, RADIO); - embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 67b32fe5f..65d52364d 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -150,9 +150,6 @@ embassy_hal_internal::peripherals! { // PDM PDM, - - // Radio - RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -267,8 +264,6 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); -impl_radio!(RADIO, RADIO, RADIO); - embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 20f14e2d6..7c9b66d69 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -170,9 +170,6 @@ embassy_hal_internal::peripherals! { // I2S I2S, - - // Radio - RADIO, } impl_usb!(USBD, USBD, USBD); @@ -309,8 +306,6 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); -impl_radio!(RADIO, RADIO, RADIO); - embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index 65e8f9653..a7cf82872 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -248,9 +248,6 @@ embassy_hal_internal::peripherals! { P1_13, P1_14, P1_15, - - // Radio - RADIO, } impl_uarte!(SERIAL0, UARTE0, SERIAL0); @@ -348,8 +345,6 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable); impl_ppi_channel!(PPI_CH30, 30 => configurable); impl_ppi_channel!(PPI_CH31, 31 => configurable); -impl_radio!(RADIO, RADIO, RADIO); - embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 767293230..5dba6f975 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -46,16 +46,7 @@ pub mod gpio; #[cfg(feature = "gpiote")] pub mod gpiote; -#[cfg(any( - //feature = "nrf52805", - //feature = "nrf52810", - feature = "nrf52811", - feature = "nrf52820", - //feature = "nrf52832", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" -))] +#[cfg(any(feature = "nrf52840"))] // needs to be tested on other chips pub mod radio; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] From 2e15d1371a891cc3456d7b9fd22a68291770df41 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 8 Feb 2024 00:31:21 +0100 Subject: [PATCH 395/760] Delete tests/stm32/teleprobe.sh --- tests/stm32/teleprobe.sh | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100755 tests/stm32/teleprobe.sh diff --git a/tests/stm32/teleprobe.sh b/tests/stm32/teleprobe.sh deleted file mode 100755 index 6eec6ca93..000000000 --- a/tests/stm32/teleprobe.sh +++ /dev/null @@ -1,12 +0,0 @@ -echo Running target=$1 elf=$2 -STATUSCODE=$( - curl \ - -sS \ - --output /dev/stderr \ - --write-out "%{http_code}" \ - -H "Authorization: Bearer $TELEPROBE_TOKEN" \ - https://teleprobe.embassy.dev/targets/$1/run --data-binary @$2 -) -echo -echo HTTP Status code: $STATUSCODE -test "$STATUSCODE" -eq 200 From ab8f25fd78582aab68c9820e4b4dd9771a1ded65 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 10:47:26 +0100 Subject: [PATCH 396/760] added support for ADC of L0s --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/mod.rs | 23 ++++++++++++----------- embassy-stm32/src/adc/resolution.rs | 8 ++++---- embassy-stm32/src/adc/sample_time.rs | 2 +- embassy-stm32/src/adc/v1.rs | 21 +++++++++++++++++++++ 5 files changed, 40 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8f0fc1c59..61d70b732 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7c933984fe0cbd120b6aaa7742bd585f89fa786" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7c933984fe0cbd120b6aaa7742bd585f89fa786", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index d21c3053f..51b4b5fcc 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -8,6 +8,7 @@ #[cfg_attr(adc_f3, path = "f3.rs")] #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] #[cfg_attr(adc_v1, path = "v1.rs")] +#[cfg_attr(adc_l0, path = "v1.rs")] #[cfg_attr(adc_v2, path = "v2.rs")] #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] #[cfg_attr(adc_v4, path = "v4.rs")] @@ -36,15 +37,15 @@ pub struct Adc<'d, T: Instance> { } pub(crate) mod sealed { - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] pub struct State { pub waker: AtomicWaker, } - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] impl State { pub const fn new() -> Self { Self { @@ -59,14 +60,14 @@ pub(crate) mod sealed { pub trait Instance: InterruptableInstance { fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon; - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] fn state() -> &'static State; } pub trait AdcPin { - #[cfg(any(adc_v1, adc_v2))] + #[cfg(any(adc_v1, adc_l0, adc_v2))] fn set_as_analog(&mut self) {} fn channel(&self) -> u8; @@ -78,10 +79,10 @@ pub(crate) mod sealed { } /// ADC instance. -#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] +#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] pub trait Instance: sealed::Instance + crate::Peripheral

{} /// ADC instance. -#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] +#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} /// ADC pin. @@ -96,12 +97,12 @@ foreach_adc!( crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { return crate::pac::$common_inst } - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] fn state() -> &'static sealed::State { static STATE: sealed::State = sealed::State::new(); &STATE @@ -125,7 +126,7 @@ macro_rules! impl_adc_pin { impl crate::adc::AdcPin for crate::peripherals::$pin {} impl crate::adc::sealed::AdcPin for crate::peripherals::$pin { - #[cfg(any(adc_v1, adc_v2))] + #[cfg(any(adc_v1, adc_l0, adc_v2))] fn set_as_analog(&mut self) { ::set_as_analog(self); } diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 9513e1df7..0e6c45c65 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -1,6 +1,6 @@ /// ADC resolution #[allow(missing_docs)] -#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] +#[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Resolution { @@ -25,7 +25,7 @@ pub enum Resolution { impl Default for Resolution { fn default() -> Self { - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] { Self::TwelveBit } @@ -46,7 +46,7 @@ impl From for crate::pac::adc::vals::Res { Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, } } @@ -65,7 +65,7 @@ impl Resolution { Resolution::TwelveBit => (1 << 12) - 1, Resolution::TenBit => (1 << 10) - 1, Resolution::EightBit => (1 << 8) - 1, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] Resolution::SixBit => (1 << 6) - 1, } } diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index 5a06f1a5a..f4b22b462 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs @@ -83,7 +83,7 @@ impl_sample_time!( ) ); -#[cfg(adc_g0)] +#[cfg(any(adc_l0, adc_g0))] impl_sample_time!( "1.5", Cycles1_5, diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 852b027df..13a7ead3e 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -6,6 +6,10 @@ use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; + +#[cfg(adc_l0)] +use stm32_metapac::adc::vals::Ckmode; + use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; @@ -30,8 +34,13 @@ impl interrupt::typelevel::Handler for InterruptHandl } } +#[cfg(not(adc_l0))] pub struct Vbat; + +#[cfg(not(adc_l0))] impl AdcPin for Vbat {} + +#[cfg(not(adc_l0))] impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { 18 @@ -72,6 +81,11 @@ impl<'d, T: Instance> Adc<'d, T> { // A.7.1 ADC calibration code example T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); T::regs().cr().modify(|reg| reg.set_adcal(true)); + + #[cfg(adc_l0)] + while !T::regs().isr().read().eocal() {} + + #[cfg(not(adc_l0))] while T::regs().cr().read().adcal() {} // A.7.2 ADC enable sequence code example @@ -97,6 +111,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } + #[cfg(not(adc_l0))] pub fn enable_vbat(&self, _delay: &mut impl DelayUs) -> Vbat { // SMP must be ≥ 56 ADC clock cycles when using HSI14. // @@ -133,6 +148,12 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } + #[cfg(adc_l0)] + pub fn set_ckmode(&mut self, ckmode: Ckmode) { + // set ADC clock mode + T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode)); + } + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { let channel = pin.channel(); pin.set_as_analog(); From 8dff89bfd99140bc7de48bb5de600a2aeb920681 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:07:30 +0100 Subject: [PATCH 397/760] added ADC example running on L0 --- examples/stm32l0/src/bin/adc.rs | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 examples/stm32l0/src/bin/adc.rs diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs new file mode 100644 index 000000000..93bf5adc6 --- /dev/null +++ b/examples/stm32l0/src/bin/adc.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::Config; +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 {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ADC1_COMP => adc::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // enable HSI because default is MSI but ADC doesn't support + // this as clock source on L0s and uses HSI by default + let mut config = Config::default(); + config.rcc.hsi = true; + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); + adc.set_sample_time(SampleTime::Cycles79_5); + let mut pin = p.PA1; + + let mut vrefint = adc.enable_vref(&mut Delay); + let vrefint_sample = adc.read(&mut vrefint).await; + let convert_to_millivolts = |sample| { + // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf + // 6.3.3 Embedded internal reference voltage + const VREFINT_MV: u32 = 1224; // mV + + (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 + }; + + loop { + let v = adc.read(&mut pin).await; + info!("--> {} - {} mV", v, convert_to_millivolts(v)); + Timer::after_millis(100).await; + } +} From 158d7dbc8f4714c94cf58e48942543726d717f57 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:11:13 +0100 Subject: [PATCH 398/760] cargo fmt --- examples/stm32l0/src/bin/adc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index 93bf5adc6..f94bf907f 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -2,10 +2,10 @@ #![no_main] use defmt::*; -use embassy_stm32::Config; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; +use embassy_stm32::Config; use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; From 8d0a9bbefb29cab54ba37106a54e5e1f1f04a383 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:14:14 +0100 Subject: [PATCH 399/760] clippy --- embassy-stm32/src/adc/v1.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 13a7ead3e..92529b036 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -5,11 +5,10 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; - #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; +use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; From b2b2abeb333f9bacaa43910d1b75308a3f1c5c4e Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:14:29 +0100 Subject: [PATCH 400/760] clippy --- examples/stm32l0/src/bin/adc.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index f94bf907f..eee69211c 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -5,8 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; -use embassy_stm32::Config; -use embassy_stm32::{adc, bind_interrupts}; +use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; From dabe48c3bd647f13d62d15bbb17983be541f7583 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:15:28 +0100 Subject: [PATCH 401/760] fmt --- embassy-stm32/src/adc/v1.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 92529b036..83bf5aece 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -4,7 +4,6 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; - #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; From 34c71b58cf281e7a0d5517a3f3939477dadb5575 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:28:53 +0100 Subject: [PATCH 402/760] made adc example working with default clock configuration and switched in `v1` to PCLK/2 per default --- embassy-stm32/src/adc/v1.rs | 4 ++++ examples/stm32l0/src/bin/adc.rs | 9 ++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 83bf5aece..37115dfab 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -76,6 +76,10 @@ impl<'d, T: Instance> Adc<'d, T> { // tstab = 14 * 1/fadc delay.delay_us(1); + // set default PCKL/2 on L0s because HSI is disabled in the default clock config + #[cfg(adc_l0)] + T::regs().cfgr2().modify(|reg| reg.set_ckmode(Ckmode::PCLK_DIV2)); + // A.7.1 ADC calibration code example T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); T::regs().cr().modify(|reg| reg.set_adcal(true)); diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index eee69211c..adeaa208a 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; -use embassy_stm32::{adc, bind_interrupts, Config}; +use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -15,12 +15,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - // enable HSI because default is MSI but ADC doesn't support - // this as clock source on L0s and uses HSI by default - let mut config = Config::default(); - config.rcc.hsi = true; - let p = embassy_stm32::init(config); - + let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); From d48620d58f588936a5c74840063fe422764b749f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xgroleau=F0=9F=90=A2?= Date: Tue, 6 Feb 2024 15:50:28 -0500 Subject: [PATCH 403/760] fix: compilation for rtos trace --- ci.sh | 2 ++ embassy-executor/Cargo.toml | 4 ---- embassy-executor/src/raw/mod.rs | 12 +++++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/ci.sh b/ci.sh index df9e09848..4f28c5e92 100755 --- a/ci.sh +++ b/ci.sh @@ -23,6 +23,8 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers,rtos-trace \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \ diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 0762e2434..409df0d75 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -34,7 +34,6 @@ log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" } -embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" @@ -72,9 +71,6 @@ turbowakers = [] ## Use the executor-integrated `embassy-time` timer queue. integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"] -# Support for rtos trace require time -rtos-trace = ["dep:rtos-trace", "dep:embassy-time"] - #! ### Architecture _arch = [] # some arch was picked ## std diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index fbc0481c2..3d221c94b 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -581,6 +581,15 @@ impl embassy_time_queue_driver::TimerQueue for TimerQueue { #[cfg(feature = "integrated-timers")] embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); +#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))] +const fn gcd(a: u64, b: u64) -> u64 { + if b == 0 { + a + } else { + gcd(b, a % b) + } +} + #[cfg(feature = "rtos-trace")] impl rtos_trace::RtosTraceOSCallbacks for Executor { fn task_list() { @@ -588,7 +597,8 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { } #[cfg(feature = "integrated-timers")] fn time() -> u64 { - embassy_time::Instant::now().as_millis() + const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); + embassy_time_driver::now() * (1_000_00 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M); } #[cfg(not(feature = "integrated-timers"))] fn time() -> u64 { From 09613e90de92ba43974796efec13e38adf4c3ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xgroleau=F0=9F=90=A2?= Date: Thu, 8 Feb 2024 09:01:07 -0500 Subject: [PATCH 404/760] fix: missing 0 --- embassy-executor/src/raw/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3d221c94b..3c9407d39 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -598,7 +598,7 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { #[cfg(feature = "integrated-timers")] fn time() -> u64 { const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); - embassy_time_driver::now() * (1_000_00 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M); + embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M); } #[cfg(not(feature = "integrated-timers"))] fn time() -> u64 { From 262518cfe5c303034f71393367914bec221c71be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xgroleau=F0=9F=90=A2?= Date: Thu, 8 Feb 2024 09:02:07 -0500 Subject: [PATCH 405/760] fix: removed trailing comma --- embassy-executor/src/raw/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3c9407d39..3d5e3ab9f 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -598,7 +598,7 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { #[cfg(feature = "integrated-timers")] fn time() -> u64 { const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); - embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M); + embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M) } #[cfg(not(feature = "integrated-timers"))] fn time() -> u64 { From 27411658d9710451b04efe014747606018646527 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 8 Feb 2024 21:43:05 +0200 Subject: [PATCH 406/760] nrf: spim/spis: Add size checks for EasyDMA buffer On most nRF chips, maximum buffer size for EasyDMA is 255, thus we never got any data when attempting to use 256 bytes as RX/TX buffer. --- embassy-nrf/src/spim.rs | 14 +++++++++++--- embassy-nrf/src/spis.rs | 8 +++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 6b6f79188..8937159df 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -13,7 +13,7 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO pub use pac::spim0::config::ORDER_A as BitOrder; pub use pac::spim0::frequency::FREQUENCY_A as Frequency; -use crate::chip::FORCE_COPY_BUFFER_SIZE; +use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::sealed::Pin as _; use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; @@ -25,9 +25,9 @@ use crate::{interrupt, pac, Peripheral}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { - /// TX buffer was too long. + /// Supplied TX buffer overflows EasyDMA transmit buffer TxBufferTooLong, - /// RX buffer was too long. + /// Supplied RX buffer overflows EasyDMA receive buffer RxBufferTooLong, /// EasyDMA can only read from data memory, read only buffers in flash will fail. BufferNotInRAM, @@ -220,11 +220,19 @@ impl<'d, T: Instance> Spim<'d, T> { // Set up the DMA write. let (ptr, tx_len) = slice_ptr_parts(tx); + if tx_len > EASY_DMA_SIZE { + return Err(Error::TxBufferTooLong); + } + r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); // Set up the DMA read. let (ptr, rx_len) = slice_ptr_parts_mut(rx); + if rx_len > EASY_DMA_SIZE { + return Err(Error::RxBufferTooLong); + } + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 60f4c9865..772ca40cc 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -11,7 +11,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; pub use pac::spis0::config::ORDER_A as BitOrder; -use crate::chip::FORCE_COPY_BUFFER_SIZE; +use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::sealed::Pin as _; use crate::gpio::{self, AnyPin, Pin as GpioPin}; use crate::interrupt::typelevel::Interrupt; @@ -227,11 +227,17 @@ impl<'d, T: Instance> Spis<'d, T> { // Set up the DMA write. let (ptr, len) = slice_ptr_parts(tx); + if len > EASY_DMA_SIZE { + return Err(Error::TxBufferTooLong); + } r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); // Set up the DMA read. let (ptr, len) = slice_ptr_parts_mut(rx); + if len > EASY_DMA_SIZE { + return Err(Error::RxBufferTooLong); + } r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); From f6645750c95ac008f74b980b553117e7a390a833 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Thu, 8 Feb 2024 17:24:27 -0500 Subject: [PATCH 407/760] Removed hash DMA from unsupported configs. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/hash/mod.rs | 7 +- embassy-stm32/src/hash/{v1.rs => v1v3v4.rs} | 77 +++++++++++++++++++-- embassy-stm32/src/hash/{v2v3.rs => v2.rs} | 6 +- examples/stm32f7/.cargo/config.toml | 2 +- examples/stm32f7/src/bin/hash.rs | 9 ++- 6 files changed, 89 insertions(+), 16 deletions(-) rename embassy-stm32/src/hash/{v1.rs => v1v3v4.rs} (84%) rename embassy-stm32/src/hash/{v2v3.rs => v2.rs} (98%) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ef6063656..87815c63a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-5674011dd7db845c9d70d6a20a16129221026d25" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-36a3262735a169e31b702bcb0ac6c0067c3f078e" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-5674011dd7db845c9d70d6a20a16129221026d25", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-36a3262735a169e31b702bcb0ac6c0067c3f078e", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 6b23f3b55..64c1a0a8c 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -1,7 +1,8 @@ //! Hash Accelerator (HASH) -#[cfg_attr(hash_v1, path = "v1.rs")] -#[cfg_attr(hash_v2, path = "v2v3.rs")] -#[cfg_attr(hash_v3, path = "v2v3.rs")] +#[cfg_attr(hash_v1, path = "v1v3v4.rs")] +#[cfg_attr(hash_v2, path = "v2.rs")] +#[cfg_attr(hash_v3, path = "v1v3v4.rs")] +#[cfg_attr(hash_v4, path = "v1v3v4.rs")] mod _version; pub use _version::*; diff --git a/embassy-stm32/src/hash/v1.rs b/embassy-stm32/src/hash/v1v3v4.rs similarity index 84% rename from embassy-stm32/src/hash/v1.rs rename to embassy-stm32/src/hash/v1v3v4.rs index 36beb7c3e..771144b11 100644 --- a/embassy-stm32/src/hash/v1.rs +++ b/embassy-stm32/src/hash/v1v3v4.rs @@ -13,10 +13,16 @@ use crate::peripherals::HASH; use crate::rcc::sealed::RccPeripheral; use crate::{interrupt, pac, peripherals, Peripheral}; +#[cfg(hash_v1)] const NUM_CONTEXT_REGS: usize = 51; -const HASH_BUFFER_LEN: usize = 68; -const DIGEST_BLOCK_SIZE: usize = 64; -const MAX_DIGEST_SIZE: usize = 20; +#[cfg(hash_v3)] +const NUM_CONTEXT_REGS: usize = 103; +#[cfg(hash_v4)] +const NUM_CONTEXT_REGS: usize = 54; + +const HASH_BUFFER_LEN: usize = 132; +const DIGEST_BLOCK_SIZE: usize = 128; +const MAX_DIGEST_SIZE: usize = 128; static HASH_WAKER: AtomicWaker = AtomicWaker::new(); @@ -40,12 +46,36 @@ impl interrupt::typelevel::Handler for InterruptHandl } ///Hash algorithm selection -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq)] pub enum Algorithm { /// SHA-1 Algorithm SHA1 = 0, + + #[cfg(any(hash_v1, hash_v4))] /// MD5 Algorithm MD5 = 1, + + /// SHA-224 Algorithm + SHA224 = 2, + + /// SHA-256 Algorithm + SHA256 = 3, + + #[cfg(hash_v3)] + /// SHA-384 Algorithm + SHA384 = 12, + + #[cfg(hash_v3)] + /// SHA-512/224 Algorithm + SHA512_224 = 13, + + #[cfg(hash_v3)] + /// SHA-512/256 Algorithm + SHA512_256 = 14, + + #[cfg(hash_v3)] + /// SHA-256 Algorithm + SHA512 = 15, } /// Input data width selection @@ -83,7 +113,10 @@ pub struct Hash<'d, T: Instance> { impl<'d, T: Instance> Hash<'d, T> { /// Instantiates, resets, and enables the HASH peripheral. - pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { + pub fn new( + peripheral: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { HASH::enable_and_reset(); into_ref!(peripheral); let instance = Self { @@ -115,10 +148,31 @@ impl<'d, T: Instance> Hash<'d, T> { T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); // Select the algorithm. + #[cfg(hash_v1)] if ctx.algo == Algorithm::MD5 { T::regs().cr().modify(|w| w.set_algo(true)); } + #[cfg(hash_v2)] + { + // Select the algorithm. + let mut algo0 = false; + let mut algo1 = false; + if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 { + algo0 = true; + } + if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { + algo1 = true; + } + T::regs().cr().modify(|w| w.set_algo0(algo0)); + T::regs().cr().modify(|w| w.set_algo1(algo1)); + } + + #[cfg(any(hash_v3, hash_v4))] + T::regs().cr().modify(|w| w.set_algo(ctx.algo as u8)); + + T::regs().cr().modify(|w| w.set_init(true)); + // Store and return the state of the peripheral. self.store_context(&mut ctx).await; ctx @@ -174,7 +228,7 @@ impl<'d, T: Instance> Hash<'d, T> { ilen_remaining -= copy_len; input_start += copy_len; } - self.accumulate(&ctx.buffer[0..64]); + self.accumulate(&ctx.buffer[0..DIGEST_BLOCK_SIZE]); ctx.buflen = 0; // Move any extra data to the now-empty buffer. @@ -229,7 +283,18 @@ impl<'d, T: Instance> Hash<'d, T> { // Return the digest. let digest_words = match ctx.algo { Algorithm::SHA1 => 5, + #[cfg(any(hash_v1, hash_v4))] Algorithm::MD5 => 4, + Algorithm::SHA224 => 7, + Algorithm::SHA256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA384 => 12, + #[cfg(hash_v3)] + Algorithm::SHA512_224 => 7, + #[cfg(hash_v3)] + Algorithm::SHA512_256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA512 => 16, }; let mut i = 0; while i < digest_words { diff --git a/embassy-stm32/src/hash/v2v3.rs b/embassy-stm32/src/hash/v2.rs similarity index 98% rename from embassy-stm32/src/hash/v2v3.rs rename to embassy-stm32/src/hash/v2.rs index ba1e05f0c..b8104c825 100644 --- a/embassy-stm32/src/hash/v2v3.rs +++ b/embassy-stm32/src/hash/v2.rs @@ -111,7 +111,11 @@ pub struct Hash<'d, T: Instance, D: Dma> { impl<'d, T: Instance, D: Dma> Hash<'d, T, D> { /// Instantiates, resets, and enables the HASH peripheral. - pub fn new(peripheral: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { + pub fn new( + peripheral: impl Peripheral

+ 'd, + dma: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { HASH::enable_and_reset(); into_ref!(peripheral, dma); let instance = Self { diff --git a/examples/stm32f7/.cargo/config.toml b/examples/stm32f7/.cargo/config.toml index 9088eea6e..086da2d78 100644 --- a/examples/stm32f7/.cargo/config.toml +++ b/examples/stm32f7/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip STM32F767ZITx" +runner = "probe-rs run --chip STM32F777ZITx" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index 4bd9b4e2e..7d96bd49c 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -3,12 +3,15 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::hash::*; -use embassy_stm32::Config; +use embassy_stm32::{bind_interrupts, Config, hash, hash::*, peripherals}; use embassy_time::Instant; use sha2::{Digest, Sha256}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + HASH_RNG => hash::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let config = Config::default(); @@ -17,7 +20,7 @@ async fn main(_spawner: Spawner) -> ! { let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr"; - let mut hw_hasher = Hash::new(p.HASH, p.DMA2_CH7); + let mut hw_hasher = Hash::new(p.HASH, p.DMA2_CH7, Irqs); let hw_start_time = Instant::now(); From bb743420be5f7347cab7e2cc19a427b93e90b1e8 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 9 Feb 2024 10:14:34 +0200 Subject: [PATCH 408/760] faq: Fix typo --- docs/modules/ROOT/pages/best_practices.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/best_practices.adoc b/docs/modules/ROOT/pages/best_practices.adoc index 1e02f9ba9..bfcedec06 100644 --- a/docs/modules/ROOT/pages/best_practices.adoc +++ b/docs/modules/ROOT/pages/best_practices.adoc @@ -3,8 +3,10 @@ Over time, a couple of best practices have emerged. The following list should serve as a guideline for developers writing embedded software in _Rust_, especially in the context of the _Embassy_ framework. == Passing Buffers by Reference -It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`], to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't want to spend ressources on an allocator and end up placing buffers on the stack. -This, however, can easily blow up your stack if you are not careful. +It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`], +to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't +want to spend resources on an allocator and end up placing buffers on the stack. This, however, can easily blow up +your stack if you are not careful. Consider the following example: [,rust] From 6e2d54c40bfdb07b6bb28f5fd8009846d0695f67 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 9 Feb 2024 10:14:55 +0200 Subject: [PATCH 409/760] faq: Nightly is not required anymore --- docs/modules/ROOT/pages/faq.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index 05ff7c598..c8695a01a 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -29,11 +29,10 @@ If you see an error like this: You are likely missing some features of the `embassy-executor` crate. -For Cortex-M targets, consider making sure that ALL of the following features are active in your `Cargo.toml` for the `embassy-executor` crate: +For Cortex-M targets, check whether ALL of the following features are enabled in your `Cargo.toml` for the `embassy-executor` crate: * `arch-cortex-m` * `executor-thread` -* `nightly` For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate]. From cbdc49ef8d92606f917d1df0d88e4baef7bb23df Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 9 Feb 2024 10:15:15 +0200 Subject: [PATCH 410/760] faq: embassy-time was split into three packages, update faq accordingly I ran into this issue when I had to pull in embassy-nrf from git, though cargo didn't complain about conflicting embassy-time links. --- docs/modules/ROOT/pages/faq.adoc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index c8695a01a..7fb81e2ca 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -124,15 +124,18 @@ You have multiple versions of the same crate in your dependency tree. This means embassy crates are coming from crates.io, and some from git, each of them pulling in a different set of dependencies. -To resolve this issue, make sure to only use a single source for all your embassy crates! To do this, -you should patch your dependencies to use git sources using `[patch.crates.io]` and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`. +To resolve this issue, make sure to only use a single source for all your embassy crates! +To do this, you should patch your dependencies to use git sources using `[patch.crates.io]` +and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`. Example: [source,toml] ---- [patch.crates-io] -embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } +embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } +embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } +# embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } ---- Note that the git revision should match any other embassy patches or git dependencies that you are using! From 32f950cb5ebe478b2641a991dcaa00591ef081f6 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 9 Feb 2024 20:29:38 +0100 Subject: [PATCH 411/760] docs: use correct link to book Fixes #2550 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24347a43f..b6f667f75 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. -## Documentation - API reference - Website - Chat +## Documentation - API reference - Website - Chat ## Rust + async ❤️ embedded 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. From d6636ca11669c60925acb08c32d488c481ee1581 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 30 Jan 2024 16:54:06 +0800 Subject: [PATCH 412/760] minor fix --- embassy-stm32/src/dma/ringbuffer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs index c5b42060a..23f1d67d5 100644 --- a/embassy-stm32/src/dma/ringbuffer.rs +++ b/embassy-stm32/src/dma/ringbuffer.rs @@ -37,6 +37,7 @@ pub struct ReadableDmaRingBuffer<'a, W: Word> { } #[derive(Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct OverrunError; pub trait DmaCtrl { From dc4898ca89d2130158acf1ced1f8cb3b25efe4b8 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 30 Jan 2024 16:53:39 +0800 Subject: [PATCH 413/760] update timer mod after stm32-metapac timer_v2 --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/time_driver.rs | 8 +- embassy-stm32/src/timer/complementary_pwm.rs | 2 +- embassy-stm32/src/timer/mod.rs | 526 ++++++++++++++----- embassy-stm32/src/timer/qei.rs | 2 +- embassy-stm32/src/timer/simple_pwm.rs | 6 +- examples/stm32h7/src/bin/dac_dma.rs | 14 +- examples/stm32l4/src/bin/dac_dma.rs | 14 +- 8 files changed, 433 insertions(+), 143 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 61d70b732..c6bc27f89 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-d7c933984fe0cbd120b6aaa7742bd585f89fa786" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", rev = "stm32-data-028efe4e6e0719b661cbdf8ffda3341e4d63d0df" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-d7c933984fe0cbd120b6aaa7742bd585f89fa786", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-028efe4e6e0719b661cbdf8ffda3341e4d63d0df", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 320b29ddb..29ff4a736 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -14,7 +14,7 @@ use crate::pac::timer::vals; use crate::rcc::sealed::RccPeripheral; #[cfg(feature = "low-power")] use crate::rtc::Rtc; -use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; +use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; use crate::{interrupt, peripherals}; // NOTE regarding ALARM_COUNT: @@ -234,8 +234,8 @@ impl RtcDriver { w.set_ccie(0, true); }); - ::Interrupt::unpend(); - unsafe { ::Interrupt::enable() }; + ::Interrupt::unpend(); + unsafe { ::Interrupt::enable() }; r.cr1().modify(|w| w.set_cen(true)); } @@ -251,7 +251,7 @@ impl RtcDriver { // Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT. // Other approaches such as writing all zeros, or RMWing won't work, they can // miss interrupts. - r.sr().write_value(regs::SrGp(!sr.0)); + r.sr().write_value(regs::SrGp16(!sr.0)); // Overflow if sr.uif() { diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index eddce0404..0470e3048 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -52,7 +52,7 @@ pub struct ComplementaryPwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] pub fn new( diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 210bf7153..f66b4d094 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,5 +1,19 @@ //! Timers, PWM, quadrature decoder. +// Timer inheritance +// +// CaptureCompare16bitInstance ComplementaryCaptureCompare16bitInstance +// v v +// Core -------------------------> 1CH -------------------------> 1CH_CMP +// | | ^ | +// +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV +// | | | ^ | | ^ ^ +// | | +------|--|--------------|-----------+ | +// | +--------------------+ +--------------|-----------|---------+ +// | | | | +// | +--------------------------------------|-----------+ +// +----------------------------------------------------+ + pub mod complementary_pwm; pub mod qei; pub mod simple_pwm; @@ -19,32 +33,32 @@ pub mod low_level { pub(crate) mod sealed { use super::*; - /// Basic 16-bit timer instance. - pub trait Basic16bitInstance: RccPeripheral { + /// Virtual Core 16-bit timer instance. + pub trait CoreInstance: RccPeripheral { /// Interrupt for this timer. type Interrupt: interrupt::typelevel::Interrupt; - /// Get access to the basic 16bit timer registers. + /// Get access to the virutal core 16bit timer registers. /// /// Note: This works even if the timer is more capable, because registers /// for the less capable timers are a subset. This allows writing a driver /// for a given set of capabilities, and having it transparently work with /// more capable timers. - fn regs() -> crate::pac::timer::TimBasic; + fn regs_core() -> crate::pac::timer::TimCore; /// Start the timer. fn start(&mut self) { - Self::regs().cr1().modify(|r| r.set_cen(true)); + Self::regs_core().cr1().modify(|r| r.set_cen(true)); } /// Stop the timer. fn stop(&mut self) { - Self::regs().cr1().modify(|r| r.set_cen(false)); + Self::regs_core().cr1().modify(|r| r.set_cen(false)); } /// Reset the counter value to 0 fn reset(&mut self) { - Self::regs().cnt().write(|r| r.set_cnt(0)); + Self::regs_core().cnt().write(|r| r.set_cnt(0)); } /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. @@ -64,7 +78,7 @@ pub(crate) mod sealed { // the timer counts `0..=arr`, we want it to count `0..divide_by` let arr = unwrap!(u16::try_from(divide_by - 1)); - let regs = Self::regs(); + let regs = Self::regs_core(); regs.psc().write(|r| r.set_psc(psc)); regs.arr().write(|r| r.set_arr(arr)); @@ -77,7 +91,7 @@ pub(crate) mod sealed { /// /// Returns whether the update interrupt flag was set. fn clear_update_interrupt(&mut self) -> bool { - let regs = Self::regs(); + let regs = Self::regs_core(); let sr = regs.sr().read(); if sr.uif() { regs.sr().modify(|r| { @@ -91,29 +105,19 @@ pub(crate) mod sealed { /// Enable/disable the update interrupt. fn enable_update_interrupt(&mut self, enable: bool) { - Self::regs().dier().modify(|r| r.set_uie(enable)); - } - - /// Enable/disable the update dma. - fn enable_update_dma(&mut self, enable: bool) { - Self::regs().dier().modify(|r| r.set_ude(enable)); - } - - /// Get the update dma enable/disable state. - fn get_update_dma_state(&self) -> bool { - Self::regs().dier().read().ude() + Self::regs_core().dier().modify(|r| r.set_uie(enable)); } /// Enable/disable autoreload preload. fn set_autoreload_preload(&mut self, enable: bool) { - Self::regs().cr1().modify(|r| r.set_arpe(enable)); + Self::regs_core().cr1().modify(|r| r.set_arpe(enable)); } /// Get the timer frequency. fn get_frequency(&self) -> Hertz { let timer_f = Self::frequency(); - let regs = Self::regs(); + let regs = Self::regs_core(); let arr = regs.arr().read().arr(); let psc = regs.psc().read().psc(); @@ -121,8 +125,67 @@ pub(crate) mod sealed { } } + /// Virtual Basic without CR2 16-bit timer instance. + pub trait BasicNoCr2Instance: CoreInstance { + /// Get access to the Baisc 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2; + + /// Enable/disable the update dma. + fn enable_update_dma(&mut self, enable: bool) { + Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); + } + + /// Get the update dma enable/disable state. + fn get_update_dma_state(&self) -> bool { + Self::regs_basic_no_cr2().dier().read().ude() + } + } + + /// Basic 16-bit timer instance. + pub trait BasicInstance: BasicNoCr2Instance { + /// Get access to the Baisc 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + fn regs_basic() -> crate::pac::timer::TimBasic; + } + + /// Gneral-purpose 1 channel 16-bit timer instance. + pub trait GeneralPurpose1ChannelInstance: CoreInstance { + /// Get access to the general purpose 1 channel 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + fn regs_1ch() -> crate::pac::timer::Tim1ch; + + /// Set clock divider. + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); + } + } + + /// Gneral-purpose 1 channel 16-bit timer instance. + pub trait GeneralPurpose2ChannelInstance: GeneralPurpose1ChannelInstance { + /// Get access to the general purpose 2 channel 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + fn regs_2ch() -> crate::pac::timer::Tim2ch; + } + /// Gneral-purpose 16-bit timer instance. - pub trait GeneralPurpose16bitInstance: Basic16bitInstance { + pub trait GeneralPurpose16bitInstance: BasicInstance + GeneralPurpose2ChannelInstance { /// Get access to the general purpose 16bit timer registers. /// /// Note: This works even if the timer is more capable, because registers @@ -135,7 +198,7 @@ pub(crate) mod sealed { fn set_counting_mode(&mut self, mode: CountingMode) { let (cms, dir) = mode.into(); - let timer_enabled = Self::regs().cr1().read().cen(); + let timer_enabled = Self::regs_core().cr1().read().cen(); // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. // Changing direction is discouraged while the timer is running. assert!(!timer_enabled); @@ -149,11 +212,6 @@ pub(crate) mod sealed { let cr1 = Self::regs_gp16().cr1().read(); (cr1.cms(), cr1.dir()).into() } - - /// Set clock divider. - fn set_clock_division(&mut self, ckd: vals::Ckd) { - Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); - } } /// Gneral-purpose 32-bit timer instance. @@ -196,36 +254,67 @@ pub(crate) mod sealed { } } + /// Gneral-purpose 1 channel with one complementary 16-bit timer instance. + pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance { + /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; + + /// Enable timer outputs. + fn enable_outputs(&mut self) { + Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); + } + } + + /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. + pub trait GeneralPurpose2ChannelComplementaryInstance: + BasicInstance + GeneralPurpose1ChannelComplementaryInstance + { + /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp; + } + /// Advanced control timer instance. - pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { + pub trait AdvancedControlInstance: + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + { /// Get access to the advanced timer registers. fn regs_advanced() -> crate::pac::timer::TimAdv; } /// Capture/Compare 16-bit timer instance. - pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { + pub trait CaptureCompare16bitInstance: GeneralPurpose1ChannelInstance { /// Set input capture filter. - fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { let raw_channel = channel.index(); - Self::regs_gp16() + Self::regs_1ch() .ccmr_input(raw_channel / 2) .modify(|r| r.set_icf(raw_channel % 2, icf)); } /// Clear input interrupt. fn clear_input_interrupt(&mut self, channel: Channel) { - Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); + Self::regs_1ch().sr().modify(|r| r.set_ccif(channel.index(), false)); } /// Enable input interrupt. fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { - Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); + Self::regs_1ch().dier().modify(|r| r.set_ccie(channel.index(), enable)); } /// Set input capture prescaler. fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { let raw_channel = channel.index(); - Self::regs_gp16() + Self::regs_1ch() .ccmr_input(raw_channel / 2) .modify(|r| r.set_icpsc(raw_channel % 2, factor)); } @@ -233,14 +322,14 @@ pub(crate) mod sealed { /// Set input TI selection. fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { let raw_channel = channel.index(); - Self::regs_gp16() + Self::regs_1ch() .ccmr_input(raw_channel / 2) .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); } /// Set input capture mode. fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { - Self::regs_gp16().ccer().modify(|r| match mode { + Self::regs_1ch().ccer().modify(|r| match mode { InputCaptureMode::Rising => { r.set_ccnp(channel.index(), false); r.set_ccp(channel.index(), false); @@ -256,12 +345,9 @@ pub(crate) mod sealed { }); } - /// Enable timer outputs. - fn enable_outputs(&mut self); - /// Set output compare mode. fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - let r = Self::regs_gp16(); + let r = Self::regs_1ch(); let raw_channel: usize = channel.index(); r.ccmr_output(raw_channel / 2) .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); @@ -269,45 +355,45 @@ pub(crate) mod sealed { /// Set output polarity. fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::regs_gp16() + Self::regs_1ch() .ccer() .modify(|w| w.set_ccp(channel.index(), polarity.into())); } /// Enable/disable a channel. fn enable_channel(&mut self, channel: Channel, enable: bool) { - Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); + Self::regs_1ch().ccer().modify(|w| w.set_cce(channel.index(), enable)); } /// Get enable/disable state of a channel fn get_channel_enable_state(&self, channel: Channel) -> bool { - Self::regs_gp16().ccer().read().cce(channel.index()) + Self::regs_1ch().ccer().read().cce(channel.index()) } /// Set compare value for a channel. fn set_compare_value(&mut self, channel: Channel, value: u16) { - Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); + Self::regs_1ch().ccr(channel.index()).modify(|w| w.set_ccr(value)); } /// Get capture value for a channel. fn get_capture_value(&mut self, channel: Channel) -> u16 { - Self::regs_gp16().ccr(channel.index()).read().ccr() + Self::regs_1ch().ccr(channel.index()).read().ccr() } /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. fn get_max_compare_value(&self) -> u16 { - Self::regs_gp16().arr().read().arr() + Self::regs_1ch().arr().read().arr() } /// Get compare value for a channel. fn get_compare_value(&self, channel: Channel) -> u16 { - Self::regs_gp16().ccr(channel.index()).read().ccr() + Self::regs_1ch().ccr(channel.index()).read().ccr() } /// Set output compare preload. fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { let channel_index = channel.index(); - Self::regs_gp16() + Self::regs_1ch() .ccmr_output(channel_index / 2) .modify(|w| w.set_ocpe(channel_index % 2, preload)); } @@ -334,27 +420,29 @@ pub(crate) mod sealed { } /// Capture/Compare 16-bit timer instance with complementary pin support. - pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { + pub trait ComplementaryCaptureCompare16bitInstance: + CaptureCompare16bitInstance + GeneralPurpose1ChannelComplementaryInstance + { /// Set complementary output polarity. fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::regs_advanced() + Self::regs_1ch_cmp() .ccer() .modify(|w| w.set_ccnp(channel.index(), polarity.into())); } /// Set clock divider for the dead time. fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { - Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); + Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); } /// Set dead time, as a fraction of the max duty value. fn set_dead_time_value(&mut self, value: u8) { - Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); + Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); } /// Enable/disable a complementary channel. fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { - Self::regs_advanced() + Self::regs_1ch_cmp() .ccer() .modify(|w| w.set_ccne(channel.index(), enable)); } @@ -571,11 +659,29 @@ impl From for bool { } } -/// Basic 16-bit timer instance. -pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} +/// Virtual Core 16-bit timer instance. +pub trait CoreInstance: sealed::CoreInstance + 'static {} -/// Gneral-purpose 16-bit timer instance. -pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + Basic16bitInstance + 'static {} +/// Virtual Basic 16-bit timer without CR2 register instance. +pub trait BasicNoCr2Instance: sealed::BasicNoCr2Instance + CoreInstance + 'static {} + +/// Basic 16-bit timer instance. +pub trait BasicInstance: sealed::BasicInstance + BasicNoCr2Instance + 'static {} + +/// 1 channel 16-bit instance. +pub trait GeneralPurpose1ChannelInstance: sealed::GeneralPurpose1ChannelInstance + CoreInstance + 'static {} + +/// 2 channel 16-bit instance. +pub trait GeneralPurpose2ChannelInstance: + sealed::GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelInstance + 'static +{ +} + +/// General-purpose 16-bit timer instance. +pub trait GeneralPurpose16bitInstance: + sealed::GeneralPurpose16bitInstance + BasicInstance + GeneralPurpose2ChannelInstance + 'static +{ +} /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: @@ -583,18 +689,39 @@ pub trait GeneralPurpose32bitInstance: { } +/// General-purpose 1 channel with one complementary 16-bit timer instance. +pub trait GeneralPurpose1ChannelComplementaryInstance: + sealed::GeneralPurpose1ChannelComplementaryInstance + GeneralPurpose1ChannelInstance + 'static +{ +} + +/// General-purpose 2 channel with one complementary 16-bit timer instance. +pub trait GeneralPurpose2ChannelComplementaryInstance: + sealed::GeneralPurpose2ChannelComplementaryInstance + + BasicInstance + + GeneralPurpose1ChannelComplementaryInstance + + 'static +{ +} + /// Advanced control timer instance. -pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose16bitInstance + 'static {} +pub trait AdvancedControlInstance: + sealed::AdvancedControlInstance + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + 'static +{ +} /// Capture/Compare 16-bit timer instance. pub trait CaptureCompare16bitInstance: - sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static + sealed::CaptureCompare16bitInstance + GeneralPurpose1ChannelInstance + 'static { } /// Capture/Compare 16-bit timer instance with complementary pin support. pub trait ComplementaryCaptureCompare16bitInstance: - sealed::ComplementaryCaptureCompare16bitInstance + CaptureCompare16bitInstance + AdvancedControlInstance + 'static + sealed::ComplementaryCaptureCompare16bitInstance + + CaptureCompare16bitInstance + + GeneralPurpose1ChannelComplementaryInstance + + 'static { } @@ -621,12 +748,34 @@ pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); #[allow(unused)] -macro_rules! impl_basic_16bit_timer { +macro_rules! impl_core_timer { ($inst:ident, $irq:ident) => { - impl sealed::Basic16bitInstance for crate::peripherals::$inst { + impl sealed::CoreInstance for crate::peripherals::$inst { type Interrupt = crate::interrupt::typelevel::$irq; - fn regs() -> crate::pac::timer::TimBasic { + fn regs_core() -> crate::pac::timer::TimCore { + unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) } + } + } + }; +} + +#[allow(unused)] +macro_rules! impl_basic_no_cr2_timer { + ($inst:ident) => { + impl sealed::BasicNoCr2Instance for crate::peripherals::$inst { + fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 { + unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) } + } + } + }; +} + +#[allow(unused)] +macro_rules! impl_basic_timer { + ($inst:ident) => { + impl sealed::BasicInstance for crate::peripherals::$inst { + fn regs_basic() -> crate::pac::timer::TimBasic { unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } } } @@ -634,7 +783,40 @@ macro_rules! impl_basic_16bit_timer { } #[allow(unused)] -macro_rules! impl_32bit_timer { +macro_rules! impl_1ch_timer { + ($inst:ident) => { + impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst { + fn regs_1ch() -> crate::pac::timer::Tim1ch { + unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) } + } + } + }; +} + +#[allow(unused)] +macro_rules! impl_2ch_timer { + ($inst:ident) => { + impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst { + fn regs_2ch() -> crate::pac::timer::Tim2ch { + unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) } + } + } + }; +} + +#[allow(unused)] +macro_rules! impl_gp_16bit_timer { + ($inst:ident) => { + impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { + fn regs_gp16() -> crate::pac::timer::TimGp16 { + unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } + } + } + }; +} + +#[allow(unused)] +macro_rules! impl_gp_32bit_timer { ($inst:ident) => { impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { fn regs_gp32() -> crate::pac::timer::TimGp32 { @@ -644,84 +826,194 @@ macro_rules! impl_32bit_timer { }; } +#[allow(unused)] +macro_rules! impl_1ch_cmp_timer { + ($inst:ident) => { + impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst { + fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp { + unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) } + } + } + }; +} + +#[allow(unused)] +macro_rules! impl_2ch_cmp_timer { + ($inst:ident) => { + impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst { + fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp { + unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) } + } + } + }; +} + +#[allow(unused)] +macro_rules! impl_adv_timer { + ($inst:ident) => { + impl sealed::AdvancedControlInstance for crate::peripherals::$inst { + fn regs_advanced() -> crate::pac::timer::TimAdv { + unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } + } + } + }; +} + #[allow(unused)] macro_rules! impl_compare_capable_16bit { ($inst:ident) => { - impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { - fn enable_outputs(&mut self) {} - } + impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {} + }; +} + +#[allow(unused)] +macro_rules! impl_compare_capable_32bit { + ($inst:ident) => { + impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {} + }; +} + +#[allow(unused)] +macro_rules! impl_compare_capable_complementary_16bit { + ($inst:ident) => { + impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; } foreach_interrupt! { - ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { - impl_basic_16bit_timer!($inst, $irq); - impl Basic16bitInstance for crate::peripherals::$inst {} - }; - ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { - impl_basic_16bit_timer!($inst, $irq); - impl_compare_capable_16bit!($inst); - impl Basic16bitInstance for crate::peripherals::$inst {} - impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} - impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { - fn regs_gp16() -> crate::pac::timer::TimGp16 { - crate::pac::$inst - } - } + ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + }; + + ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_1ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + }; + + + ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_1ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl_2ch_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} + }; + + ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); + impl_1ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl_2ch_timer!($inst); + impl_gp_16bit_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} + impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { - impl_basic_16bit_timer!($inst, $irq); - impl_32bit_timer!($inst); + impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); + impl_1ch_timer!($inst); impl_compare_capable_16bit!($inst); - impl Basic16bitInstance for crate::peripherals::$inst {} + impl_compare_capable_32bit!($inst); + impl_2ch_timer!($inst); + impl_gp_16bit_timer!($inst); + impl_gp_32bit_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl CaptureCompare32bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} - impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {} - - impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { - fn regs_gp16() -> crate::pac::timer::TimGp16 { - unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } - } - } }; - ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { - impl_basic_16bit_timer!($inst, $irq); + ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_1ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl_1ch_cmp_timer!($inst); + impl_compare_capable_complementary_16bit!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + }; - impl Basic16bitInstance for crate::peripherals::$inst {} + + ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); + impl_1ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl_1ch_cmp_timer!($inst); + impl_compare_capable_complementary_16bit!($inst); + impl_2ch_cmp_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} + }; + + + ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); + impl_1ch_timer!($inst); + impl_2ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl_1ch_cmp_timer!($inst); + impl_gp_16bit_timer!($inst); + impl_compare_capable_complementary_16bit!($inst); + impl_2ch_cmp_timer!($inst); + impl_adv_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} impl AdvancedControlInstance for crate::peripherals::$inst {} - impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { - fn enable_outputs(&mut self) { - use crate::timer::sealed::AdvancedControlInstance; - let r = Self::regs_advanced(); - r.bdtr().modify(|w| w.set_moe(true)); - } - } - impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} - impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { - fn regs_gp16() -> crate::pac::timer::TimGp16 { - unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - - impl sealed::AdvancedControlInstance for crate::peripherals::$inst { - fn regs_advanced() -> crate::pac::timer::TimAdv { - crate::pac::$inst - } - } }; } // Update Event trigger DMA for every timer -dma_trait!(UpDma, Basic16bitInstance); +dma_trait!(UpDma, BasicNoCr2Instance); dma_trait!(Ch1Dma, CaptureCompare16bitInstance); dma_trait!(Ch2Dma, CaptureCompare16bitInstance); diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 59efb72ba..75e5ab12a 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -57,7 +57,7 @@ pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } -impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> Qei<'d, T> { /// Create a new quadrature decoder driver. pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 0b4c1225f..1c665d456 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -59,7 +59,7 @@ pub struct SimplePwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, @@ -84,8 +84,6 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { this.set_frequency(freq); this.inner.start(); - this.inner.enable_outputs(); - [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] .iter() .for_each(|&channel| { @@ -202,7 +200,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { &mut dma, req, duty, - T::regs_gp16().ccr(channel.index()).as_ptr() as *mut _, + T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _, dma_transfer_option, ) .await diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index 8e5c41a43..d88bd838f 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms; use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; use embassy_stm32::rcc::low_level::RccPeripheral; use embassy_stm32::time::Hertz; -use embassy_stm32::timer::low_level::Basic16bitInstance; +use embassy_stm32::timer::low_level::BasicInstance; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -75,9 +75,9 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { dac.enable(); TIM6::enable_and_reset(); - TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); - TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); - TIM6::regs().cr1().modify(|w| { + TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); + TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + TIM6::regs_basic().cr1().modify(|w| { w.set_opm(false); w.set_cen(true); }); @@ -112,9 +112,9 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { } TIM7::enable_and_reset(); - TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); - TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); - TIM7::regs().cr1().modify(|w| { + TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); + TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + TIM7::regs_basic().cr1().modify(|w| { w.set_opm(false); w.set_cen(true); }); diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index 8e5098557..f227812cd 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms; use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; use embassy_stm32::rcc::low_level::RccPeripheral; use embassy_stm32::time::Hertz; -use embassy_stm32::timer::low_level::Basic16bitInstance; +use embassy_stm32::timer::low_level::BasicInstance; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -46,9 +46,9 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { dac.enable(); TIM6::enable_and_reset(); - TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); - TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); - TIM6::regs().cr1().modify(|w| { + TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); + TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + TIM6::regs_basic().cr1().modify(|w| { w.set_opm(false); w.set_cen(true); }); @@ -83,9 +83,9 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { } TIM7::enable_and_reset(); - TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); - TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); - TIM7::regs().cr1().modify(|w| { + TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); + TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + TIM7::regs_basic().cr1().modify(|w| { w.set_opm(false); w.set_cen(true); }); From 53bf0332e9e862fa5c09a1e9ab9a6d7116219ed7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 10 Feb 2024 00:00:26 +0100 Subject: [PATCH 414/760] asdkf --- embassy-stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index c6bc27f89..eb67404d3 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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", rev = "stm32-data-028efe4e6e0719b661cbdf8ffda3341e4d63d0df" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-028efe4e6e0719b661cbdf8ffda3341e4d63d0df" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" From d538829f2f3542c78ee9eb218c0b5c982acfb46b Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 1 Feb 2024 17:10:47 +0800 Subject: [PATCH 415/760] add methods with macro --- embassy-stm32/src/timer/complementary_pwm.rs | 52 +- embassy-stm32/src/timer/mod.rs | 522 ++++++++---------- embassy-stm32/src/timer/qei.rs | 4 +- embassy-stm32/src/timer/simple_pwm.rs | 40 +- .../stm32h7/src/bin/low_level_timer_api.rs | 4 +- 5 files changed, 298 insertions(+), 324 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 0470e3048..b9cd044c9 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -1,6 +1,7 @@ //! PWM driver with complementary output support. use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; use embassy_hal_internal::{into_ref, PeripheralRef}; use stm32_metapac::timer::vals::Ckd; @@ -23,7 +24,7 @@ pub struct ComplementaryPwmPin<'d, T, C> { macro_rules! complementary_channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { + impl<'d, T: AdvancedControlInstance> ComplementaryPwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); @@ -52,7 +53,7 @@ pub struct ComplementaryPwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { +impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] pub fn new( @@ -84,27 +85,30 @@ impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstan this.inner.enable_outputs(); - this.inner - .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); - this.inner - .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); - this.inner - .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); - this.inner - .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); + [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] + .iter() + .for_each(|&channel| { + sealed::GeneralPurpose16bitInstance::set_output_compare_mode( + this.inner.deref_mut(), + channel, + OutputCompareMode::PwmMode1, + ); + sealed::GeneralPurpose16bitInstance::set_output_compare_preload(this.inner.deref_mut(), channel, true); + }); + this } /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { - self.inner.enable_channel(channel, true); - self.inner.enable_complementary_channel(channel, true); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); + sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, true); } /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { - self.inner.enable_complementary_channel(channel, false); - self.inner.enable_channel(channel, false); + sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, false); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); } /// Set PWM frequency. @@ -132,13 +136,13 @@ impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstan /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) } /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - self.inner.set_output_polarity(channel, polarity); - self.inner.set_complementary_output_polarity(channel, polarity); + sealed::GeneralPurpose16bitInstance::set_output_polarity(self.inner.deref_mut(), channel, polarity); + sealed::AdvancedControlInstance::set_complementary_output_polarity(self.inner.deref_mut(), channel, polarity); } /// Set the dead time as a proportion of max_duty @@ -150,19 +154,19 @@ impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstan } } -impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { +impl<'d, T: AdvancedControlInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; fn disable(&mut self, channel: Self::Channel) { - self.inner.enable_complementary_channel(channel, false); - self.inner.enable_channel(channel, false); + sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, false); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); } fn enable(&mut self, channel: Self::Channel) { - self.inner.enable_channel(channel, true); - self.inner.enable_complementary_channel(channel, true); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); + sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, true); } fn get_period(&self) -> Self::Time { @@ -170,7 +174,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - self.inner.get_compare_value(channel) + sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) } fn get_max_duty(&self) -> Self::Duty { @@ -179,7 +183,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) } fn set_period

(&mut self, period: P) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index f66b4d094..2f5d5770a 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -2,8 +2,6 @@ // Timer inheritance // -// CaptureCompare16bitInstance ComplementaryCaptureCompare16bitInstance -// v v // Core -------------------------> 1CH -------------------------> 1CH_CMP // | | ^ | // +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV @@ -33,6 +31,156 @@ pub mod low_level { pub(crate) mod sealed { use super::*; + macro_rules! add_capture_compare_common_methods { + ($regs:ident) => { + /// Set input capture filter. + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { + let raw_channel = channel.index(); + Self::$regs() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + + /// Clear input interrupt. + fn clear_input_interrupt(&mut self, channel: Channel) { + Self::$regs().sr().modify(|r| r.set_ccif(channel.index(), false)); + } + + /// Enable input interrupt. + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + Self::$regs() + .dier() + .modify(|r| r.set_ccie(channel.index(), enable)); + } + + /// Set input capture prescaler. + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + let raw_channel = channel.index(); + Self::$regs() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + /// Set input TI selection. + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + let raw_channel = channel.index(); + Self::$regs() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + + /// Set input capture mode. + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + Self::$regs().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.index(), true); + r.set_ccp(channel.index(), true); + } + }); + } + + /// Set output compare mode. + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { + let r = Self::$regs(); + let raw_channel: usize = channel.index(); + r.ccmr_output(raw_channel / 2) + .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); + } + + /// Set output polarity. + fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + Self::$regs() + .ccer() + .modify(|w| w.set_ccp(channel.index(), polarity.into())); + } + + /// Enable/disable a channel. + fn enable_channel(&mut self, channel: Channel, enable: bool) { + Self::$regs() + .ccer() + .modify(|w| w.set_cce(channel.index(), enable)); + } + + /// Get enable/disable state of a channel + fn get_channel_enable_state(&self, channel: Channel) -> bool { + Self::$regs().ccer().read().cce(channel.index()) + } + + /// Set compare value for a channel. + fn set_compare_value(&mut self, channel: Channel, value: u16) { + Self::$regs().ccr(channel.index()).modify(|w| w.set_ccr(value)); + } + + /// Get capture value for a channel. + fn get_capture_value(&mut self, channel: Channel) -> u16 { + Self::$regs().ccr(channel.index()).read().ccr() + } + + /// Get compare value for a channel. + fn get_compare_value(&self, channel: Channel) -> u16 { + Self::$regs().ccr(channel.index()).read().ccr() + } + + /// Set output compare preload. + fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { + let channel_index = channel.index(); + Self::regs_1ch() + .ccmr_output(channel_index / 2) + .modify(|w| w.set_ocpe(channel_index % 2, preload)); + } + }; + } + + macro_rules! add_capture_compare_dma_methods { + ($regs:ident) => { + /// Get capture compare DMA selection + fn get_cc_dma_selection(&self) -> super::vals::Ccds { + Self::$regs().cr2().read().ccds() + } + + /// Set capture compare DMA selection + fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { + Self::$regs().cr2().modify(|w| w.set_ccds(ccds)) + } + + /// Get capture compare DMA enable state + fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { + Self::$regs().dier().read().ccde(channel.index()) + } + + /// Set capture compare DMA enable state + fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { + Self::$regs().dier().modify(|w| w.set_ccde(channel.index(), ccde)) + } + }; + } + + macro_rules! add_complementary_capture_compare_methods { + ($regs:ident) => { + /// Set complementary output polarity. + fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + Self::$regs() + .ccer() + .modify(|w| w.set_ccnp(channel.index(), polarity.into())); + } + + /// Enable/disable a complementary channel. + fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { + Self::$regs() + .ccer() + .modify(|w| w.set_ccne(channel.index(), enable)); + } + }; + } + /// Virtual Core 16-bit timer instance. pub trait CoreInstance: RccPeripheral { /// Interrupt for this timer. @@ -171,6 +319,13 @@ pub(crate) mod sealed { fn set_clock_division(&mut self, ckd: vals::Ckd) { Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); } + + /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. + fn get_max_compare_value(&self) -> u16 { + Self::regs_1ch().arr().read().arr() + } + + add_capture_compare_common_methods!(regs_1ch); } /// Gneral-purpose 1 channel 16-bit timer instance. @@ -182,6 +337,8 @@ pub(crate) mod sealed { /// for a given set of capabilities, and having it transparently work with /// more capable timers. fn regs_2ch() -> crate::pac::timer::Tim2ch; + + add_capture_compare_common_methods!(regs_2ch); } /// Gneral-purpose 16-bit timer instance. @@ -212,6 +369,9 @@ pub(crate) mod sealed { let cr1 = Self::regs_gp16().cr1().read(); (cr1.cms(), cr1.dir()).into() } + + add_capture_compare_common_methods!(regs_gp16); + add_capture_compare_dma_methods!(regs_gp16); } /// Gneral-purpose 32-bit timer instance. @@ -252,204 +412,7 @@ pub(crate) mod sealed { timer_f / arr / (psc + 1) } - } - /// Gneral-purpose 1 channel with one complementary 16-bit timer instance. - pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance { - /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; - - /// Enable timer outputs. - fn enable_outputs(&mut self) { - Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); - } - } - - /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. - pub trait GeneralPurpose2ChannelComplementaryInstance: - BasicInstance + GeneralPurpose1ChannelComplementaryInstance - { - /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp; - } - - /// Advanced control timer instance. - pub trait AdvancedControlInstance: - GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance - { - /// Get access to the advanced timer registers. - fn regs_advanced() -> crate::pac::timer::TimAdv; - } - - /// Capture/Compare 16-bit timer instance. - pub trait CaptureCompare16bitInstance: GeneralPurpose1ChannelInstance { - /// Set input capture filter. - fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { - let raw_channel = channel.index(); - Self::regs_1ch() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icf(raw_channel % 2, icf)); - } - - /// Clear input interrupt. - fn clear_input_interrupt(&mut self, channel: Channel) { - Self::regs_1ch().sr().modify(|r| r.set_ccif(channel.index(), false)); - } - - /// Enable input interrupt. - fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { - Self::regs_1ch().dier().modify(|r| r.set_ccie(channel.index(), enable)); - } - - /// Set input capture prescaler. - fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { - let raw_channel = channel.index(); - Self::regs_1ch() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icpsc(raw_channel % 2, factor)); - } - - /// Set input TI selection. - fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { - let raw_channel = channel.index(); - Self::regs_1ch() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); - } - - /// Set input capture mode. - fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { - Self::regs_1ch().ccer().modify(|r| match mode { - InputCaptureMode::Rising => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), false); - } - InputCaptureMode::Falling => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), true); - } - InputCaptureMode::BothEdges => { - r.set_ccnp(channel.index(), true); - r.set_ccp(channel.index(), true); - } - }); - } - - /// Set output compare mode. - fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - let r = Self::regs_1ch(); - let raw_channel: usize = channel.index(); - r.ccmr_output(raw_channel / 2) - .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); - } - - /// Set output polarity. - fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::regs_1ch() - .ccer() - .modify(|w| w.set_ccp(channel.index(), polarity.into())); - } - - /// Enable/disable a channel. - fn enable_channel(&mut self, channel: Channel, enable: bool) { - Self::regs_1ch().ccer().modify(|w| w.set_cce(channel.index(), enable)); - } - - /// Get enable/disable state of a channel - fn get_channel_enable_state(&self, channel: Channel) -> bool { - Self::regs_1ch().ccer().read().cce(channel.index()) - } - - /// Set compare value for a channel. - fn set_compare_value(&mut self, channel: Channel, value: u16) { - Self::regs_1ch().ccr(channel.index()).modify(|w| w.set_ccr(value)); - } - - /// Get capture value for a channel. - fn get_capture_value(&mut self, channel: Channel) -> u16 { - Self::regs_1ch().ccr(channel.index()).read().ccr() - } - - /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. - fn get_max_compare_value(&self) -> u16 { - Self::regs_1ch().arr().read().arr() - } - - /// Get compare value for a channel. - fn get_compare_value(&self, channel: Channel) -> u16 { - Self::regs_1ch().ccr(channel.index()).read().ccr() - } - - /// Set output compare preload. - fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { - let channel_index = channel.index(); - Self::regs_1ch() - .ccmr_output(channel_index / 2) - .modify(|w| w.set_ocpe(channel_index % 2, preload)); - } - - /// Get capture compare DMA selection - fn get_cc_dma_selection(&self) -> super::vals::Ccds { - Self::regs_gp16().cr2().read().ccds() - } - - /// Set capture compare DMA selection - fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { - Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) - } - - /// Get capture compare DMA enable state - fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { - Self::regs_gp16().dier().read().ccde(channel.index()) - } - - /// Set capture compare DMA enable state - fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { - Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) - } - } - - /// Capture/Compare 16-bit timer instance with complementary pin support. - pub trait ComplementaryCaptureCompare16bitInstance: - CaptureCompare16bitInstance + GeneralPurpose1ChannelComplementaryInstance - { - /// Set complementary output polarity. - fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::regs_1ch_cmp() - .ccer() - .modify(|w| w.set_ccnp(channel.index(), polarity.into())); - } - - /// Set clock divider for the dead time. - fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { - Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); - } - - /// Set dead time, as a fraction of the max duty value. - fn set_dead_time_value(&mut self, value: u8) { - Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); - } - - /// Enable/disable a complementary channel. - fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { - Self::regs_1ch_cmp() - .ccer() - .modify(|w| w.set_ccne(channel.index(), enable)); - } - } - - /// Capture/Compare 32-bit timer instance. - pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { /// Set comapre value for a channel. fn set_compare_value(&mut self, channel: Channel, value: u32) { Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); @@ -470,6 +433,59 @@ pub(crate) mod sealed { Self::regs_gp32().ccr(channel.index()).read().ccr() } } + + /// Gneral-purpose 1 channel with one complementary 16-bit timer instance. + pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance { + /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; + + /// Set clock divider for the dead time. + fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { + Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); + } + + /// Set dead time, as a fraction of the max duty value. + fn set_dead_time_value(&mut self, value: u8) { + Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); + } + + /// Enable timer outputs. + fn enable_outputs(&mut self) { + Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); + } + + add_complementary_capture_compare_methods!(regs_1ch_cmp); + } + + /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. + pub trait GeneralPurpose2ChannelComplementaryInstance: + BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance + { + /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp; + + add_complementary_capture_compare_methods!(regs_2ch_cmp); + } + + /// Advanced control timer instance. + pub trait AdvancedControlInstance: + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + { + /// Get access to the advanced timer registers. + fn regs_advanced() -> crate::pac::timer::TimAdv; + + add_complementary_capture_compare_methods!(regs_advanced); + } } /// Timer channel. @@ -699,6 +715,7 @@ pub trait GeneralPurpose1ChannelComplementaryInstance: pub trait GeneralPurpose2ChannelComplementaryInstance: sealed::GeneralPurpose2ChannelComplementaryInstance + BasicInstance + + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance + 'static { @@ -710,42 +727,30 @@ pub trait AdvancedControlInstance: { } -/// Capture/Compare 16-bit timer instance. -pub trait CaptureCompare16bitInstance: - sealed::CaptureCompare16bitInstance + GeneralPurpose1ChannelInstance + 'static -{ -} +pin_trait!(Channel1Pin, GeneralPurpose1ChannelInstance); +pin_trait!(Channel2Pin, GeneralPurpose2ChannelInstance); +pin_trait!(Channel3Pin, GeneralPurpose16bitInstance); +pin_trait!(Channel4Pin, GeneralPurpose16bitInstance); -/// Capture/Compare 16-bit timer instance with complementary pin support. -pub trait ComplementaryCaptureCompare16bitInstance: - sealed::ComplementaryCaptureCompare16bitInstance - + CaptureCompare16bitInstance - + GeneralPurpose1ChannelComplementaryInstance - + 'static -{ -} +#[cfg(not(stm32l0))] +pin_trait!(ExternalTriggerPin, GeneralPurpose16bitInstance); -/// Capture/Compare 32-bit timer instance. -pub trait CaptureCompare32bitInstance: - sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static -{ -} +#[cfg(stm32l0)] +pin_trait!(ExternalTriggerPin, GeneralPurpose2ChannelInstance); -pin_trait!(Channel1Pin, CaptureCompare16bitInstance); -pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance); -pin_trait!(Channel2Pin, CaptureCompare16bitInstance); -pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance); -pin_trait!(Channel3Pin, CaptureCompare16bitInstance); -pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance); -pin_trait!(Channel4Pin, CaptureCompare16bitInstance); -pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance); -pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); -pin_trait!(BreakInputPin, CaptureCompare16bitInstance); -pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance); -pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); -pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); -pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); -pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); +pin_trait!(Channel1ComplementaryPin, GeneralPurpose1ChannelComplementaryInstance); +pin_trait!(Channel2ComplementaryPin, GeneralPurpose2ChannelComplementaryInstance); +pin_trait!(Channel3ComplementaryPin, AdvancedControlInstance); +pin_trait!(Channel4ComplementaryPin, AdvancedControlInstance); + +pin_trait!(BreakInputPin, GeneralPurpose1ChannelComplementaryInstance); +pin_trait!(BreakInput2Pin, GeneralPurpose2ChannelComplementaryInstance); + +pin_trait!(BreakInputComparator1Pin, GeneralPurpose1ChannelComplementaryInstance); +pin_trait!(BreakInputComparator2Pin, AdvancedControlInstance); + +pin_trait!(BreakInput2Comparator1Pin, AdvancedControlInstance); +pin_trait!(BreakInput2Comparator2Pin, AdvancedControlInstance); #[allow(unused)] macro_rules! impl_core_timer { @@ -859,27 +864,6 @@ macro_rules! impl_adv_timer { }; } -#[allow(unused)] -macro_rules! impl_compare_capable_16bit { - ($inst:ident) => { - impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {} - }; -} - -#[allow(unused)] -macro_rules! impl_compare_capable_32bit { - ($inst:ident) => { - impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {} - }; -} - -#[allow(unused)] -macro_rules! impl_compare_capable_complementary_16bit { - ($inst:ident) => { - impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} - }; -} - foreach_interrupt! { ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { @@ -894,21 +878,17 @@ foreach_interrupt! { ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { impl_core_timer!($inst, $irq); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl CoreInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { impl_core_timer!($inst, $irq); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl_2ch_timer!($inst); impl CoreInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} }; @@ -917,14 +897,12 @@ foreach_interrupt! { impl_basic_no_cr2_timer!($inst); impl_basic_timer!($inst); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl_2ch_timer!($inst); impl_gp_16bit_timer!($inst); impl CoreInstance for crate::peripherals::$inst {} impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} }; @@ -934,8 +912,6 @@ foreach_interrupt! { impl_basic_no_cr2_timer!($inst); impl_basic_timer!($inst); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); - impl_compare_capable_32bit!($inst); impl_2ch_timer!($inst); impl_gp_16bit_timer!($inst); impl_gp_32bit_timer!($inst); @@ -943,8 +919,6 @@ foreach_interrupt! { impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} - impl CaptureCompare32bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} @@ -954,15 +928,11 @@ foreach_interrupt! { impl_core_timer!($inst, $irq); impl_basic_no_cr2_timer!($inst); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl_1ch_cmp_timer!($inst); - impl_compare_capable_complementary_16bit!($inst); impl CoreInstance for crate::peripherals::$inst {} impl BasicNoCr2Instance for crate::peripherals::$inst{} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; @@ -971,17 +941,15 @@ foreach_interrupt! { impl_basic_no_cr2_timer!($inst); impl_basic_timer!($inst); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); + impl_2ch_timer!($inst); impl_1ch_cmp_timer!($inst); - impl_compare_capable_complementary_16bit!($inst); impl_2ch_cmp_timer!($inst); impl CoreInstance for crate::peripherals::$inst {} impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} }; @@ -992,10 +960,8 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl_1ch_cmp_timer!($inst); impl_gp_16bit_timer!($inst); - impl_compare_capable_complementary_16bit!($inst); impl_2ch_cmp_timer!($inst); impl_adv_timer!($inst); impl CoreInstance for crate::peripherals::$inst {} @@ -1004,9 +970,7 @@ foreach_interrupt! { impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} impl AdvancedControlInstance for crate::peripherals::$inst {} }; @@ -1015,7 +979,7 @@ foreach_interrupt! { // Update Event trigger DMA for every timer dma_trait!(UpDma, BasicNoCr2Instance); -dma_trait!(Ch1Dma, CaptureCompare16bitInstance); -dma_trait!(Ch2Dma, CaptureCompare16bitInstance); -dma_trait!(Ch3Dma, CaptureCompare16bitInstance); -dma_trait!(Ch4Dma, CaptureCompare16bitInstance); +dma_trait!(Ch1Dma, GeneralPurpose1ChannelInstance); +dma_trait!(Ch2Dma, GeneralPurpose2ChannelInstance); +dma_trait!(Ch3Dma, GeneralPurpose16bitInstance); +dma_trait!(Ch4Dma, GeneralPurpose16bitInstance); diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 75e5ab12a..7e56312bb 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -30,7 +30,7 @@ pub struct QeiPin<'d, T, Channel> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { + impl<'d, T: GeneralPurpose16bitInstance> QeiPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); @@ -57,7 +57,7 @@ pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> Qei<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance> Qei<'d, T> { /// Create a new quadrature decoder driver. pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1c665d456..088d02c97 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -1,6 +1,7 @@ //! Simple PWM driver. use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; use embassy_hal_internal::{into_ref, PeripheralRef}; @@ -30,7 +31,7 @@ pub struct PwmPin<'d, T, C> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { + impl<'d, T: GeneralPurpose16bitInstance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); @@ -59,7 +60,7 @@ pub struct SimplePwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, @@ -87,8 +88,13 @@ impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] .iter() .for_each(|&channel| { - this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); - this.inner.set_output_compare_preload(channel, true) + sealed::GeneralPurpose16bitInstance::set_output_compare_mode( + this.inner.deref_mut(), + channel, + OutputCompareMode::PwmMode1, + ); + + sealed::GeneralPurpose16bitInstance::set_output_compare_preload(this.inner.deref_mut(), channel, true); }); this @@ -96,17 +102,17 @@ impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { - self.inner.enable_channel(channel, true); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); } /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { - self.inner.enable_channel(channel, false); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); } /// Check whether given channel is enabled pub fn is_enabled(&self, channel: Channel) -> bool { - self.inner.get_channel_enable_state(channel) + sealed::GeneralPurpose16bitInstance::get_channel_enable_state(self.inner.deref(), channel) } /// Set PWM frequency. @@ -134,24 +140,24 @@ impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) } /// Get the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn get_duty(&self, channel: Channel) -> u16 { - self.inner.get_compare_value(channel) + sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) } /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - self.inner.set_output_polarity(channel, polarity); + sealed::GeneralPurpose16bitInstance::set_output_polarity(self.inner.deref_mut(), channel, polarity); } /// Set the output compare mode for a given channel. pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - self.inner.set_output_compare_mode(channel, mode); + sealed::GeneralPurpose16bitInstance::set_output_compare_mode(self.inner.deref_mut(), channel, mode); } /// Generate a sequence of PWM waveform @@ -226,7 +232,7 @@ impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm macro_rules! impl_waveform_chx { ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { - impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { + impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform /// /// Note: @@ -313,17 +319,17 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); -impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; fn disable(&mut self, channel: Self::Channel) { - self.inner.enable_channel(channel, false); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); } fn enable(&mut self, channel: Self::Channel) { - self.inner.enable_channel(channel, true); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); } fn get_period(&self) -> Self::Time { @@ -331,7 +337,7 @@ impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - self.inner.get_compare_value(channel) + sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) } fn get_max_duty(&self) -> Self::Duty { @@ -340,7 +346,7 @@ impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) } fn set_period

(&mut self, period: P) diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index cc508c3cf..0be3eccb7 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -56,11 +56,11 @@ async fn main(_spawner: Spawner) { Timer::after_millis(300).await; } } -pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { +pub struct SimplePwm32<'d, T: GeneralPurpose32bitInstance> { inner: PeripheralRef<'d, T>, } -impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { +impl<'d, T: GeneralPurpose32bitInstance> SimplePwm32<'d, T> { pub fn new( tim: impl Peripheral

+ 'd, ch1: impl Peripheral

> + 'd, From 5b646bc3bd0c4a2cd9acf6a59b3a76f2bbcb0bfb Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 1 Feb 2024 23:04:39 +0800 Subject: [PATCH 416/760] stm32-timer: L0 is special --- embassy-stm32/src/timer/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 2f5d5770a..8be96b414 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -12,6 +12,7 @@ // | +--------------------------------------|-----------+ // +----------------------------------------------------+ +#[cfg(not(any(stm32l0, stm32l1)))] pub mod complementary_pwm; pub mod qei; pub mod simple_pwm; @@ -163,6 +164,7 @@ pub(crate) mod sealed { }; } + #[cfg(not(any(stm32l0, stm32l1)))] macro_rules! add_complementary_capture_compare_methods { ($regs:ident) => { /// Set complementary output polarity. @@ -374,6 +376,7 @@ pub(crate) mod sealed { add_capture_compare_dma_methods!(regs_gp16); } + #[cfg(not(any(stm32l0)))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { /// Get access to the general purpose 32bit timer registers. @@ -434,6 +437,7 @@ pub(crate) mod sealed { } } + #[cfg(not(any(stm32l0, stm32l1)))] /// Gneral-purpose 1 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance { /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. @@ -462,6 +466,7 @@ pub(crate) mod sealed { add_complementary_capture_compare_methods!(regs_1ch_cmp); } + #[cfg(not(any(stm32l0, stm32l1)))] /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose2ChannelComplementaryInstance: BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance @@ -477,6 +482,7 @@ pub(crate) mod sealed { add_complementary_capture_compare_methods!(regs_2ch_cmp); } + #[cfg(not(any(stm32l0, stm32l1)))] /// Advanced control timer instance. pub trait AdvancedControlInstance: GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance @@ -699,18 +705,21 @@ pub trait GeneralPurpose16bitInstance: { } +#[cfg(not(stm32l0))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static { } +#[cfg(not(any(stm32l0, stm32l1)))] /// General-purpose 1 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose1ChannelComplementaryInstance: sealed::GeneralPurpose1ChannelComplementaryInstance + GeneralPurpose1ChannelInstance + 'static { } +#[cfg(not(any(stm32l0, stm32l1)))] /// General-purpose 2 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose2ChannelComplementaryInstance: sealed::GeneralPurpose2ChannelComplementaryInstance @@ -721,6 +730,7 @@ pub trait GeneralPurpose2ChannelComplementaryInstance: { } +#[cfg(not(any(stm32l0, stm32l1)))] /// Advanced control timer instance. pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + 'static @@ -738,18 +748,28 @@ pin_trait!(ExternalTriggerPin, GeneralPurpose16bitInstance); #[cfg(stm32l0)] pin_trait!(ExternalTriggerPin, GeneralPurpose2ChannelInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(Channel1ComplementaryPin, GeneralPurpose1ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(Channel2ComplementaryPin, GeneralPurpose2ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(Channel3ComplementaryPin, AdvancedControlInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(Channel4ComplementaryPin, AdvancedControlInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInputPin, GeneralPurpose1ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInput2Pin, GeneralPurpose2ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInputComparator1Pin, GeneralPurpose1ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInputComparator2Pin, AdvancedControlInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInput2Comparator1Pin, AdvancedControlInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInput2Comparator2Pin, AdvancedControlInstance); #[allow(unused)] From 319f10da5daff415ad2dac17f4eed43313455167 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 1 Feb 2024 23:41:32 +0800 Subject: [PATCH 417/760] stm32-timer: filter out c0, f1 and f37x --- embassy-stm32/src/timer/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 8be96b414..be5c6cf29 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -376,7 +376,7 @@ pub(crate) mod sealed { add_capture_compare_dma_methods!(regs_gp16); } - #[cfg(not(any(stm32l0)))] + #[cfg(not(any(stm32f1, stm32l0, stm32c0)))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { /// Get access to the general purpose 32bit timer registers. @@ -705,7 +705,7 @@ pub trait GeneralPurpose16bitInstance: { } -#[cfg(not(stm32l0))] +#[cfg(not(any(stm32f1, stm32l0, stm32c0)))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static @@ -730,7 +730,7 @@ pub trait GeneralPurpose2ChannelComplementaryInstance: { } -#[cfg(not(any(stm32l0, stm32l1)))] +#[cfg(not(any(stm32f37, stm32l0, stm32l1)))] /// Advanced control timer instance. pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + 'static From b3cdf3a040ae97923e84eca525505f7eff55e870 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 2 Feb 2024 14:52:54 +0800 Subject: [PATCH 418/760] bug fix --- embassy-stm32/src/timer/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index be5c6cf29..3e303a6cf 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -90,9 +90,9 @@ pub(crate) mod sealed { /// Set output compare mode. fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - let r = Self::$regs(); let raw_channel: usize = channel.index(); - r.ccmr_output(raw_channel / 2) + Self::$regs() + .ccmr_output(raw_channel / 2) .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); } @@ -133,7 +133,7 @@ pub(crate) mod sealed { /// Set output compare preload. fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { let channel_index = channel.index(); - Self::regs_1ch() + Self::$regs() .ccmr_output(channel_index / 2) .modify(|w| w.set_ocpe(channel_index % 2, preload)); } From 6c690ab259ed15eece329a53a7147e7780f53cf3 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 2 Feb 2024 17:45:51 +0800 Subject: [PATCH 419/760] restore original public API of timer, but keep new PAC --- embassy-stm32/src/timer/complementary_pwm.rs | 41 +- embassy-stm32/src/timer/mod.rs | 525 ++++++++---------- embassy-stm32/src/timer/qei.rs | 4 +- embassy-stm32/src/timer/simple_pwm.rs | 39 +- .../stm32h7/src/bin/low_level_timer_api.rs | 4 +- 5 files changed, 274 insertions(+), 339 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index b9cd044c9..72f1ec864 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -1,7 +1,6 @@ //! PWM driver with complementary output support. use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; use embassy_hal_internal::{into_ref, PeripheralRef}; use stm32_metapac::timer::vals::Ckd; @@ -24,7 +23,7 @@ pub struct ComplementaryPwmPin<'d, T, C> { macro_rules! complementary_channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: AdvancedControlInstance> ComplementaryPwmPin<'d, T, $channel> { + impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); @@ -53,7 +52,7 @@ pub struct ComplementaryPwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { +impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] pub fn new( @@ -88,12 +87,8 @@ impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] .iter() .for_each(|&channel| { - sealed::GeneralPurpose16bitInstance::set_output_compare_mode( - this.inner.deref_mut(), - channel, - OutputCompareMode::PwmMode1, - ); - sealed::GeneralPurpose16bitInstance::set_output_compare_preload(this.inner.deref_mut(), channel, true); + this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); + this.inner.set_output_compare_preload(channel, true); }); this @@ -101,14 +96,14 @@ impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); - sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, true); + self.inner.enable_channel(channel, true); + self.inner.enable_complementary_channel(channel, true); } /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { - sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, false); - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); + self.inner.enable_complementary_channel(channel, false); + self.inner.enable_channel(channel, false); } /// Set PWM frequency. @@ -136,13 +131,13 @@ impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) + self.inner.set_compare_value(channel, duty) } /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - sealed::GeneralPurpose16bitInstance::set_output_polarity(self.inner.deref_mut(), channel, polarity); - sealed::AdvancedControlInstance::set_complementary_output_polarity(self.inner.deref_mut(), channel, polarity); + self.inner.set_output_polarity(channel, polarity); + self.inner.set_complementary_output_polarity(channel, polarity); } /// Set the dead time as a proportion of max_duty @@ -154,19 +149,19 @@ impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { } } -impl<'d, T: AdvancedControlInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { +impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; fn disable(&mut self, channel: Self::Channel) { - sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, false); - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); + self.inner.enable_complementary_channel(channel, false); + self.inner.enable_channel(channel, false); } fn enable(&mut self, channel: Self::Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); - sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, true); + self.inner.enable_channel(channel, true); + self.inner.enable_complementary_channel(channel, true); } fn get_period(&self) -> Self::Time { @@ -174,7 +169,7 @@ impl<'d, T: AdvancedControlInstance> embedded_hal_02::Pwm for ComplementaryPwm<' } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) + self.inner.get_compare_value(channel) } fn get_max_duty(&self) -> Self::Duty { @@ -183,7 +178,7 @@ impl<'d, T: AdvancedControlInstance> embedded_hal_02::Pwm for ComplementaryPwm<' fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) + self.inner.set_compare_value(channel, duty) } fn set_period

(&mut self, period: P) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 3e303a6cf..5f40be957 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,6 +1,8 @@ //! Timers, PWM, quadrature decoder. -// Timer inheritance +//! Timer inheritance + +// sealed: // // Core -------------------------> 1CH -------------------------> 1CH_CMP // | | ^ | @@ -12,7 +14,18 @@ // | +--------------------------------------|-----------+ // +----------------------------------------------------+ -#[cfg(not(any(stm32l0, stm32l1)))] +//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance +//! | +//! +--> CaptureCompare32bitInstance +//! +//! mapping: +//! +//! Basic Timer --> BasicInstance +//! 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer --> CaptureCompare16bitInstance +//! General Purpose 32-bit Timer --> CaptureCompare32bitInstance +//! 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer --> ComplementaryCaptureCompare16bitInstance + +#[cfg(not(stm32l0))] pub mod complementary_pwm; pub mod qei; pub mod simple_pwm; @@ -32,157 +45,6 @@ pub mod low_level { pub(crate) mod sealed { use super::*; - macro_rules! add_capture_compare_common_methods { - ($regs:ident) => { - /// Set input capture filter. - fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { - let raw_channel = channel.index(); - Self::$regs() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icf(raw_channel % 2, icf)); - } - - /// Clear input interrupt. - fn clear_input_interrupt(&mut self, channel: Channel) { - Self::$regs().sr().modify(|r| r.set_ccif(channel.index(), false)); - } - - /// Enable input interrupt. - fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { - Self::$regs() - .dier() - .modify(|r| r.set_ccie(channel.index(), enable)); - } - - /// Set input capture prescaler. - fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { - let raw_channel = channel.index(); - Self::$regs() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icpsc(raw_channel % 2, factor)); - } - - /// Set input TI selection. - fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { - let raw_channel = channel.index(); - Self::$regs() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); - } - - /// Set input capture mode. - fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { - Self::$regs().ccer().modify(|r| match mode { - InputCaptureMode::Rising => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), false); - } - InputCaptureMode::Falling => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), true); - } - InputCaptureMode::BothEdges => { - r.set_ccnp(channel.index(), true); - r.set_ccp(channel.index(), true); - } - }); - } - - /// Set output compare mode. - fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - let raw_channel: usize = channel.index(); - Self::$regs() - .ccmr_output(raw_channel / 2) - .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); - } - - /// Set output polarity. - fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::$regs() - .ccer() - .modify(|w| w.set_ccp(channel.index(), polarity.into())); - } - - /// Enable/disable a channel. - fn enable_channel(&mut self, channel: Channel, enable: bool) { - Self::$regs() - .ccer() - .modify(|w| w.set_cce(channel.index(), enable)); - } - - /// Get enable/disable state of a channel - fn get_channel_enable_state(&self, channel: Channel) -> bool { - Self::$regs().ccer().read().cce(channel.index()) - } - - /// Set compare value for a channel. - fn set_compare_value(&mut self, channel: Channel, value: u16) { - Self::$regs().ccr(channel.index()).modify(|w| w.set_ccr(value)); - } - - /// Get capture value for a channel. - fn get_capture_value(&mut self, channel: Channel) -> u16 { - Self::$regs().ccr(channel.index()).read().ccr() - } - - /// Get compare value for a channel. - fn get_compare_value(&self, channel: Channel) -> u16 { - Self::$regs().ccr(channel.index()).read().ccr() - } - - /// Set output compare preload. - fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { - let channel_index = channel.index(); - Self::$regs() - .ccmr_output(channel_index / 2) - .modify(|w| w.set_ocpe(channel_index % 2, preload)); - } - }; - } - - macro_rules! add_capture_compare_dma_methods { - ($regs:ident) => { - /// Get capture compare DMA selection - fn get_cc_dma_selection(&self) -> super::vals::Ccds { - Self::$regs().cr2().read().ccds() - } - - /// Set capture compare DMA selection - fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { - Self::$regs().cr2().modify(|w| w.set_ccds(ccds)) - } - - /// Get capture compare DMA enable state - fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { - Self::$regs().dier().read().ccde(channel.index()) - } - - /// Set capture compare DMA enable state - fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { - Self::$regs().dier().modify(|w| w.set_ccde(channel.index(), ccde)) - } - }; - } - - #[cfg(not(any(stm32l0, stm32l1)))] - macro_rules! add_complementary_capture_compare_methods { - ($regs:ident) => { - /// Set complementary output polarity. - fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::$regs() - .ccer() - .modify(|w| w.set_ccnp(channel.index(), polarity.into())); - } - - /// Enable/disable a complementary channel. - fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { - Self::$regs() - .ccer() - .modify(|w| w.set_ccne(channel.index(), enable)); - } - }; - } - /// Virtual Core 16-bit timer instance. pub trait CoreInstance: RccPeripheral { /// Interrupt for this timer. @@ -326,8 +188,6 @@ pub(crate) mod sealed { fn get_max_compare_value(&self) -> u16 { Self::regs_1ch().arr().read().arr() } - - add_capture_compare_common_methods!(regs_1ch); } /// Gneral-purpose 1 channel 16-bit timer instance. @@ -339,8 +199,6 @@ pub(crate) mod sealed { /// for a given set of capabilities, and having it transparently work with /// more capable timers. fn regs_2ch() -> crate::pac::timer::Tim2ch; - - add_capture_compare_common_methods!(regs_2ch); } /// Gneral-purpose 16-bit timer instance. @@ -372,11 +230,128 @@ pub(crate) mod sealed { (cr1.cms(), cr1.dir()).into() } - add_capture_compare_common_methods!(regs_gp16); - add_capture_compare_dma_methods!(regs_gp16); + /// Set input capture filter. + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { + let raw_channel = channel.index(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + + /// Clear input interrupt. + fn clear_input_interrupt(&mut self, channel: Channel) { + Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); + } + + /// Enable input interrupt. + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); + } + + /// Set input capture prescaler. + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + let raw_channel = channel.index(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + /// Set input TI selection. + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + let raw_channel = channel.index(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + + /// Set input capture mode. + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + Self::regs_gp16().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.index(), true); + r.set_ccp(channel.index(), true); + } + }); + } + + /// Set output compare mode. + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { + let raw_channel: usize = channel.index(); + Self::regs_gp16() + .ccmr_output(raw_channel / 2) + .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); + } + + /// Set output polarity. + fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + Self::regs_gp16() + .ccer() + .modify(|w| w.set_ccp(channel.index(), polarity.into())); + } + + /// Enable/disable a channel. + fn enable_channel(&mut self, channel: Channel, enable: bool) { + Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); + } + + /// Get enable/disable state of a channel + fn get_channel_enable_state(&self, channel: Channel) -> bool { + Self::regs_gp16().ccer().read().cce(channel.index()) + } + + /// Set compare value for a channel. + fn set_compare_value(&mut self, channel: Channel, value: u16) { + Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); + } + + /// Get capture value for a channel. + fn get_capture_value(&mut self, channel: Channel) -> u16 { + Self::regs_gp16().ccr(channel.index()).read().ccr() + } + + /// Get compare value for a channel. + fn get_compare_value(&self, channel: Channel) -> u16 { + Self::regs_gp16().ccr(channel.index()).read().ccr() + } + + /// Set output compare preload. + fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { + let channel_index = channel.index(); + Self::regs_gp16() + .ccmr_output(channel_index / 2) + .modify(|w| w.set_ocpe(channel_index % 2, preload)); + } + + /// Get capture compare DMA selection + fn get_cc_dma_selection(&self) -> super::vals::Ccds { + Self::regs_gp16().cr2().read().ccds() + } + + /// Set capture compare DMA selection + fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { + Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) + } + + /// Get capture compare DMA enable state + fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { + Self::regs_gp16().dier().read().ccde(channel.index()) + } + + /// Set capture compare DMA enable state + fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { + Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) + } } - #[cfg(not(any(stm32f1, stm32l0, stm32c0)))] + #[cfg(not(stm32l0))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { /// Get access to the general purpose 32bit timer registers. @@ -437,7 +412,7 @@ pub(crate) mod sealed { } } - #[cfg(not(any(stm32l0, stm32l1)))] + #[cfg(not(stm32l0))] /// Gneral-purpose 1 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance { /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. @@ -462,11 +437,9 @@ pub(crate) mod sealed { fn enable_outputs(&mut self) { Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); } - - add_complementary_capture_compare_methods!(regs_1ch_cmp); } - #[cfg(not(any(stm32l0, stm32l1)))] + #[cfg(not(stm32l0))] /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose2ChannelComplementaryInstance: BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance @@ -478,11 +451,9 @@ pub(crate) mod sealed { /// for a given set of capabilities, and having it transparently work with /// more capable timers. fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp; - - add_complementary_capture_compare_methods!(regs_2ch_cmp); } - #[cfg(not(any(stm32l0, stm32l1)))] + #[cfg(not(stm32l0))] /// Advanced control timer instance. pub trait AdvancedControlInstance: GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance @@ -490,7 +461,19 @@ pub(crate) mod sealed { /// Get access to the advanced timer registers. fn regs_advanced() -> crate::pac::timer::TimAdv; - add_complementary_capture_compare_methods!(regs_advanced); + /// Set complementary output polarity. + fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + Self::regs_advanced() + .ccer() + .modify(|w| w.set_ccnp(channel.index(), polarity.into())); + } + + /// Enable/disable a complementary channel. + fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { + Self::regs_advanced() + .ccer() + .modify(|w| w.set_ccne(channel.index(), enable)); + } } } @@ -681,96 +664,66 @@ impl From for bool { } } -/// Virtual Core 16-bit timer instance. -pub trait CoreInstance: sealed::CoreInstance + 'static {} - -/// Virtual Basic 16-bit timer without CR2 register instance. -pub trait BasicNoCr2Instance: sealed::BasicNoCr2Instance + CoreInstance + 'static {} - /// Basic 16-bit timer instance. -pub trait BasicInstance: sealed::BasicInstance + BasicNoCr2Instance + 'static {} - -/// 1 channel 16-bit instance. -pub trait GeneralPurpose1ChannelInstance: sealed::GeneralPurpose1ChannelInstance + CoreInstance + 'static {} - -/// 2 channel 16-bit instance. -pub trait GeneralPurpose2ChannelInstance: - sealed::GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelInstance + 'static -{ -} +pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} /// General-purpose 16-bit timer instance. -pub trait GeneralPurpose16bitInstance: - sealed::GeneralPurpose16bitInstance + BasicInstance + GeneralPurpose2ChannelInstance + 'static -{ -} - -#[cfg(not(any(stm32f1, stm32l0, stm32c0)))] -/// Gneral-purpose 32-bit timer instance. -pub trait GeneralPurpose32bitInstance: - sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static -{ -} - -#[cfg(not(any(stm32l0, stm32l1)))] -/// General-purpose 1 channel with one complementary 16-bit timer instance. -pub trait GeneralPurpose1ChannelComplementaryInstance: - sealed::GeneralPurpose1ChannelComplementaryInstance + GeneralPurpose1ChannelInstance + 'static -{ -} - -#[cfg(not(any(stm32l0, stm32l1)))] -/// General-purpose 2 channel with one complementary 16-bit timer instance. -pub trait GeneralPurpose2ChannelComplementaryInstance: - sealed::GeneralPurpose2ChannelComplementaryInstance - + BasicInstance - + GeneralPurpose2ChannelInstance - + GeneralPurpose1ChannelComplementaryInstance +pub trait CaptureCompare16bitInstance: + BasicInstance + + sealed::GeneralPurpose2ChannelInstance + + sealed::GeneralPurpose1ChannelInstance + + sealed::GeneralPurpose16bitInstance + 'static { } -#[cfg(not(any(stm32f37, stm32l0, stm32l1)))] -/// Advanced control timer instance. -pub trait AdvancedControlInstance: - sealed::AdvancedControlInstance + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + 'static +#[cfg(not(stm32l0))] +/// Gneral-purpose 32-bit timer instance. +pub trait CaptureCompare32bitInstance: + sealed::GeneralPurpose32bitInstance + CaptureCompare16bitInstance + 'static { } -pin_trait!(Channel1Pin, GeneralPurpose1ChannelInstance); -pin_trait!(Channel2Pin, GeneralPurpose2ChannelInstance); -pin_trait!(Channel3Pin, GeneralPurpose16bitInstance); -pin_trait!(Channel4Pin, GeneralPurpose16bitInstance); +#[cfg(not(stm32l0))] +/// Advanced control timer instance. +pub trait ComplementaryCaptureCompare16bitInstance: + CaptureCompare16bitInstance + + sealed::GeneralPurpose1ChannelComplementaryInstance + + sealed::GeneralPurpose2ChannelComplementaryInstance + + sealed::AdvancedControlInstance + + 'static +{ +} + +pin_trait!(Channel1Pin, CaptureCompare16bitInstance); +pin_trait!(Channel2Pin, CaptureCompare16bitInstance); +pin_trait!(Channel3Pin, CaptureCompare16bitInstance); +pin_trait!(Channel4Pin, CaptureCompare16bitInstance); +pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); #[cfg(not(stm32l0))] -pin_trait!(ExternalTriggerPin, GeneralPurpose16bitInstance); +pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(stm32l0)] -pin_trait!(ExternalTriggerPin, GeneralPurpose2ChannelInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(Channel1ComplementaryPin, GeneralPurpose1ChannelComplementaryInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(Channel2ComplementaryPin, GeneralPurpose2ChannelComplementaryInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(Channel3ComplementaryPin, AdvancedControlInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(Channel4ComplementaryPin, AdvancedControlInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInputPin, GeneralPurpose1ChannelComplementaryInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInput2Pin, GeneralPurpose2ChannelComplementaryInstance); - -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInputComparator1Pin, GeneralPurpose1ChannelComplementaryInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInputComparator2Pin, AdvancedControlInstance); - -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInput2Comparator1Pin, AdvancedControlInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInput2Comparator2Pin, AdvancedControlInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); #[allow(unused)] macro_rules! impl_core_timer { @@ -830,7 +783,7 @@ macro_rules! impl_2ch_timer { } #[allow(unused)] -macro_rules! impl_gp_16bit_timer { +macro_rules! impl_gp16_timer { ($inst:ident) => { impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { fn regs_gp16() -> crate::pac::timer::TimGp16 { @@ -841,7 +794,7 @@ macro_rules! impl_gp_16bit_timer { } #[allow(unused)] -macro_rules! impl_gp_32bit_timer { +macro_rules! impl_gp32_timer { ($inst:ident) => { impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { fn regs_gp32() -> crate::pac::timer::TimGp32 { @@ -890,26 +843,30 @@ foreach_interrupt! { impl_core_timer!($inst, $irq); impl_basic_no_cr2_timer!($inst); impl_basic_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); impl_1ch_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl_2ch_timer!($inst); + impl_gp16_timer!($inst); + impl BasicInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} + impl_gp16_timer!($inst); + impl BasicInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { @@ -918,13 +875,9 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); - impl_gp_16bit_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl_gp16_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { @@ -933,26 +886,26 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); - impl_gp_16bit_timer!($inst); - impl_gp_32bit_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl_gp16_timer!($inst); + impl_gp32_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} - impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare32bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { impl_core_timer!($inst, $irq); impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); impl_1ch_timer!($inst); + impl_2ch_timer!($inst); + impl_gp16_timer!($inst); impl_1ch_cmp_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} + impl_2ch_cmp_timer!($inst); + impl_adv_timer!($inst); + impl BasicInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; @@ -962,15 +915,13 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); + impl_gp16_timer!($inst); impl_1ch_cmp_timer!($inst); impl_2ch_cmp_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl_adv_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; @@ -980,26 +931,20 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); + impl_gp16_timer!($inst); impl_1ch_cmp_timer!($inst); - impl_gp_16bit_timer!($inst); impl_2ch_cmp_timer!($inst); impl_adv_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} - impl AdvancedControlInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; } // Update Event trigger DMA for every timer -dma_trait!(UpDma, BasicNoCr2Instance); +dma_trait!(UpDma, BasicInstance); -dma_trait!(Ch1Dma, GeneralPurpose1ChannelInstance); -dma_trait!(Ch2Dma, GeneralPurpose2ChannelInstance); -dma_trait!(Ch3Dma, GeneralPurpose16bitInstance); -dma_trait!(Ch4Dma, GeneralPurpose16bitInstance); +dma_trait!(Ch1Dma, CaptureCompare16bitInstance); +dma_trait!(Ch2Dma, CaptureCompare16bitInstance); +dma_trait!(Ch3Dma, CaptureCompare16bitInstance); +dma_trait!(Ch4Dma, CaptureCompare16bitInstance); diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 7e56312bb..59efb72ba 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -30,7 +30,7 @@ pub struct QeiPin<'d, T, Channel> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: GeneralPurpose16bitInstance> QeiPin<'d, T, $channel> { + impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); @@ -57,7 +57,7 @@ pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance> Qei<'d, T> { +impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { /// Create a new quadrature decoder driver. pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 088d02c97..1acba504e 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -1,7 +1,6 @@ //! Simple PWM driver. use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; use embassy_hal_internal::{into_ref, PeripheralRef}; @@ -31,7 +30,7 @@ pub struct PwmPin<'d, T, C> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: GeneralPurpose16bitInstance> PwmPin<'d, T, $channel> { + impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); @@ -60,7 +59,7 @@ pub struct SimplePwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { +impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, @@ -88,13 +87,9 @@ impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] .iter() .for_each(|&channel| { - sealed::GeneralPurpose16bitInstance::set_output_compare_mode( - this.inner.deref_mut(), - channel, - OutputCompareMode::PwmMode1, - ); + this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); - sealed::GeneralPurpose16bitInstance::set_output_compare_preload(this.inner.deref_mut(), channel, true); + this.inner.set_output_compare_preload(channel, true); }); this @@ -102,17 +97,17 @@ impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); + self.inner.enable_channel(channel, true); } /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); + self.inner.enable_channel(channel, false); } /// Check whether given channel is enabled pub fn is_enabled(&self, channel: Channel) -> bool { - sealed::GeneralPurpose16bitInstance::get_channel_enable_state(self.inner.deref(), channel) + self.inner.get_channel_enable_state(channel) } /// Set PWM frequency. @@ -140,24 +135,24 @@ impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) + self.inner.set_compare_value(channel, duty) } /// Get the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn get_duty(&self, channel: Channel) -> u16 { - sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) + self.inner.get_compare_value(channel) } /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - sealed::GeneralPurpose16bitInstance::set_output_polarity(self.inner.deref_mut(), channel, polarity); + self.inner.set_output_polarity(channel, polarity); } /// Set the output compare mode for a given channel. pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - sealed::GeneralPurpose16bitInstance::set_output_compare_mode(self.inner.deref_mut(), channel, mode); + self.inner.set_output_compare_mode(channel, mode); } /// Generate a sequence of PWM waveform @@ -232,7 +227,7 @@ impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { macro_rules! impl_waveform_chx { ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { - impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { + impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform /// /// Note: @@ -319,17 +314,17 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); -impl<'d, T: GeneralPurpose16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { +impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; fn disable(&mut self, channel: Self::Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); + self.inner.enable_channel(channel, false); } fn enable(&mut self, channel: Self::Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); + self.inner.enable_channel(channel, true); } fn get_period(&self) -> Self::Time { @@ -337,7 +332,7 @@ impl<'d, T: GeneralPurpose16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) + self.inner.get_compare_value(channel) } fn get_max_duty(&self) -> Self::Duty { @@ -346,7 +341,7 @@ impl<'d, T: GeneralPurpose16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) + self.inner.set_compare_value(channel, duty) } fn set_period

(&mut self, period: P) diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 0be3eccb7..cc508c3cf 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -56,11 +56,11 @@ async fn main(_spawner: Spawner) { Timer::after_millis(300).await; } } -pub struct SimplePwm32<'d, T: GeneralPurpose32bitInstance> { +pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose32bitInstance> SimplePwm32<'d, T> { +impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { pub fn new( tim: impl Peripheral

+ 'd, ch1: impl Peripheral

> + 'd, From 0f94006be3aa099d0a6039d51834562e51f91580 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 3 Feb 2024 17:30:00 +0800 Subject: [PATCH 420/760] doc fix --- embassy-stm32/src/timer/mod.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 5f40be957..9780c005c 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -20,10 +20,10 @@ //! //! mapping: //! -//! Basic Timer --> BasicInstance -//! 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer --> CaptureCompare16bitInstance -//! General Purpose 32-bit Timer --> CaptureCompare32bitInstance -//! 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer --> ComplementaryCaptureCompare16bitInstance +//! BasicInstance --> Basic Timer +//! CaptureCompare16bitInstance --> 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer +//! CaptureCompare32bitInstance --> General Purpose 32-bit Timer +//! ComplementaryCaptureCompare16bitInstance --> 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer #[cfg(not(stm32l0))] pub mod complementary_pwm; @@ -667,7 +667,8 @@ impl From for bool { /// Basic 16-bit timer instance. pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} -/// General-purpose 16-bit timer instance. +// It's just a General-purpose 16-bit timer instance. +/// Capture Compare timer instance. pub trait CaptureCompare16bitInstance: BasicInstance + sealed::GeneralPurpose2ChannelInstance @@ -678,14 +679,16 @@ pub trait CaptureCompare16bitInstance: } #[cfg(not(stm32l0))] -/// Gneral-purpose 32-bit timer instance. +// It's just a General-purpose 32-bit timer instance. +/// Capture Compare 32-bit timer instance. pub trait CaptureCompare32bitInstance: - sealed::GeneralPurpose32bitInstance + CaptureCompare16bitInstance + 'static + CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static { } #[cfg(not(stm32l0))] -/// Advanced control timer instance. +// It's just a Advanced Control timer instance. +/// Complementary Capture Compare 32-bit timer instance. pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + sealed::GeneralPurpose1ChannelComplementaryInstance From 8fd803a5fe0af8cc9d648ba2efba755b502f08e9 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sun, 4 Feb 2024 15:14:02 +0800 Subject: [PATCH 421/760] use cfg_if to reduce macro condition --- embassy-stm32/src/timer/mod.rs | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9780c005c..0118395a7 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -704,29 +704,23 @@ pin_trait!(Channel3Pin, CaptureCompare16bitInstance); pin_trait!(Channel4Pin, CaptureCompare16bitInstance); pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +cfg_if::cfg_if! { + if #[cfg(not(stm32l0))] { + pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); + } +} #[allow(unused)] macro_rules! impl_core_timer { From 832776d2c72a1fa9f6dcc89ea535e1023c368456 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 10 Feb 2024 02:50:35 +0100 Subject: [PATCH 422/760] stm32: update metapac. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/rcc/h.rs | 1 + embassy-stm32/src/rcc/u5.rs | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index eb67404d3..3f5f12f06 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-028efe4e6e0719b661cbdf8ffda3341e4d63d0df" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-028efe4e6e0719b661cbdf8ffda3341e4d63d0df", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 352e10816..474c44115 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -658,6 +658,7 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h5)] audioclk: None, per: None, + i2s_ckin: None, ); } diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 9cec6c96c..20cc3112a 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -477,6 +477,7 @@ pub(crate) unsafe fn init(config: Config) { pll3_p: None, pll3_q: None, pll3_r: None, + iclk: None, ); } From 802bdd1af86829482d6b847f73f02e6973bb68ea Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Sat, 10 Feb 2024 08:09:08 +0100 Subject: [PATCH 423/760] remove first person comments and assert disable state when it's necessary --- embassy-nrf/src/radio/ble.rs | 201 ++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 95 deletions(-) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 369b49c55..b0d374579 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -64,13 +64,13 @@ impl<'d, T: Instance> Radio<'d, T> { // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a // packet larger than MAXLEN, the payload will be truncated at MAXLEN // - // To simplify the implementation, I'm setting the max length to the maximum value - // and I'm using only the length field to truncate the payload + // To simplify the implementation, It is setted as the maximum value + // and the length of the packet is controlled only by the LENGTH field in the packet .maxlen() .bits(255) // Configure the length of the address field in the packet // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address - // The base address is truncated from the least significant byte if the BALEN is less than 4 + // The base address is truncated from the least significant byte if the BALEN is less than 4 // // BLE address is always 4 bytes long .balen() @@ -92,14 +92,14 @@ impl<'d, T: Instance> Radio<'d, T> { // Before whitening or de-whitening, the shift register should be // initialized based on the channel index. .whiteen() - .set_bit() // Enable whitening + .set_bit() }); // Configure CRC r.crccnf.write(|w| { // In BLE the CRC shall be calculated on the PDU of all Link Layer // packets (even if the packet is encrypted). - // So here we skip the address field + // It skips the address field w.skipaddr() .skip() // In BLE 24-bit CRC = 3 bytes @@ -125,11 +125,18 @@ impl<'d, T: Instance> Radio<'d, T> { Self { _p: radio } } + fn state(&self) -> RadioState { + match T::regs().state.read().state().variant() { + Ok(s) => s, + None => unreachable!(), + } + } + #[allow(dead_code)] fn trace_state(&self) { let r = T::regs(); - match r.state.read().state().variant().unwrap() { + match self.state() { RadioState::DISABLED => trace!("radio:state:DISABLED"), RadioState::RX_RU => trace!("radio:state:RX_RU"), RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"), @@ -142,86 +149,12 @@ impl<'d, T: Instance> Radio<'d, T> { } } - async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce() -> ()) { - //self.trace_state(); - - let r = T::regs(); - let s = T::state(); - - // If the Future is dropped before the end of the transmission - // we need to disable the interrupt and stop the transmission - // to keep the state consistent - let drop = OnDrop::new(|| { - trace!("radio drop: stopping"); - - r.intenclr.write(|w| w.end().clear()); - r.events_end.reset(); - - r.tasks_stop.write(|w| w.tasks_stop().set_bit()); - - // The docs don't explicitly mention any event to acknowledge the stop task - // So I guess it's the same as end - while r.events_end.read().events_end().bit_is_clear() {} - - trace!("radio drop: stopped"); - }); - - // trace!("radio:enable interrupt"); - // Clear some remnant side-effects (I'm unsure if this is needed) - r.events_end.reset(); - - // Enable interrupt - r.intenset.write(|w| w.end().set()); - - compiler_fence(Ordering::SeqCst); - - // Trigger the transmission - trigger(); - // self.trace_state(); - - // On poll check if interrupt happen - poll_fn(|cx| { - s.end_waker.register(cx.waker()); - if r.events_end.read().events_end().bit_is_set() { - // trace!("radio:end"); - return core::task::Poll::Ready(()); - } - Poll::Pending - }) - .await; - - compiler_fence(Ordering::SeqCst); - r.events_disabled.reset(); // ACK - - // Everthing ends fine, so we can disable the drop - drop.defuse(); - } - - /// Disable the radio. - fn disable(&mut self) { - let r = T::regs(); - - compiler_fence(Ordering::SeqCst); - // If is already disabled, do nothing - if !r.state.read().state().is_disabled() { - trace!("radio:disable"); - // Trigger the disable task - r.tasks_disable.write(|w| w.tasks_disable().set_bit()); - - // Wait until the radio is disabled - while r.events_disabled.read().events_disabled().bit_is_clear() {} - - compiler_fence(Ordering::SeqCst); - - // Acknowledge it - r.events_disabled.reset(); - } - } - /// Set the radio mode /// /// The radio must be disabled before calling this function pub fn set_mode(&mut self, mode: Mode) { + assert!(self.state() == RadioState::DISABLED); + let r = T::regs(); r.mode.write(|w| w.mode().variant(mode)); @@ -235,10 +168,12 @@ impl<'d, T: Instance> Radio<'d, T> { }); } - /// Set the header size changing the S1 field + /// Set the header size changing the S1's len field /// /// The radio must be disabled before calling this function pub fn set_header_expansion(&mut self, use_s1_field: bool) { + assert!(self.state() == RadioState::DISABLED); + let r = T::regs(); // s1 len in bits @@ -268,6 +203,8 @@ impl<'d, T: Instance> Radio<'d, T> { /// /// The radio must be disabled before calling this function pub fn set_whitening_init(&mut self, whitening_init: u8) { + assert!(self.state() == RadioState::DISABLED); + let r = T::regs(); r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) }); @@ -276,9 +213,11 @@ impl<'d, T: Instance> Radio<'d, T> { /// Set the central frequency to be used /// It should be in the range 2400..2500 /// - /// The radio must be disabled before calling this function + /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change) pub fn set_frequency(&mut self, frequency: u32) { + assert!(self.state() == RadioState::DISABLED); assert!(2400 <= frequency && frequency <= 2500); + let r = T::regs(); r.frequency @@ -292,6 +231,8 @@ impl<'d, T: Instance> Radio<'d, T> { /// /// The radio must be disabled before calling this function pub fn set_access_address(&mut self, access_address: u32) { + assert!(self.state() == RadioState::DISABLED); + let r = T::regs(); // Configure logical address @@ -309,9 +250,9 @@ impl<'d, T: Instance> Radio<'d, T> { r.txaddress.write(|w| unsafe { w.txaddress().bits(0) }); // Match on logical address - // For what I understand, this config only filter the packets - // by the address, so only packages send to the previous address - // will finish the reception + // This config only filter the packets by the address, + // so only packages send to the previous address + // will finish the reception (TODO: check the explanation) r.rxaddresses.write(|w| { w.addr0() .enabled() @@ -331,6 +272,8 @@ impl<'d, T: Instance> Radio<'d, T> { /// /// The radio must be disabled before calling this function pub fn set_crc_poly(&mut self, crc_poly: u32) { + assert!(self.state() == RadioState::DISABLED); + let r = T::regs(); r.crcpoly.write(|w| unsafe { @@ -351,6 +294,8 @@ impl<'d, T: Instance> Radio<'d, T> { /// /// The radio must be disabled before calling this function pub fn set_crc_init(&mut self, crc_init: u32) { + assert!(self.state() == RadioState::DISABLED); + let r = T::regs(); r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) }); @@ -360,6 +305,8 @@ impl<'d, T: Instance> Radio<'d, T> { /// /// The radio must be disabled before calling this function pub fn set_tx_power(&mut self, tx_power: TxPower) { + assert!(self.state() == RadioState::DISABLED); + let r = T::regs(); r.txpower.write(|w| w.txpower().variant(tx_power)); @@ -408,19 +355,83 @@ impl<'d, T: Instance> Radio<'d, T> { // Initialize the transmission // trace!("rxen"); r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()); + }) + .await; + } - // Await until ready - while r.events_ready.read().events_ready().bit_is_clear() {} + async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) { + //self.trace_state(); + + let r = T::regs(); + let s = T::state(); + + // If the Future is dropped before the end of the transmission + // we need to disable the interrupt and stop the transmission + // to keep the state consistent + let drop = OnDrop::new(|| { + trace!("radio drop: stopping"); + + r.intenclr.write(|w| w.end().clear()); + r.events_end.reset(); + + r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + + // The docs don't explicitly mention any event to acknowledge the stop task + while r.events_end.read().events_end().bit_is_clear() {} + + trace!("radio drop: stopped"); + }); + + // trace!("radio:enable interrupt"); + // Clear some remnant side-effects (TODO: check if this is necessary) + r.events_end.reset(); + + // Enable interrupt + r.intenset.write(|w| w.end().set()); + + compiler_fence(Ordering::SeqCst); + + // Trigger the transmission + trigger(); + // self.trace_state(); + + // On poll check if interrupt happen + poll_fn(|cx| { + s.end_waker.register(cx.waker()); + if r.events_end.read().events_end().bit_is_set() { + // trace!("radio:end"); + return core::task::Poll::Ready(()); + } + Poll::Pending + }) + .await; + + compiler_fence(Ordering::SeqCst); + r.events_disabled.reset(); // ACK + + // Everthing ends fine, so we can disable the drop + drop.defuse(); + } + + /// Disable the radio + fn disable(&mut self) { + let r = T::regs(); + + compiler_fence(Ordering::SeqCst); + // If it is already disabled, do nothing + if self.state() != RadioState::DISABLED { + trace!("radio:disable"); + // Trigger the disable task + r.tasks_disable.write(|w| w.tasks_disable().set_bit()); + + // Wait until the radio is disabled + while r.events_disabled.read().events_disabled().bit_is_clear() {} compiler_fence(Ordering::SeqCst); // Acknowledge it - r.events_ready.reset(); - - // trace!("radio:start"); - r.tasks_start.write(|w| w.tasks_start().set_bit()); - }) - .await; + r.events_disabled.reset(); + } } } From 37739284253699d3f087fd8e1f9282090e6aaf95 Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Sat, 10 Feb 2024 08:18:32 +0100 Subject: [PATCH 424/760] apply clippy sugestions --- embassy-nrf/src/radio/ble.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index b0d374579..c74676f58 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -127,15 +127,13 @@ impl<'d, T: Instance> Radio<'d, T> { fn state(&self) -> RadioState { match T::regs().state.read().state().variant() { - Ok(s) => s, + Some(s) => s, None => unreachable!(), } } #[allow(dead_code)] fn trace_state(&self) { - let r = T::regs(); - match self.state() { RadioState::DISABLED => trace!("radio:state:DISABLED"), RadioState::RX_RU => trace!("radio:state:RX_RU"), @@ -216,7 +214,7 @@ impl<'d, T: Instance> Radio<'d, T> { /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change) pub fn set_frequency(&mut self, frequency: u32) { assert!(self.state() == RadioState::DISABLED); - assert!(2400 <= frequency && frequency <= 2500); + assert!((2400..=2500).contains(&frequency)); let r = T::regs(); From 40282c2666f8b8bda5785b30a62ab352ff8e7498 Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Sat, 10 Feb 2024 08:49:14 +0100 Subject: [PATCH 425/760] add buffer input on transmit/receive --- embassy-nrf/src/radio/ble.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index c74676f58..7718cfe14 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -316,7 +316,7 @@ impl<'d, T: Instance> Radio<'d, T> { /// for the life time of the transmission or if the buffer will be modified. /// Also if the buffer is smaller than the packet length, the radio will /// read/write memory out of the buffer bounds. - pub fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { + fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { // Because we are serializing the buffer, we should always have the buffer in RAM slice_in_ram_or(buffer, Error::BufferNotInRAM)?; @@ -334,27 +334,33 @@ impl<'d, T: Instance> Radio<'d, T> { } /// Send packet - pub async fn transmit(&mut self) { - let r = T::regs(); + pub async fn transmit(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.set_buffer(buffer)?; + let r = T::regs(); self.trigger_and_wait_end(move || { // Initialize the transmission // trace!("txen"); r.tasks_txen.write(|w| w.tasks_txen().set_bit()); }) .await; + + Ok(()) } /// Receive packet - pub async fn receive(&mut self) { - let r = T::regs(); + pub async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + self.set_buffer(buffer)?; + let r = T::regs(); self.trigger_and_wait_end(move || { // Initialize the transmission // trace!("rxen"); r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()); }) .await; + + Ok(()) } async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) { From fdb15b205424e71107f18b43553d43691f3d8fb7 Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Sat, 10 Feb 2024 08:58:31 +0100 Subject: [PATCH 426/760] add comments about buffer unsound --- embassy-nrf/src/radio/ble.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 7718cfe14..ba9ac5f2e 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -334,6 +334,8 @@ impl<'d, T: Instance> Radio<'d, T> { } /// Send packet + /// If the length byte in the package is greater than the buffer length + /// the radio will read memory out of the buffer bounds pub async fn transmit(&mut self, buffer: &[u8]) -> Result<(), Error> { self.set_buffer(buffer)?; @@ -349,6 +351,8 @@ impl<'d, T: Instance> Radio<'d, T> { } /// Receive packet + /// If the length byte in the received package is greater than the buffer length + /// the radio will write memory out of the buffer bounds pub async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.set_buffer(buffer)?; From b4399a1bf56403a8a3204e440fb1b9295bb2a137 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 10 Feb 2024 15:58:56 +0800 Subject: [PATCH 427/760] timer-doc-fix --- embassy-stm32/src/timer/mod.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 0118395a7..9480d6972 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,6 +1,8 @@ //! Timers, PWM, quadrature decoder. +//! //! Timer inheritance +//! // sealed: // @@ -14,16 +16,20 @@ // | +--------------------------------------|-----------+ // +----------------------------------------------------+ -//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance -//! | -//! +--> CaptureCompare32bitInstance +//! ```text +//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance +//! | +//! +--> CaptureCompare32bitInstance +//! ``` //! -//! mapping: +//! Mapping: //! -//! BasicInstance --> Basic Timer -//! CaptureCompare16bitInstance --> 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer -//! CaptureCompare32bitInstance --> General Purpose 32-bit Timer -//! ComplementaryCaptureCompare16bitInstance --> 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer +//! | trait | timer | +//! | :----------------------------------------: | ------------------------------------------------------------------------------------------------- | +//! | [BasicInstance] | Basic Timer | +//! | [CaptureCompare16bitInstance] | 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer | +//! | [CaptureCompare32bitInstance] | General Purpose 32-bit Timer | +//! | [ComplementaryCaptureCompare16bitInstance] | 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer | #[cfg(not(stm32l0))] pub mod complementary_pwm; From d77b6a60d21568b8470957441b07a4974751c288 Mon Sep 17 00:00:00 2001 From: Han Cen Date: Sat, 10 Feb 2024 20:44:14 +0800 Subject: [PATCH 428/760] Fix unaligned buffer in async updater --- embassy-boot/src/firmware_updater/asynch.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 668f16f16..a7c360a35 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -276,16 +276,25 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { async fn set_magic(&mut self, magic: u8) -> Result<(), FirmwareUpdaterError> { self.state.read(0, &mut self.aligned).await?; - if self.aligned.iter().any(|&b| b != magic) { + if self.aligned[..STATE::WRITE_SIZE].iter().any(|&b| b != magic) { // Read progress validity - self.state.read(STATE::WRITE_SIZE as u32, &mut self.aligned).await?; + if STATE::READ_SIZE <= 2 * STATE::WRITE_SIZE { + self.state.read(STATE::WRITE_SIZE as u32, &mut self.aligned).await?; + } else { + self.aligned.rotate_left(STATE::WRITE_SIZE); + } - if self.aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { + if self.aligned[..STATE::WRITE_SIZE] + .iter() + .any(|&b| b != STATE_ERASE_VALUE) + { // The current progress validity marker is invalid } else { // Invalidate progress self.aligned.fill(!STATE_ERASE_VALUE); - self.state.write(STATE::WRITE_SIZE as u32, &self.aligned).await?; + self.state + .write(STATE::WRITE_SIZE as u32, &self.aligned[..STATE::WRITE_SIZE]) + .await?; } // Clear magic and progress @@ -293,7 +302,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { // Set magic self.aligned.fill(magic); - self.state.write(0, &self.aligned).await?; + self.state.write(0, &self.aligned[..STATE::WRITE_SIZE]).await?; } Ok(()) } From c873dcbb20f06e00659ab1c984ce7a753aaea7dc Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sat, 10 Feb 2024 16:55:32 -0500 Subject: [PATCH 429/760] Add explicit reset time to ws2812 write fn. --- examples/rp/src/bin/pio_ws2812.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index 9a97cb8a7..e9a3d0e41 100644 --- a/examples/rp/src/bin/pio_ws2812.rs +++ b/examples/rp/src/bin/pio_ws2812.rs @@ -107,6 +107,8 @@ impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { // DMA transfer self.sm.tx().dma_push(self.dma.reborrow(), &words).await; + + Timer::after_micros(55).await; } } From b4dc406e199a7e4aafcdd601aaef999c6b7ba590 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sat, 10 Feb 2024 17:00:10 -0500 Subject: [PATCH 430/760] Switch to ticker --- examples/rp/src/bin/pio_ws2812.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index e9a3d0e41..ac145933c 100644 --- a/examples/rp/src/bin/pio_ws2812.rs +++ b/examples/rp/src/bin/pio_ws2812.rs @@ -12,7 +12,7 @@ use embassy_rp::pio::{ Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; -use embassy_time::Timer; +use embassy_time::{Duration, Ticker, Timer}; use fixed::types::U24F8; use fixed_macro::fixed; use smart_leds::RGB8; @@ -145,6 +145,7 @@ async fn main(_spawner: Spawner) { let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); // Loop forever making RGB values and pushing them out to the WS2812. + let mut ticker = Ticker::every(Duration::from_millis(10)); loop { for j in 0..(256 * 5) { debug!("New Colors:"); @@ -154,7 +155,7 @@ async fn main(_spawner: Spawner) { } ws2812.write(&data).await; - Timer::after_millis(10).await; + ticker.next().await; } } } From eb64d71247dd7c217c7ead98635610fdd8a104e3 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 11 Feb 2024 11:32:29 -0500 Subject: [PATCH 431/760] Consolidated hash drivers. --- embassy-stm32/src/hash/mod.rs | 551 ++++++++++++++++++++++++++++++- embassy-stm32/src/hash/v1v3v4.rs | 399 ---------------------- embassy-stm32/src/hash/v2.rs | 389 ---------------------- examples/stm32f7/src/bin/hash.rs | 10 +- tests/stm32/Cargo.toml | 2 +- tests/stm32/src/bin/hash.rs | 30 +- tests/stm32/src/common.rs | 7 - 7 files changed, 565 insertions(+), 823 deletions(-) delete mode 100644 embassy-stm32/src/hash/v1v3v4.rs delete mode 100644 embassy-stm32/src/hash/v2.rs diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 64c1a0a8c..f0c2c839a 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -1,8 +1,545 @@ -//! Hash Accelerator (HASH) -#[cfg_attr(hash_v1, path = "v1v3v4.rs")] -#[cfg_attr(hash_v2, path = "v2.rs")] -#[cfg_attr(hash_v3, path = "v1v3v4.rs")] -#[cfg_attr(hash_v4, path = "v1v3v4.rs")] -mod _version; +//! Hash generator (HASH) +use core::cmp::min; +#[cfg(hash_v2)] +use core::future::poll_fn; +use core::marker::PhantomData; +#[cfg(hash_v2)] +use core::ptr; +#[cfg(hash_v2)] +use core::task::Poll; -pub use _version::*; +use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +use stm32_metapac::hash::regs::*; + +use crate::dma::NoDma; +#[cfg(hash_v2)] +use crate::dma::Transfer; +use crate::interrupt::typelevel::Interrupt; +use crate::peripherals::HASH; +use crate::rcc::sealed::RccPeripheral; +use crate::{interrupt, pac, peripherals, Peripheral}; + +#[cfg(hash_v1)] +const NUM_CONTEXT_REGS: usize = 51; +#[cfg(hash_v3)] +const NUM_CONTEXT_REGS: usize = 103; +#[cfg(any(hash_v2, hash_v4))] +const NUM_CONTEXT_REGS: usize = 54; + +const HASH_BUFFER_LEN: usize = 132; +const DIGEST_BLOCK_SIZE: usize = 128; + +static HASH_WAKER: AtomicWaker = AtomicWaker::new(); + +/// HASH interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let bits = T::regs().sr().read(); + if bits.dinis() { + T::regs().imr().modify(|reg| reg.set_dinie(false)); + HASH_WAKER.wake(); + } + if bits.dcis() { + T::regs().imr().modify(|reg| reg.set_dcie(false)); + HASH_WAKER.wake(); + } + } +} + +///Hash algorithm selection +#[derive(Clone, Copy, PartialEq)] +pub enum Algorithm { + /// SHA-1 Algorithm + SHA1 = 0, + + #[cfg(any(hash_v1, hash_v2, hash_v4))] + /// MD5 Algorithm + MD5 = 1, + + /// SHA-224 Algorithm + SHA224 = 2, + + /// SHA-256 Algorithm + SHA256 = 3, + + #[cfg(hash_v3)] + /// SHA-384 Algorithm + SHA384 = 12, + + #[cfg(hash_v3)] + /// SHA-512/224 Algorithm + SHA512_224 = 13, + + #[cfg(hash_v3)] + /// SHA-512/256 Algorithm + SHA512_256 = 14, + + #[cfg(hash_v3)] + /// SHA-256 Algorithm + SHA512 = 15, +} + +/// Input data width selection +#[repr(u8)] +#[derive(Clone, Copy)] +pub enum DataType { + ///32-bit data, no data is swapped. + Width32 = 0, + ///16-bit data, each half-word is swapped. + Width16 = 1, + ///8-bit data, all bytes are swapped. + Width8 = 2, + ///1-bit data, all bits are swapped. + Width1 = 3, +} + +/// Stores the state of the HASH peripheral for suspending/resuming +/// digest calculation. +pub struct Context { + first_word_sent: bool, + buffer: [u8; HASH_BUFFER_LEN], + buflen: usize, + algo: Algorithm, + format: DataType, + imr: u32, + str: u32, + cr: u32, + csr: [u32; NUM_CONTEXT_REGS], +} + +/// HASH driver. +pub struct Hash<'d, T: Instance, D = NoDma> { + _peripheral: PeripheralRef<'d, T>, + #[allow(dead_code)] + dma: PeripheralRef<'d, D>, +} + +impl<'d, T: Instance, D> Hash<'d, T, D> { + /// Instantiates, resets, and enables the HASH peripheral. + pub fn new( + peripheral: impl Peripheral

+ 'd, + dma: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + HASH::enable_and_reset(); + into_ref!(peripheral, dma); + let instance = Self { + _peripheral: peripheral, + dma: dma, + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + instance + } + + /// Starts computation of a new hash and returns the saved peripheral state. + pub fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { + // Define a context for this new computation. + let mut ctx = Context { + first_word_sent: false, + buffer: [0; HASH_BUFFER_LEN], + buflen: 0, + algo: algorithm, + format: format, + imr: 0, + str: 0, + cr: 0, + csr: [0; NUM_CONTEXT_REGS], + }; + + // Set the data type in the peripheral. + T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); + + // Select the algorithm. + #[cfg(hash_v1)] + if ctx.algo == Algorithm::MD5 { + T::regs().cr().modify(|w| w.set_algo(true)); + } + + #[cfg(hash_v2)] + { + // Select the algorithm. + let mut algo0 = false; + let mut algo1 = false; + if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 { + algo0 = true; + } + if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { + algo1 = true; + } + T::regs().cr().modify(|w| w.set_algo0(algo0)); + T::regs().cr().modify(|w| w.set_algo1(algo1)); + } + + #[cfg(any(hash_v3, hash_v4))] + T::regs().cr().modify(|w| w.set_algo(ctx.algo as u8)); + + T::regs().cr().modify(|w| w.set_init(true)); + + // Store and return the state of the peripheral. + self.store_context(&mut ctx); + ctx + } + + /// Restores the peripheral state using the given context, + /// then updates the state with the provided data. + /// Peripheral state is saved upon return. + pub fn update_blocking(&mut self, ctx: &mut Context, input: &[u8]) { + let mut data_waiting = input.len() + ctx.buflen; + if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) { + // There isn't enough data to digest a block, so append it to the buffer. + ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); + ctx.buflen += input.len(); + return; + } + + // Restore the peripheral state. + self.load_context(&ctx); + + let mut ilen_remaining = input.len(); + let mut input_start = 0; + + // Handle first block. + if !ctx.first_word_sent { + let empty_len = ctx.buffer.len() - ctx.buflen; + let copy_len = min(empty_len, ilen_remaining); + // Fill the buffer. + if copy_len > 0 { + ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[0..copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; + } + self.accumulate_blocking(ctx.buffer.as_slice()); + data_waiting -= ctx.buflen; + ctx.buflen = 0; + ctx.first_word_sent = true; + } + + if data_waiting < DIGEST_BLOCK_SIZE { + // There isn't enough data remaining to process another block, so store it. + ctx.buffer[0..ilen_remaining].copy_from_slice(&input[input_start..input_start + ilen_remaining]); + ctx.buflen += ilen_remaining; + } else { + // First ingest the data in the buffer. + let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; + if empty_len > 0 { + let copy_len = min(empty_len, ilen_remaining); + ctx.buffer[ctx.buflen..ctx.buflen + copy_len] + .copy_from_slice(&input[input_start..input_start + copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; + } + self.accumulate_blocking(&ctx.buffer[0..DIGEST_BLOCK_SIZE]); + ctx.buflen = 0; + + // Move any extra data to the now-empty buffer. + let leftovers = ilen_remaining % 64; + if leftovers > 0 { + ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); + ctx.buflen += leftovers; + ilen_remaining -= leftovers; + } + + // Hash the remaining data. + self.accumulate_blocking(&input[input_start..input_start + ilen_remaining]); + } + + // Save the peripheral context. + self.store_context(ctx); + } + + /// Restores the peripheral state using the given context, + /// then updates the state with the provided data. + /// Peripheral state is saved upon return. + #[cfg(hash_v2)] + pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) + where + D: crate::hash::Dma, + { + let data_waiting = input.len() + ctx.buflen; + if data_waiting < DIGEST_BLOCK_SIZE { + // There isn't enough data to digest a block, so append it to the buffer. + ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); + ctx.buflen += input.len(); + return; + } + + // Restore the peripheral state. + self.load_context(&ctx); + + // Enable multiple DMA transfers. + T::regs().cr().modify(|w| w.set_mdmat(true)); + + let mut ilen_remaining = input.len(); + let mut input_start = 0; + + // First ingest the data in the buffer. + let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; + if empty_len > 0 { + let copy_len = min(empty_len, ilen_remaining); + ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[input_start..input_start + copy_len]); + ctx.buflen += copy_len; + ilen_remaining -= copy_len; + input_start += copy_len; + } + self.accumulate(&ctx.buffer[..DIGEST_BLOCK_SIZE]).await; + ctx.buflen = 0; + + // Move any extra data to the now-empty buffer. + let leftovers = ilen_remaining % DIGEST_BLOCK_SIZE; + if leftovers > 0 { + assert!(ilen_remaining >= leftovers); + ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); + ctx.buflen += leftovers; + ilen_remaining -= leftovers; + } else { + ctx.buffer + .copy_from_slice(&input[input.len() - DIGEST_BLOCK_SIZE..input.len()]); + ctx.buflen += DIGEST_BLOCK_SIZE; + ilen_remaining -= DIGEST_BLOCK_SIZE; + } + + // Hash the remaining data. + self.accumulate(&input[input_start..input_start + ilen_remaining]).await; + + // Save the peripheral context. + self.store_context(ctx); + } + + /// Computes a digest for the given context. + /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. + /// The largest returned digest size is 128 bytes for SHA-512. + /// Panics if the supplied digest buffer is too short. + pub fn finish_blocking(&mut self, mut ctx: Context, digest: &mut [u8]) -> usize { + // Restore the peripheral state. + self.load_context(&ctx); + + // Hash the leftover bytes, if any. + self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]); + ctx.buflen = 0; + + //Start the digest calculation. + T::regs().str().write(|w| w.set_dcal(true)); + + // Block waiting for digest. + while !T::regs().sr().read().dcis() {} + + // Return the digest. + let digest_words = match ctx.algo { + Algorithm::SHA1 => 5, + #[cfg(any(hash_v1, hash_v2, hash_v4))] + Algorithm::MD5 => 4, + Algorithm::SHA224 => 7, + Algorithm::SHA256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA384 => 12, + #[cfg(hash_v3)] + Algorithm::SHA512_224 => 7, + #[cfg(hash_v3)] + Algorithm::SHA512_256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA512 => 16, + }; + + let digest_len_bytes = digest_words * 4; + // Panics if the supplied digest buffer is too short. + if digest.len() < digest_len_bytes { + panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); + } + + let mut i = 0; + while i < digest_words { + let word = T::regs().hr(i).read(); + digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); + i += 1; + } + digest_len_bytes + } + + /// Computes a digest for the given context. + /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. + /// The largest returned digest size is 128 bytes for SHA-512. + /// Panics if the supplied digest buffer is too short. + #[cfg(hash_v2)] + pub async fn finish(&mut self, mut ctx: Context, digest: &mut [u8]) -> usize + where + D: crate::hash::Dma, + { + // Restore the peripheral state. + self.load_context(&ctx); + + // Must be cleared prior to the last DMA transfer. + T::regs().cr().modify(|w| w.set_mdmat(false)); + + // Hash the leftover bytes, if any. + self.accumulate(&ctx.buffer[0..ctx.buflen]).await; + ctx.buflen = 0; + + // Wait for completion. + poll_fn(|cx| { + // Check if already done. + let bits = T::regs().sr().read(); + if bits.dcis() { + return Poll::Ready(()); + } + // Register waker, then enable interrupts. + HASH_WAKER.register(cx.waker()); + T::regs().imr().modify(|reg| reg.set_dcie(true)); + // Check for completion. + let bits = T::regs().sr().read(); + if bits.dcis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + // Return the digest. + let digest_words = match ctx.algo { + Algorithm::SHA1 => 5, + #[cfg(any(hash_v1, hash_v2, hash_v4))] + Algorithm::MD5 => 4, + Algorithm::SHA224 => 7, + Algorithm::SHA256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA384 => 12, + #[cfg(hash_v3)] + Algorithm::SHA512_224 => 7, + #[cfg(hash_v3)] + Algorithm::SHA512_256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA512 => 16, + }; + + let digest_len_bytes = digest_words * 4; + // Panics if the supplied digest buffer is too short. + if digest.len() < digest_len_bytes { + panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); + } + + let mut i = 0; + while i < digest_words { + let word = T::regs().hr(i).read(); + digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); + i += 1; + } + digest_len_bytes + } + + /// Push data into the hash core. + fn accumulate_blocking(&mut self, input: &[u8]) { + // Set the number of valid bits. + let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; + T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); + + let mut i = 0; + while i < input.len() { + let mut word: [u8; 4] = [0; 4]; + let copy_idx = min(i + 4, input.len()); + word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); + T::regs().din().write_value(u32::from_ne_bytes(word)); + i += 4; + } + } + + /// Push data into the hash core. + #[cfg(hash_v2)] + async fn accumulate(&mut self, input: &[u8]) + where + D: crate::hash::Dma, + { + // Ignore an input length of 0. + if input.len() == 0 { + return; + } + + // Set the number of valid bits. + let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; + T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); + + // Configure DMA to transfer input to hash core. + let dma_request = self.dma.request(); + let dst_ptr = T::regs().din().as_ptr(); + let mut num_words = input.len() / 4; + if input.len() % 4 > 0 { + num_words += 1; + } + let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); + let dma_transfer = + unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) }; + T::regs().cr().modify(|w| w.set_dmae(true)); + + // Wait for the transfer to complete. + dma_transfer.await; + } + + /// Save the peripheral state to a context. + fn store_context(&mut self, ctx: &mut Context) { + // Block waiting for data in ready. + while !T::regs().sr().read().dinis() {} + + // Store peripheral context. + ctx.imr = T::regs().imr().read().0; + ctx.str = T::regs().str().read().0; + ctx.cr = T::regs().cr().read().0; + let mut i = 0; + while i < NUM_CONTEXT_REGS { + ctx.csr[i] = T::regs().csr(i).read(); + i += 1; + } + } + + /// Restore the peripheral state from a context. + fn load_context(&mut self, ctx: &Context) { + // Restore the peripheral state from the context. + T::regs().imr().write_value(Imr { 0: ctx.imr }); + T::regs().str().write_value(Str { 0: ctx.str }); + T::regs().cr().write_value(Cr { 0: ctx.cr }); + T::regs().cr().modify(|w| w.set_init(true)); + let mut i = 0; + while i < NUM_CONTEXT_REGS { + T::regs().csr(i).write_value(ctx.csr[i]); + i += 1; + } + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Instance { + fn regs() -> pac::hash::Hash; + } +} + +/// HASH instance trait. +pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { + /// Interrupt for this HASH instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +foreach_interrupt!( + ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => { + impl Instance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + + impl sealed::Instance for peripherals::$inst { + fn regs() -> crate::pac::hash::Hash { + crate::pac::$inst + } + } + }; +); + +dma_trait!(Dma, Instance); diff --git a/embassy-stm32/src/hash/v1v3v4.rs b/embassy-stm32/src/hash/v1v3v4.rs deleted file mode 100644 index 771144b11..000000000 --- a/embassy-stm32/src/hash/v1v3v4.rs +++ /dev/null @@ -1,399 +0,0 @@ -//! Hash generator (HASH) -use core::cmp::min; -use core::future::poll_fn; -use core::marker::PhantomData; -use core::task::Poll; - -use embassy_hal_internal::{into_ref, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; -use stm32_metapac::hash::regs::*; - -use crate::interrupt::typelevel::Interrupt; -use crate::peripherals::HASH; -use crate::rcc::sealed::RccPeripheral; -use crate::{interrupt, pac, peripherals, Peripheral}; - -#[cfg(hash_v1)] -const NUM_CONTEXT_REGS: usize = 51; -#[cfg(hash_v3)] -const NUM_CONTEXT_REGS: usize = 103; -#[cfg(hash_v4)] -const NUM_CONTEXT_REGS: usize = 54; - -const HASH_BUFFER_LEN: usize = 132; -const DIGEST_BLOCK_SIZE: usize = 128; -const MAX_DIGEST_SIZE: usize = 128; - -static HASH_WAKER: AtomicWaker = AtomicWaker::new(); - -/// HASH interrupt handler. -pub struct InterruptHandler { - _phantom: PhantomData, -} - -impl interrupt::typelevel::Handler for InterruptHandler { - unsafe fn on_interrupt() { - let bits = T::regs().sr().read(); - if bits.dinis() { - T::regs().imr().modify(|reg| reg.set_dinie(false)); - HASH_WAKER.wake(); - } - if bits.dcis() { - T::regs().imr().modify(|reg| reg.set_dcie(false)); - HASH_WAKER.wake(); - } - } -} - -///Hash algorithm selection -#[derive(Clone, Copy, PartialEq)] -pub enum Algorithm { - /// SHA-1 Algorithm - SHA1 = 0, - - #[cfg(any(hash_v1, hash_v4))] - /// MD5 Algorithm - MD5 = 1, - - /// SHA-224 Algorithm - SHA224 = 2, - - /// SHA-256 Algorithm - SHA256 = 3, - - #[cfg(hash_v3)] - /// SHA-384 Algorithm - SHA384 = 12, - - #[cfg(hash_v3)] - /// SHA-512/224 Algorithm - SHA512_224 = 13, - - #[cfg(hash_v3)] - /// SHA-512/256 Algorithm - SHA512_256 = 14, - - #[cfg(hash_v3)] - /// SHA-256 Algorithm - SHA512 = 15, -} - -/// Input data width selection -#[repr(u8)] -#[derive(Clone, Copy)] -pub enum DataType { - ///32-bit data, no data is swapped. - Width32 = 0, - ///16-bit data, each half-word is swapped. - Width16 = 1, - ///8-bit data, all bytes are swapped. - Width8 = 2, - ///1-bit data, all bits are swapped. - Width1 = 3, -} - -/// Stores the state of the HASH peripheral for suspending/resuming -/// digest calculation. -pub struct Context { - first_word_sent: bool, - buffer: [u8; HASH_BUFFER_LEN], - buflen: usize, - algo: Algorithm, - format: DataType, - imr: u32, - str: u32, - cr: u32, - csr: [u32; NUM_CONTEXT_REGS], -} - -/// HASH driver. -pub struct Hash<'d, T: Instance> { - _peripheral: PeripheralRef<'d, T>, -} - -impl<'d, T: Instance> Hash<'d, T> { - /// Instantiates, resets, and enables the HASH peripheral. - pub fn new( - peripheral: impl Peripheral

+ 'd, - _irq: impl interrupt::typelevel::Binding> + 'd, - ) -> Self { - HASH::enable_and_reset(); - into_ref!(peripheral); - let instance = Self { - _peripheral: peripheral, - }; - - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - instance - } - - /// Starts computation of a new hash and returns the saved peripheral state. - pub async fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { - // Define a context for this new computation. - let mut ctx = Context { - first_word_sent: false, - buffer: [0; HASH_BUFFER_LEN], - buflen: 0, - algo: algorithm, - format: format, - imr: 0, - str: 0, - cr: 0, - csr: [0; NUM_CONTEXT_REGS], - }; - - // Set the data type in the peripheral. - T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); - - // Select the algorithm. - #[cfg(hash_v1)] - if ctx.algo == Algorithm::MD5 { - T::regs().cr().modify(|w| w.set_algo(true)); - } - - #[cfg(hash_v2)] - { - // Select the algorithm. - let mut algo0 = false; - let mut algo1 = false; - if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 { - algo0 = true; - } - if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { - algo1 = true; - } - T::regs().cr().modify(|w| w.set_algo0(algo0)); - T::regs().cr().modify(|w| w.set_algo1(algo1)); - } - - #[cfg(any(hash_v3, hash_v4))] - T::regs().cr().modify(|w| w.set_algo(ctx.algo as u8)); - - T::regs().cr().modify(|w| w.set_init(true)); - - // Store and return the state of the peripheral. - self.store_context(&mut ctx).await; - ctx - } - - /// Restores the peripheral state using the given context, - /// then updates the state with the provided data. - /// Peripheral state is saved upon return. - pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) { - let mut data_waiting = input.len() + ctx.buflen; - if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) { - // There isn't enough data to digest a block, so append it to the buffer. - ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); - ctx.buflen += input.len(); - return; - } - - // Restore the peripheral state. - self.load_context(&ctx); - - let mut ilen_remaining = input.len(); - let mut input_start = 0; - - // Handle first block. - if !ctx.first_word_sent { - let empty_len = ctx.buffer.len() - ctx.buflen; - let copy_len = min(empty_len, ilen_remaining); - // Fill the buffer. - if copy_len > 0 { - ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[0..copy_len]); - ctx.buflen += copy_len; - ilen_remaining -= copy_len; - input_start += copy_len; - } - self.accumulate(ctx.buffer.as_slice()); - data_waiting -= ctx.buflen; - ctx.buflen = 0; - ctx.first_word_sent = true; - } - - if data_waiting < DIGEST_BLOCK_SIZE { - // There isn't enough data remaining to process another block, so store it. - ctx.buffer[0..ilen_remaining].copy_from_slice(&input[input_start..input_start + ilen_remaining]); - ctx.buflen += ilen_remaining; - } else { - // First ingest the data in the buffer. - let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; - if empty_len > 0 { - let copy_len = min(empty_len, ilen_remaining); - ctx.buffer[ctx.buflen..ctx.buflen + copy_len] - .copy_from_slice(&input[input_start..input_start + copy_len]); - ctx.buflen += copy_len; - ilen_remaining -= copy_len; - input_start += copy_len; - } - self.accumulate(&ctx.buffer[0..DIGEST_BLOCK_SIZE]); - ctx.buflen = 0; - - // Move any extra data to the now-empty buffer. - let leftovers = ilen_remaining % 64; - if leftovers > 0 { - ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); - ctx.buflen += leftovers; - ilen_remaining -= leftovers; - } - - // Hash the remaining data. - self.accumulate(&input[input_start..input_start + ilen_remaining]); - } - - // Save the peripheral context. - self.store_context(ctx).await; - } - - /// Computes a digest for the given context. A slice of the provided digest buffer is returned. - /// The length of the returned slice is dependent on the digest length of the selected algorithm. - pub async fn finish<'a>(&mut self, mut ctx: Context, digest: &'a mut [u8; MAX_DIGEST_SIZE]) -> &'a [u8] { - // Restore the peripheral state. - self.load_context(&ctx); - - // Hash the leftover bytes, if any. - self.accumulate(&ctx.buffer[0..ctx.buflen]); - ctx.buflen = 0; - - //Start the digest calculation. - T::regs().str().write(|w| w.set_dcal(true)); - - // Wait for completion. - poll_fn(|cx| { - // Check if already done. - let bits = T::regs().sr().read(); - if bits.dcis() { - return Poll::Ready(()); - } - // Register waker, then enable interrupts. - HASH_WAKER.register(cx.waker()); - T::regs().imr().modify(|reg| reg.set_dcie(true)); - // Check for completion. - let bits = T::regs().sr().read(); - if bits.dcis() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - - // Return the digest. - let digest_words = match ctx.algo { - Algorithm::SHA1 => 5, - #[cfg(any(hash_v1, hash_v4))] - Algorithm::MD5 => 4, - Algorithm::SHA224 => 7, - Algorithm::SHA256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA384 => 12, - #[cfg(hash_v3)] - Algorithm::SHA512_224 => 7, - #[cfg(hash_v3)] - Algorithm::SHA512_256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA512 => 16, - }; - let mut i = 0; - while i < digest_words { - let word = T::regs().hr(i).read(); - digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); - i += 1; - } - &digest[0..digest_words * 4] - } - - /// Push data into the hash core. - fn accumulate(&mut self, input: &[u8]) { - // Set the number of valid bits. - let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; - T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); - - let mut i = 0; - while i < input.len() { - let mut word: [u8; 4] = [0; 4]; - let copy_idx = min(i + 4, input.len()); - word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); - T::regs().din().write_value(u32::from_ne_bytes(word)); - i += 4; - } - } - - /// Save the peripheral state to a context. - async fn store_context(&mut self, ctx: &mut Context) { - // Wait for interrupt. - poll_fn(|cx| { - // Check if already done. - let bits = T::regs().sr().read(); - if bits.dinis() { - return Poll::Ready(()); - } - // Register waker, then enable interrupts. - HASH_WAKER.register(cx.waker()); - T::regs().imr().modify(|reg| reg.set_dinie(true)); - // Check for completion. - let bits = T::regs().sr().read(); - if bits.dinis() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - - ctx.imr = T::regs().imr().read().0; - ctx.str = T::regs().str().read().0; - ctx.cr = T::regs().cr().read().0; - let mut i = 0; - while i < NUM_CONTEXT_REGS { - ctx.csr[i] = T::regs().csr(i).read(); - i += 1; - } - } - - /// Restore the peripheral state from a context. - fn load_context(&mut self, ctx: &Context) { - // Restore the peripheral state from the context. - T::regs().imr().write_value(Imr { 0: ctx.imr }); - T::regs().str().write_value(Str { 0: ctx.str }); - T::regs().cr().write_value(Cr { 0: ctx.cr }); - T::regs().cr().modify(|w| w.set_init(true)); - let mut i = 0; - while i < NUM_CONTEXT_REGS { - T::regs().csr(i).write_value(ctx.csr[i]); - i += 1; - } - } -} - -pub(crate) mod sealed { - use super::*; - - pub trait Instance { - fn regs() -> pac::hash::Hash; - } -} - -/// HASH instance trait. -pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { - /// Interrupt for this HASH instance. - type Interrupt: interrupt::typelevel::Interrupt; -} - -foreach_interrupt!( - ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => { - impl Instance for peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$irq; - } - - impl sealed::Instance for peripherals::$inst { - fn regs() -> crate::pac::hash::Hash { - crate::pac::$inst - } - } - }; -); - -dma_trait!(Dma, Instance); diff --git a/embassy-stm32/src/hash/v2.rs b/embassy-stm32/src/hash/v2.rs deleted file mode 100644 index b8104c825..000000000 --- a/embassy-stm32/src/hash/v2.rs +++ /dev/null @@ -1,389 +0,0 @@ -//! Hash generator (HASH) -use core::cmp::min; -use core::future::poll_fn; -use core::marker::PhantomData; -use core::ptr; -use core::task::Poll; - -use embassy_hal_internal::{into_ref, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; -use stm32_metapac::hash::regs::*; - -use crate::dma::Transfer; -use crate::interrupt::typelevel::Interrupt; -use crate::peripherals::HASH; -use crate::rcc::sealed::RccPeripheral; -use crate::{interrupt, pac, peripherals, Peripheral}; - -#[cfg(hash_v2)] -const NUM_CONTEXT_REGS: usize = 54; -#[cfg(hash_v3)] -const NUM_CONTEXT_REGS: usize = 103; -const DIGEST_BLOCK_SIZE: usize = 64; -const MAX_DIGEST_SIZE: usize = 64; - -static HASH_WAKER: AtomicWaker = AtomicWaker::new(); - -/// HASH interrupt handler. -pub struct InterruptHandler { - _phantom: PhantomData, -} - -impl interrupt::typelevel::Handler for InterruptHandler { - unsafe fn on_interrupt() { - let bits = T::regs().sr().read(); - if bits.dinis() { - T::regs().imr().modify(|reg| reg.set_dinie(false)); - HASH_WAKER.wake(); - } - if bits.dcis() { - T::regs().imr().modify(|reg| reg.set_dcie(false)); - HASH_WAKER.wake(); - } - } -} - -///Hash algorithm selection -#[derive(Clone, Copy, PartialEq)] -pub enum Algorithm { - /// SHA-1 Algorithm - SHA1 = 0, - - #[cfg(hash_v2)] - /// MD5 Algorithm - MD5 = 1, - - /// SHA-224 Algorithm - SHA224 = 2, - - /// SHA-256 Algorithm - SHA256 = 3, - - #[cfg(hash_v3)] - /// SHA-384 Algorithm - SHA384 = 12, - - #[cfg(hash_v3)] - /// SHA-512/224 Algorithm - SHA512_224 = 13, - - #[cfg(hash_v3)] - /// SHA-512/256 Algorithm - SHA512_256 = 14, - - #[cfg(hash_v3)] - /// SHA-256 Algorithm - SHA512 = 15, -} - -/// Input data width selection -#[repr(u8)] -#[derive(Clone, Copy)] -pub enum DataType { - ///32-bit data, no data is swapped. - Width32 = 0, - ///16-bit data, each half-word is swapped. - Width16 = 1, - ///8-bit data, all bytes are swapped. - Width8 = 2, - ///1-bit data, all bits are swapped. - Width1 = 3, -} - -/// Stores the state of the HASH peripheral for suspending/resuming -/// digest calculation. -pub struct Context { - buffer: [u8; DIGEST_BLOCK_SIZE], - buflen: usize, - algo: Algorithm, - format: DataType, - imr: u32, - str: u32, - cr: u32, - csr: [u32; NUM_CONTEXT_REGS], -} - -/// HASH driver. -pub struct Hash<'d, T: Instance, D: Dma> { - _peripheral: PeripheralRef<'d, T>, - dma: PeripheralRef<'d, D>, -} - -impl<'d, T: Instance, D: Dma> Hash<'d, T, D> { - /// Instantiates, resets, and enables the HASH peripheral. - pub fn new( - peripheral: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, - _irq: impl interrupt::typelevel::Binding> + 'd, - ) -> Self { - HASH::enable_and_reset(); - into_ref!(peripheral, dma); - let instance = Self { - _peripheral: peripheral, - dma: dma, - }; - - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - instance - } - - /// Starts computation of a new hash and returns the saved peripheral state. - pub async fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { - // Define a context for this new computation. - let mut ctx = Context { - buffer: [0; DIGEST_BLOCK_SIZE], - buflen: 0, - algo: algorithm, - format: format, - imr: 0, - str: 0, - cr: 0, - csr: [0; NUM_CONTEXT_REGS], - }; - - // Set the data type in the peripheral. - T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); - - #[cfg(hash_v2)] - { - // Select the algorithm. - let mut algo0 = false; - let mut algo1 = false; - if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 { - algo0 = true; - } - if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { - algo1 = true; - } - T::regs().cr().modify(|w| w.set_algo0(algo0)); - T::regs().cr().modify(|w| w.set_algo1(algo1)); - } - - #[cfg(hash_v3)] - T::regs().cr().modify(|w| w.set_algo(ctx.algo as u8)); - - // Enable multiple DMA transfers. - T::regs().cr().modify(|w| w.set_mdmat(true)); - - // Set init to load the context registers. Necessary before storing context. - T::regs().cr().modify(|w| w.set_init(true)); - - // Store and return the state of the peripheral. - self.store_context(&mut ctx).await; - ctx - } - - /// Restores the peripheral state using the given context, - /// then updates the state with the provided data. - /// Peripheral state is saved upon return. - pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) { - let data_waiting = input.len() + ctx.buflen; - if data_waiting < DIGEST_BLOCK_SIZE { - // There isn't enough data to digest a block, so append it to the buffer. - ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); - ctx.buflen += input.len(); - return; - } - - // Restore the peripheral state. - self.load_context(&ctx); - - let mut ilen_remaining = input.len(); - let mut input_start = 0; - - // First ingest the data in the buffer. - let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; - if empty_len > 0 { - let copy_len = min(empty_len, ilen_remaining); - ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[input_start..input_start + copy_len]); - ctx.buflen += copy_len; - ilen_remaining -= copy_len; - input_start += copy_len; - } - self.accumulate(&ctx.buffer).await; - ctx.buflen = 0; - - // Move any extra data to the now-empty buffer. - let leftovers = ilen_remaining % DIGEST_BLOCK_SIZE; - if leftovers > 0 { - assert!(ilen_remaining >= leftovers); - ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); - ctx.buflen += leftovers; - ilen_remaining -= leftovers; - } else { - ctx.buffer - .copy_from_slice(&input[input.len() - DIGEST_BLOCK_SIZE..input.len()]); - ctx.buflen += DIGEST_BLOCK_SIZE; - ilen_remaining -= DIGEST_BLOCK_SIZE; - } - - // Hash the remaining data. - self.accumulate(&input[input_start..input_start + ilen_remaining]).await; - - // Save the peripheral context. - self.store_context(ctx).await; - } - - /// Computes a digest for the given context. A slice of the provided digest buffer is returned. - /// The length of the returned slice is dependent on the digest length of the selected algorithm. - pub async fn finish<'a>(&mut self, mut ctx: Context, digest: &'a mut [u8; MAX_DIGEST_SIZE]) -> &'a [u8] { - // Restore the peripheral state. - self.load_context(&ctx); - - // Must be cleared prior to the last DMA transfer. - T::regs().cr().modify(|w| w.set_mdmat(false)); - - // Hash the leftover bytes, if any. - self.accumulate(&ctx.buffer[0..ctx.buflen]).await; - ctx.buflen = 0; - - // Wait for completion. - poll_fn(|cx| { - // Check if already done. - let bits = T::regs().sr().read(); - if bits.dcis() { - return Poll::Ready(()); - } - // Register waker, then enable interrupts. - HASH_WAKER.register(cx.waker()); - T::regs().imr().modify(|reg| reg.set_dcie(true)); - // Check for completion. - let bits = T::regs().sr().read(); - if bits.dcis() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - - // Return the digest. - let digest_words = match ctx.algo { - Algorithm::SHA1 => 5, - #[cfg(hash_v2)] - Algorithm::MD5 => 4, - Algorithm::SHA224 => 7, - Algorithm::SHA256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA384 => 12, - #[cfg(hash_v3)] - Algorithm::SHA512_224 => 7, - #[cfg(hash_v3)] - Algorithm::SHA512_256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA512 => 16, - }; - let mut i = 0; - while i < digest_words { - let word = T::regs().hr(i).read(); - digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); - i += 1; - } - &digest[0..digest_words * 4] - } - - /// Push data into the hash core. - async fn accumulate(&mut self, input: &[u8]) { - // Ignore an input length of 0. - if input.len() == 0 { - return; - } - - // Set the number of valid bits. - let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; - T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); - - // Configure DMA to transfer input to hash core. - let dma_request = self.dma.request(); - let dst_ptr = T::regs().din().as_ptr(); - let mut num_words = input.len() / 4; - if input.len() % 4 > 0 { - num_words += 1; - } - let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); - let dma_transfer = - unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) }; - T::regs().cr().modify(|w| w.set_dmae(true)); - - // Wait for the transfer to complete. - dma_transfer.await; - } - - /// Save the peripheral state to a context. - async fn store_context(&mut self, ctx: &mut Context) { - // Wait for interrupt. - poll_fn(|cx| { - // Check if already done. - let bits = T::regs().sr().read(); - if bits.dinis() { - return Poll::Ready(()); - } - // Register waker, then enable interrupts. - HASH_WAKER.register(cx.waker()); - T::regs().imr().modify(|reg| reg.set_dinie(true)); - // Check for completion. - let bits = T::regs().sr().read(); - if bits.dinis() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - - ctx.imr = T::regs().imr().read().0; - ctx.str = T::regs().str().read().0; - ctx.cr = T::regs().cr().read().0; - let mut i = 0; - while i < NUM_CONTEXT_REGS { - ctx.csr[i] = T::regs().csr(i).read(); - i += 1; - } - } - - /// Restore the peripheral state from a context. - fn load_context(&mut self, ctx: &Context) { - // Restore the peripheral state from the context. - T::regs().imr().write_value(Imr { 0: ctx.imr }); - T::regs().str().write_value(Str { 0: ctx.str }); - T::regs().cr().write_value(Cr { 0: ctx.cr }); - T::regs().cr().modify(|w| w.set_init(true)); - let mut i = 0; - while i < NUM_CONTEXT_REGS { - T::regs().csr(i).write_value(ctx.csr[i]); - i += 1; - } - } -} - -pub(crate) mod sealed { - use super::*; - - pub trait Instance { - fn regs() -> pac::hash::Hash; - } -} - -/// HASH instance trait. -pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { - /// Interrupt for this HASH instance. - type Interrupt: interrupt::typelevel::Interrupt; -} - -foreach_interrupt!( - ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => { - impl Instance for peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$irq; - } - - impl sealed::Instance for peripherals::$inst { - fn regs() -> crate::pac::hash::Hash { - crate::pac::$inst - } - } - }; -); - -dma_trait!(Dma, Instance); diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index 7d96bd49c..31f8d32a7 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -3,7 +3,7 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::{bind_interrupts, Config, hash, hash::*, peripherals}; +use embassy_stm32::{bind_interrupts, hash, hash::*, peripherals, Config}; use embassy_time::Instant; use sha2::{Digest, Sha256}; use {defmt_rtt as _, panic_probe as _}; @@ -25,11 +25,11 @@ async fn main(_spawner: Spawner) -> ! { let hw_start_time = Instant::now(); // Compute a digest in hardware. - let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8).await; + let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); hw_hasher.update(&mut context, test_1).await; hw_hasher.update(&mut context, test_2).await; - let mut buffer: [u8; 64] = [0; 64]; - let hw_digest = hw_hasher.finish(context, &mut buffer).await; + let mut hw_digest: [u8; 32] = [0; 32]; + hw_hasher.finish(context, &mut hw_digest).await; let hw_end_time = Instant::now(); let hw_execution_time = hw_end_time - hw_start_time; @@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) -> ! { info!("Software Digest: {:?}", sw_digest[..]); info!("Hardware Execution Time: {:?}", hw_execution_time); info!("Software Execution Time: {:?}", sw_execution_time); - assert_eq!(*hw_digest, sw_digest[..]); + assert_eq!(hw_digest, sw_digest[..]); loop {} } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index d02f1a253..fc4420687 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -26,7 +26,7 @@ stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash" stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] -stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] +stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index 2867115dc..cfcf3d976 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -6,6 +6,7 @@ mod common; use common::*; use embassy_executor::Spawner; +use embassy_stm32::dma::NoDma; use embassy_stm32::hash::*; use embassy_stm32::{bind_interrupts, hash, peripherals}; use sha2::{Digest, Sha224, Sha256}; @@ -30,27 +31,26 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); - let dma = peri!(p, HASH_DMA); - let mut hw_hasher = Hash::new(p.HASH, dma); + let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs); let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr"; let test_3: &[u8] = b"a.ewtkluGWEBR.KAJRBTA,RMNRBG,FDMGB.kger.tkasjrbt.akrjtba.krjtba.ktmyna,nmbvtyliasd;gdrtba,sfvs.kgjzshd.gkbsr.tksejb.SDkfBSE.gkfgb>ESkfbSE>gkJSBESE>kbSE>fk"; // Start an SHA-256 digest. - let mut sha256context = hw_hasher.start(Algorithm::SHA256, DataType::Width8).await; - hw_hasher.update(&mut sha256context, test_1).await; + let mut sha256context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); + hw_hasher.update_blocking(&mut sha256context, test_1); // Interrupt the SHA-256 digest to compute an SHA-224 digest. - let mut sha224context = hw_hasher.start(Algorithm::SHA224, DataType::Width8).await; - hw_hasher.update(&mut sha224context, test_3).await; - let mut sha224_digest_buffer: [u8; 64] = [0; 64]; - let sha224_digest = hw_hasher.finish(sha224context, &mut sha224_digest_buffer).await; + let mut sha224context = hw_hasher.start(Algorithm::SHA224, DataType::Width8); + hw_hasher.update_blocking(&mut sha224context, test_3); + let mut sha224_digest_buffer: [u8; 28] = [0; 28]; + let _ = hw_hasher.finish_blocking(sha224context, &mut sha224_digest_buffer); // Finish the SHA-256 digest. - hw_hasher.update(&mut sha256context, test_2).await; - let mut sha_256_digest_buffer: [u8; 64] = [0; 64]; - let sha256_digest = hw_hasher.finish(sha256context, &mut sha_256_digest_buffer).await; + hw_hasher.update_blocking(&mut sha256context, test_2); + let mut sha256_digest_buffer: [u8; 32] = [0; 32]; + let _ = hw_hasher.finish_blocking(sha256context, &mut sha256_digest_buffer); // Compute the SHA-256 digest in software. let mut sw_sha256_hasher = Sha256::new(); @@ -64,14 +64,14 @@ async fn main(_spawner: Spawner) { let sw_sha224_digest = sw_sha224_hasher.finalize(); // Compare the SHA-256 digests. - info!("Hardware SHA-256 Digest: {:?}", sha256_digest); + info!("Hardware SHA-256 Digest: {:?}", sha256_digest_buffer); info!("Software SHA-256 Digest: {:?}", sw_sha256_digest[..]); - defmt::assert!(*sha256_digest == sw_sha256_digest[..]); + defmt::assert!(sha256_digest_buffer == sw_sha256_digest[..]); // Compare the SHA-224 digests. - info!("Hardware SHA-256 Digest: {:?}", sha224_digest); + info!("Hardware SHA-256 Digest: {:?}", sha224_digest_buffer); info!("Software SHA-256 Digest: {:?}", sw_sha224_digest[..]); - defmt::assert!(*sha224_digest == sw_sha224_digest[..]); + defmt::assert!(sha224_digest_buffer == sw_sha224_digest[..]); info!("Test OK"); cortex_m::asm::bkpt(); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 14d5b6d7b..fefe72c86 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -128,7 +128,6 @@ define_peris!( ); #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] define_peris!( - HASH_DMA = DMA1_CH0, UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, ADC = ADC1, DAC = DAC1, DAC_PIN = PA4, @@ -142,21 +141,18 @@ define_peris!( ); #[cfg(feature = "stm32u585ai")] define_peris!( - HASH_DMA = GPDMA1_CH0, UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, SPI = SPI1, SPI_SCK = PE13, SPI_MOSI = PE15, SPI_MISO = PE14, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, ); #[cfg(feature = "stm32u5a5zj")] define_peris!( - HASH_DMA = GPDMA1_CH0, UART = LPUART1, UART_TX = PG7, UART_RX = PG8, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, ); #[cfg(feature = "stm32h563zi")] define_peris!( - HASH_DMA = GPDMA1_CH0, UART = LPUART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, SPI = SPI4, SPI_SCK = PE12, SPI_MOSI = PE14, SPI_MISO = PE13, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, @@ -175,7 +171,6 @@ define_peris!( ); #[cfg(feature = "stm32l4a6zg")] define_peris!( - HASH_DMA = DMA2_CH7, UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, @@ -201,7 +196,6 @@ define_peris!( ); #[cfg(feature = "stm32l552ze")] define_peris!( - HASH_DMA = DMA1_CH1, UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, @@ -232,7 +226,6 @@ define_peris!( ); #[cfg(feature = "stm32wba52cg")] define_peris!( - HASH_DMA = GPDMA1_CH0, UART = LPUART1, UART_TX = PB5, UART_RX = PA10, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, SPI = SPI1, SPI_SCK = PB4, SPI_MOSI = PA15, SPI_MISO = PB3, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, From 7bf044278e8c85b5ea6dbe3de6b3cdea884c995a Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 11 Feb 2024 11:47:38 -0500 Subject: [PATCH 432/760] fmt --- examples/stm32f7/src/bin/hash.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index 31f8d32a7..96e50f84b 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -3,7 +3,8 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::{bind_interrupts, hash, hash::*, peripherals, Config}; +use embassy_stm32::hash::*; +use embassy_stm32::{bind_interrupts, hash, peripherals, Config}; use embassy_time::Instant; use sha2::{Digest, Sha256}; use {defmt_rtt as _, panic_probe as _}; From 8f7d80f9f71e55ffe97b72dbb361409aee003ea4 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Sun, 11 Feb 2024 19:37:48 +0100 Subject: [PATCH 433/760] Revert "feat(boot): introduce non-erase flash write method " This reverts commit 2e8b7d259057a0cf345396b250cacfc04a0e64a0. --- embassy-boot/src/firmware_updater/blocking.rs | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 3e83366af..4044871f0 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -225,41 +225,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> Ok(()) } - /// Write data directly to a flash page without erasing it first. - /// - /// This function writes the provided data to the specified offset in the flash memory, - /// without performing an erase operation beforehand. It is crucial that the area being - /// written to is either already erased. - /// This method is intended to be used in conjunction with the `prepare_update` method. - /// - /// The buffer must follow the alignment requirements of the target flash and be a multiple of - /// the page size. This is essential to ensure data integrity and prevent corruption. - /// - /// # Safety - /// - /// This function requires careful management of the memory being written to. Writing to a - /// non-erased page or not adhering to alignment and size requirements may result in a panic. - /// - /// Ensure that the data being written is compatible with the current contents of the flash - /// memory, as no erase operation will be performed to reset the page content to a default state. - /// - /// # Parameters - /// - /// - `offset`: The offset within the DFU partition where the data will be written. Must be - /// aligned according to the flash's requirements and within the writable memory range. - /// - `data`: A reference to the slice of bytes to be written. The length of the data must not - /// exceed the partition size and must follow the flash's alignment requirements. - /// - /// # Returns - /// - /// A result indicating the success or failure of the write operation. On success, returns `Ok(())`. - /// On failure, returns an `Err` with a `FirmwareUpdaterError` detailing the cause of the failure. - pub fn write_firmware_without_erase(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { - self.dfu.write(offset as u32, data)?; - - Ok(()) - } - /// Prepare for an incoming DFU update by erasing the entire DFU area and /// returning its `Partition`. /// From 72ab04c45335ceb725076a38a252749e781a8cf6 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Sun, 11 Feb 2024 19:38:01 +0100 Subject: [PATCH 434/760] Revert "feat(usb-dfu): change usb dfu chunks write mechanism " This reverts commit c95bf6895adfcd33b5238c02620e83c6713205ce. --- embassy-usb-dfu/src/dfu.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index 5f2c98684..e99aa70c3 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -60,21 +60,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha } Ok(Request::Dnload) if self.attrs.contains(DfuAttributes::CAN_DOWNLOAD) => { if req.value == 0 { - match self.updater.prepare_update() { - Ok(_) => { - self.status = Status::Ok; - } - Err(e) => { - self.state = State::Error; - match e { - embassy_boot::FirmwareUpdaterError::Flash(e) => match e { - NorFlashErrorKind::NotAligned => self.status = Status::ErrErase, - _ => self.status = Status::ErrUnknown, - }, - _ => self.status = Status::ErrUnknown, - } - } - } self.state = State::Download; self.offset = 0; } @@ -108,7 +93,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha self.state = State::Error; return Some(OutResponse::Rejected); } - match self.updater.write_firmware_without_erase(self.offset, buf.as_ref()) { + match self.updater.write_firmware(self.offset, buf.as_ref()) { Ok(_) => { self.status = Status::Ok; self.state = State::DlSync; From eb3bd39b068ae34892520ec38f111704ea357355 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Sun, 11 Feb 2024 20:02:28 +0100 Subject: [PATCH 435/760] feat(boot): enhance firmware write functionality --- embassy-boot/src/firmware_updater/asynch.rs | 71 ++++++++++++++++--- embassy-boot/src/firmware_updater/blocking.rs | 70 +++++++++++++++--- 2 files changed, 124 insertions(+), 17 deletions(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 668f16f16..99a3aa246 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -172,21 +172,69 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { self.state.mark_booted().await } - /// Write data to a flash page. + /// Writes firmware data to the device. /// - /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. + /// This function writes the given data to the firmware area starting at the specified offset. + /// It handles sector erasures and data writes while verifying the device is in a proper state + /// for firmware updates. The function ensures that only unerased sectors are erased before + /// writing and efficiently handles the writing process across sector boundaries and in + /// various configurations (data size, page size, etc.). /// - /// # Safety + /// # Arguments /// - /// Failing to meet alignment and size requirements may result in a panic. + /// * `offset` - The starting offset within the firmware area where data writing should begin. + /// * `data` - A slice of bytes representing the firmware data to be written. It must be a + /// multiple of NorFlash WRITE_SIZE. + /// + /// # Returns + /// + /// A `Result<(), FirmwareUpdaterError>` indicating the success or failure of the write operation. + /// + /// # Errors + /// + /// This function will return an error if: + /// + /// - The device is not in a proper state to receive firmware updates (e.g., not booted). + /// - There is a failure erasing a sector before writing. + /// - There is a failure writing data to the device. pub async fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { - assert!(data.len() >= DFU::ERASE_SIZE); - + // Make sure we are running a booted firmware to avoid reverting to a bad state. self.state.verify_booted().await?; - self.dfu.erase(offset as u32, (offset + data.len()) as u32).await?; + // Initialize variables to keep track of the remaining data and the current offset. + let mut remaining_data = data; + let mut offset = offset; - self.dfu.write(offset as u32, data).await?; + // Continue writing as long as there is data left to write. + while !remaining_data.is_empty() { + // Compute the current sector and its boundaries. + let current_sector = offset / DFU::ERASE_SIZE; + let sector_start = current_sector * DFU::ERASE_SIZE; + let sector_end = sector_start + DFU::ERASE_SIZE; + // Determine if the current sector needs to be erased before writing. + let need_erase = self + .state + .last_erased_dfu_page_index + .map_or(true, |last_erased_sector| current_sector != last_erased_sector); + + // If the sector needs to be erased, erase it and update the last erased sector index. + if need_erase { + self.dfu.erase(sector_start as u32, sector_end as u32).await?; + self.state.last_erased_dfu_page_index = Some(current_sector); + } + + // Calculate the size of the data chunk that can be written in the current iteration. + let write_size = core::cmp::min(remaining_data.len(), sector_end - offset); + // Split the data to get the current chunk to be written and the remaining data. + let (data_chunk, rest) = remaining_data.split_at(write_size); + + // Write the current data chunk. + self.dfu.write(offset as u32, data_chunk).await?; + + // Update the offset and remaining data for the next iteration. + remaining_data = rest; + offset += write_size; + } Ok(()) } @@ -210,6 +258,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { pub struct FirmwareState<'d, STATE> { state: STATE, aligned: &'d mut [u8], + last_erased_dfu_page_index: Option, } impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { @@ -231,7 +280,11 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { /// and follow the alignment rules for the flash being read from and written to. pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { assert_eq!(aligned.len(), STATE::WRITE_SIZE.max(STATE::READ_SIZE)); - Self { state, aligned } + Self { + state, + aligned, + last_erased_dfu_page_index: None, + } } // Make sure we are running a booted firmware to avoid reverting to a bad state. diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 4044871f0..45ae966f3 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -207,20 +207,69 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> self.state.mark_booted() } - /// Write data to a flash page. + /// Writes firmware data to the device. /// - /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. + /// This function writes the given data to the firmware area starting at the specified offset. + /// It handles sector erasures and data writes while verifying the device is in a proper state + /// for firmware updates. The function ensures that only unerased sectors are erased before + /// writing and efficiently handles the writing process across sector boundaries and in + /// various configurations (data size, page size, etc.). /// - /// # Safety + /// # Arguments /// - /// Failing to meet alignment and size requirements may result in a panic. + /// * `offset` - The starting offset within the firmware area where data writing should begin. + /// * `data` - A slice of bytes representing the firmware data to be written. It must be a + /// multiple of NorFlash WRITE_SIZE. + /// + /// # Returns + /// + /// A `Result<(), FirmwareUpdaterError>` indicating the success or failure of the write operation. + /// + /// # Errors + /// + /// This function will return an error if: + /// + /// - The device is not in a proper state to receive firmware updates (e.g., not booted). + /// - There is a failure erasing a sector before writing. + /// - There is a failure writing data to the device. pub fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { - assert!(data.len() >= DFU::ERASE_SIZE); + // Make sure we are running a booted firmware to avoid reverting to a bad state. self.state.verify_booted()?; - self.dfu.erase(offset as u32, (offset + data.len()) as u32)?; + // Initialize variables to keep track of the remaining data and the current offset. + let mut remaining_data = data; + let mut offset = offset; - self.dfu.write(offset as u32, data)?; + // Continue writing as long as there is data left to write. + while !remaining_data.is_empty() { + // Compute the current sector and its boundaries. + let current_sector = offset / DFU::ERASE_SIZE; + let sector_start = current_sector * DFU::ERASE_SIZE; + let sector_end = sector_start + DFU::ERASE_SIZE; + // Determine if the current sector needs to be erased before writing. + let need_erase = self + .state + .last_erased_dfu_page_index + .map_or(true, |last_erased_sector| current_sector != last_erased_sector); + + // If the sector needs to be erased, erase it and update the last erased sector index. + if need_erase { + self.dfu.erase(sector_start as u32, sector_end as u32)?; + self.state.last_erased_dfu_page_index = Some(current_sector); + } + + // Calculate the size of the data chunk that can be written in the current iteration. + let write_size = core::cmp::min(remaining_data.len(), sector_end - offset); + // Split the data to get the current chunk to be written and the remaining data. + let (data_chunk, rest) = remaining_data.split_at(write_size); + + // Write the current data chunk. + self.dfu.write(offset as u32, data_chunk)?; + + // Update the offset and remaining data for the next iteration. + remaining_data = rest; + offset += write_size; + } Ok(()) } @@ -244,6 +293,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> pub struct BlockingFirmwareState<'d, STATE> { state: STATE, aligned: &'d mut [u8], + last_erased_dfu_page_index: Option, } impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { @@ -265,7 +315,11 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { /// and written to. pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { assert_eq!(aligned.len(), STATE::WRITE_SIZE); - Self { state, aligned } + Self { + state, + aligned, + last_erased_dfu_page_index: None, + } } // Make sure we are running a booted firmware to avoid reverting to a bad state. From 333b2afe6d5319317b2679e634c3cf242bab0e73 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Sun, 11 Feb 2024 20:17:15 +0100 Subject: [PATCH 436/760] test(boot): add various write firmware test configurations --- embassy-boot/src/firmware_updater/asynch.rs | 72 +++++++++++++++++ embassy-boot/src/firmware_updater/blocking.rs | 78 +++++++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 99a3aa246..d31eff005 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -382,4 +382,76 @@ mod tests { assert_eq!(Sha1::digest(update).as_slice(), hash); } + + #[test] + fn can_verify_sha1_page_bigger_than_chunk() { + let flash = Mutex::::new(MemFlash::<131072, 4096, 8>::default()); + let state = Partition::new(&flash, 0, 4096); + let dfu = Partition::new(&flash, 65536, 65536); + let mut aligned = [0; 8]; + + let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; + let mut to_write = [0; 4096]; + to_write[..7].copy_from_slice(update.as_slice()); + + let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned); + let mut offset = 0; + for chunk in to_write.chunks(1024) { + block_on(updater.write_firmware(offset, chunk)).unwrap(); + offset += chunk.len(); + } + let mut chunk_buf = [0; 2]; + let mut hash = [0; 20]; + block_on(updater.hash::(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); + + assert_eq!(Sha1::digest(update).as_slice(), hash); + } + + #[test] + fn can_verify_sha1_page_smaller_than_chunk() { + let flash = Mutex::::new(MemFlash::<131072, 1024, 8>::default()); + let state = Partition::new(&flash, 0, 4096); + let dfu = Partition::new(&flash, 65536, 65536); + let mut aligned = [0; 8]; + + let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; + let mut to_write = [0; 4096]; + to_write[..7].copy_from_slice(update.as_slice()); + + let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned); + let mut offset = 0; + for chunk in to_write.chunks(2048) { + block_on(updater.write_firmware(offset, chunk)).unwrap(); + offset += chunk.len(); + } + let mut chunk_buf = [0; 2]; + let mut hash = [0; 20]; + block_on(updater.hash::(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); + + assert_eq!(Sha1::digest(update).as_slice(), hash); + } + + #[test] + fn can_verify_sha1_cross_page_boundary() { + let flash = Mutex::::new(MemFlash::<131072, 1024, 8>::default()); + let state = Partition::new(&flash, 0, 4096); + let dfu = Partition::new(&flash, 65536, 65536); + let mut aligned = [0; 8]; + + let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; + let mut to_write = [0; 4096]; + to_write[..7].copy_from_slice(update.as_slice()); + + let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned); + let mut offset = 0; + for chunk in to_write.chunks(896) { + block_on(updater.write_firmware(offset, chunk)).unwrap(); + offset += chunk.len(); + } + let mut chunk_buf = [0; 2]; + let mut hash = [0; 20]; + block_on(updater.hash::(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); + + assert_eq!(Sha1::digest(update).as_slice(), hash); + } } diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 45ae966f3..5b8076f81 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -422,4 +422,82 @@ mod tests { assert_eq!(Sha1::digest(update).as_slice(), hash); } + + #[test] + fn can_verify_sha1_page_bigger_than_chunk() { + let flash = Mutex::::new(RefCell::new(MemFlash::<131072, 4096, 8>::default())); + let state = BlockingPartition::new(&flash, 0, 4096); + let dfu = BlockingPartition::new(&flash, 65536, 65536); + let mut aligned = [0; 8]; + + let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; + let mut to_write = [0; 4096]; + to_write[..7].copy_from_slice(update.as_slice()); + + let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned); + let mut offset = 0; + for chunk in to_write.chunks(1024) { + updater.write_firmware(offset, chunk).unwrap(); + offset += chunk.len(); + } + let mut chunk_buf = [0; 2]; + let mut hash = [0; 20]; + updater + .hash::(update.len() as u32, &mut chunk_buf, &mut hash) + .unwrap(); + + assert_eq!(Sha1::digest(update).as_slice(), hash); + } + + #[test] + fn can_verify_sha1_page_smaller_than_chunk() { + let flash = Mutex::::new(RefCell::new(MemFlash::<131072, 1024, 8>::default())); + let state = BlockingPartition::new(&flash, 0, 4096); + let dfu = BlockingPartition::new(&flash, 65536, 65536); + let mut aligned = [0; 8]; + + let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; + let mut to_write = [0; 4096]; + to_write[..7].copy_from_slice(update.as_slice()); + + let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned); + let mut offset = 0; + for chunk in to_write.chunks(2048) { + updater.write_firmware(offset, chunk).unwrap(); + offset += chunk.len(); + } + let mut chunk_buf = [0; 2]; + let mut hash = [0; 20]; + updater + .hash::(update.len() as u32, &mut chunk_buf, &mut hash) + .unwrap(); + + assert_eq!(Sha1::digest(update).as_slice(), hash); + } + + #[test] + fn can_verify_sha1_cross_page_boundary() { + let flash = Mutex::::new(RefCell::new(MemFlash::<131072, 1024, 8>::default())); + let state = BlockingPartition::new(&flash, 0, 4096); + let dfu = BlockingPartition::new(&flash, 65536, 65536); + let mut aligned = [0; 8]; + + let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; + let mut to_write = [0; 4096]; + to_write[..7].copy_from_slice(update.as_slice()); + + let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned); + let mut offset = 0; + for chunk in to_write.chunks(896) { + updater.write_firmware(offset, chunk).unwrap(); + offset += chunk.len(); + } + let mut chunk_buf = [0; 2]; + let mut hash = [0; 20]; + updater + .hash::(update.len() as u32, &mut chunk_buf, &mut hash) + .unwrap(); + + assert_eq!(Sha1::digest(update).as_slice(), hash); + } } From 58fa5e57b67935d2a81f4fd708d6829afb8112b0 Mon Sep 17 00:00:00 2001 From: Mick Chanthaseth Date: Sun, 11 Feb 2024 16:04:06 -0800 Subject: [PATCH 437/760] added usb_hid_mouse example for rp --- examples/rp/src/bin/usb_hid_mouse.rs | 183 +++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 examples/rp/src/bin/usb_hid_mouse.rs diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs new file mode 100644 index 000000000..ec125a47e --- /dev/null +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -0,0 +1,183 @@ +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::bind_interrupts; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Input, Pull}; +use embassy_rp::peripherals::USB; +use embassy_time::Timer; +use embassy_rp::usb::{Driver, InterruptHandler}; +use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; +use embassy_usb::control::OutResponse; +use embassy_usb::{Builder, Config, Handler}; +use rand::{Rng, RngCore}; +use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + // Create the driver, from the HAL. + let driver = Driver::new(p.USB, Irqs); + + // Create embassy-usb Config + let mut config = Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("HID keyboard example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + // You can also add a Microsoft OS descriptor. + let mut msos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + let request_handler = MyRequestHandler {}; + let mut device_handler = MyDeviceHandler::new(); + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut msos_descriptor, + &mut control_buf, + ); + + builder.handler(&mut device_handler); + + // Create classes on the builder. + let config = embassy_usb::class::hid::Config { + report_descriptor: MouseReport::desc(), + request_handler: Some(&request_handler), + poll_ms: 60, + max_packet_size: 64, + }; + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Set up the signal pin that will be used to trigger the keyboard. + let mut signal_pin = Input::new(p.PIN_16, Pull::None); + + // Enable the schmitt trigger to slightly debounce. + signal_pin.set_schmitt(true); + + let (reader, mut writer) = hid.split(); + + // Do stuff with the class! + let in_fut = async { + let mut rng = RoscRng; + + loop { + // every 1 second + _ = Timer::after_secs(1).await; + let report = MouseReport{ + buttons: 0, + x: rng.gen_range(-100..100), // random small x movement + y: rng.gen_range(-100..100), // random small y movement + wheel: 0, + pan: 0, + }; + match writer.write_serialize(&report).await{ + Ok(())=>{}, + Err(e)=>{ + warn!("Failed to send report: {:?}", e); + }, + } + } + }; + + let out_fut = async { + reader.run(false, &request_handler).await; + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, join(in_fut, out_fut)).await; +} + +struct MyRequestHandler {} + +impl RequestHandler for MyRequestHandler { + fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + info!("Get report for {:?}", id); + None + } + + fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + info!("Set report for {:?}: {=[u8]}", id, data); + OutResponse::Accepted + } + + fn set_idle_ms(&self, id: Option, dur: u32) { + info!("Set idle rate for {:?} to {:?}", id, dur); + } + + fn get_idle_ms(&self, id: Option) -> Option { + info!("Get idle rate for {:?}", id); + None + } +} + +struct MyDeviceHandler { + configured: AtomicBool, +} + +impl MyDeviceHandler { + fn new() -> Self { + MyDeviceHandler { + configured: AtomicBool::new(false), + } + } +} + +impl Handler for MyDeviceHandler { + fn enabled(&mut self, enabled: bool) { + self.configured.store(false, Ordering::Relaxed); + if enabled { + info!("Device enabled"); + } else { + info!("Device disabled"); + } + } + + fn reset(&mut self) { + self.configured.store(false, Ordering::Relaxed); + info!("Bus reset, the Vbus current limit is 100mA"); + } + + fn addressed(&mut self, addr: u8) { + self.configured.store(false, Ordering::Relaxed); + info!("USB address set to: {}", addr); + } + + fn configured(&mut self, configured: bool) { + self.configured.store(configured, Ordering::Relaxed); + if configured { + info!("Device configured, it may now draw up to the configured current limit from Vbus.") + } else { + info!("Device is no longer configured, the Vbus current limit is 100mA."); + } + } +} From 0dc5e6d3e4646fd8f67840f32a756d55ac36569a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Feb 2024 02:17:33 +0100 Subject: [PATCH 438/760] stm32/rcc: port F3 RCC to new API See #2515 --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/f3.rs | 611 ++++++++++--------------- embassy-stm32/src/rcc/mco.rs | 24 +- examples/stm32f3/src/bin/hello.rs | 5 +- examples/stm32f3/src/bin/usb_serial.rs | 21 +- examples/stm32f334/src/bin/adc.rs | 24 +- examples/stm32f334/src/bin/hello.rs | 5 +- examples/stm32f334/src/bin/opamp.rs | 24 +- examples/stm32f334/src/bin/pwm.rs | 27 +- tests/stm32/src/common.rs | 18 + 10 files changed, 351 insertions(+), 412 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3f5f12f06..24af17327 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ae5bb5fe696a7e61fb41b8b797372aed8103a82" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ae5bb5fe696a7e61fb41b8b797372aed8103a82", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 25866e446..0a5e67b4a 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -1,208 +1,230 @@ -#[cfg(rcc_f3)] -use crate::pac::adccommon::vals::Ckmode; use crate::pac::flash::vals::Latency; -pub use crate::pac::rcc::vals::Adcpres; -use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; +pub use crate::pac::rcc::vals::{ + Adcpres as AdcPllPrescaler, Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Prediv as PllPreDiv, + Sw as Sysclk, +}; +use crate::pac::rcc::vals::{Pllsrc, Usbpre}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(8_000_000); -#[cfg(rcc_f3)] -impl From for Ckmode { - fn from(value: AdcClockSource) -> Self { - match value { - AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1, - AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2, - AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4, - _ => unreachable!(), - } - } +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1) + Bypass, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum PllSource { + HSE, + HSI, +} + +#[derive(Clone, Copy)] +pub struct Pll { + pub src: PllSource, + + /// PLL pre-divider. + /// + /// On some F3 chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. + pub prediv: PllPreDiv, + + /// PLL multiplication factor. + pub mul: PllMul, } #[derive(Clone, Copy)] pub enum AdcClockSource { - Pll(Adcpres), - BusDiv1, - BusDiv2, - BusDiv4, + Pll(AdcPllPrescaler), + Hclk(AdcHclkPrescaler), } -impl AdcClockSource { - pub fn bus_div(&self) -> u32 { - match self { - Self::BusDiv1 => 1, - Self::BusDiv2 => 2, - Self::BusDiv4 => 4, - _ => unreachable!(), - } - } +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AdcHclkPrescaler { + Div1, + Div2, + Div4, } -#[derive(Default)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum HrtimClockSource { - #[default] BusClk, PllClk, } /// Clocks configutation #[non_exhaustive] -#[derive(Default)] pub struct Config { - /// Frequency of HSE oscillator - /// 4MHz to 32MHz - pub hse: Option, - /// Bypass HSE for an external clock - pub bypass_hse: bool, - /// Frequency of the System Clock - pub sysclk: Option, - /// Frequency of AHB bus - pub hclk: Option, - /// Frequency of APB1 bus - /// - Max frequency 36MHz - pub pclk1: Option, - /// Frequency of APB2 bus - /// - Max frequency with HSE is 72MHz - /// - Max frequency without HSE is 64MHz - pub pclk2: Option, - /// USB clock setup - /// It is valid only when, - /// - HSE is enabled, - /// - The System clock frequency is either 48MHz or 72MHz - /// - APB1 clock has a minimum frequency of 10MHz - pub pll48: bool, - #[cfg(rcc_f3)] - /// ADC clock setup - /// - For AHB, a psc of 4 or less must be used - pub adc: Option, - #[cfg(rcc_f3)] - /// ADC clock setup - /// - For AHB, a psc of 4 or less must be used - pub adc34: Option, + pub hsi: bool, + pub hse: Option, + pub sys: Sysclk, + + pub pll: Option, + + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + pub apb2_pre: APBPrescaler, + + #[cfg(not(rcc_f37))] + pub adc: AdcClockSource, + #[cfg(all(not(rcc_f37), adc3_common))] + pub adc34: AdcClockSource, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, + pub ls: super::LsConfig, } -// Information required to setup the PLL clock -#[derive(Clone, Copy)] -struct PllConfig { - pll_src: Pllsrc, - pll_mul: Pllmul, - pll_div: Option, +impl Default for Config { + fn default() -> Self { + Self { + hsi: true, + hse: None, + sys: Sysclk::HSI, + pll: None, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + ls: Default::default(), + + #[cfg(not(rcc_f37))] + adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), + #[cfg(all(not(rcc_f37), adc3_common))] + adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), + #[cfg(stm32f334)] + hrtim: HrtimClockSource::BusClk, + } + } } /// Initialize and Set the clock frequencies pub(crate) unsafe fn init(config: Config) { - // Calculate the real System clock, and PLL configuration if applicable - let (sysclk, pll_config) = get_sysclk(&config); - assert!(sysclk.0 <= 72_000_000); - - // Calculate real AHB clock - let hclk = config.hclk.map(|h| h).unwrap_or(sysclk); - let hpre = match sysclk.0 / hclk.0 { - 0 => unreachable!(), - 1 => Hpre::DIV1, - 2 => Hpre::DIV2, - 3..=5 => Hpre::DIV4, - 6..=11 => Hpre::DIV8, - 12..=39 => Hpre::DIV16, - 40..=95 => Hpre::DIV64, - 96..=191 => Hpre::DIV128, - 192..=383 => Hpre::DIV256, - _ => Hpre::DIV512, + // Configure HSI + let hsi = match config.hsi { + false => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + true => { + RCC.cr().modify(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + Some(HSI_FREQ) + } }; - let hclk = sysclk / hpre; - assert!(hclk <= Hertz(72_000_000)); - // Calculate real APB1 clock - let pclk1 = config.pclk1.unwrap_or(hclk); - let ppre1 = match hclk / pclk1 { - 0 => unreachable!(), - 1 => Ppre::DIV1, - 2 => Ppre::DIV2, - 3..=5 => Ppre::DIV4, - 6..=11 => Ppre::DIV8, - _ => Ppre::DIV16, - }; - let timer_mul1 = if ppre1 == Ppre::DIV1 { 1u32 } else { 2 }; - let pclk1 = hclk / ppre1; - assert!(pclk1 <= Hertz(36_000_000)); + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } - // Calculate real APB2 clock - let pclk2 = config.pclk2.unwrap_or(hclk); - let ppre2 = match hclk / pclk2 { - 0 => unreachable!(), - 1 => Ppre::DIV1, - 2 => Ppre::DIV2, - 3..=5 => Ppre::DIV4, - 6..=11 => Ppre::DIV8, - _ => Ppre::DIV16, + RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } }; - let timer_mul2 = if ppre2 == Ppre::DIV1 { 1u32 } else { 2 }; - let pclk2 = hclk / ppre2; - assert!(pclk2 <= Hertz(72_000_000)); + + // Enable PLL + // RM0316: "Reserved, must be kept at reset value." + let pll = config.pll.map(|pll| { + let (src_val, src_freq) = match pll.src { + #[cfg(rcc_f3v3)] + PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)), + #[cfg(not(rcc_f3v3))] + PllSource::HSI => { + if pll.prediv != PllPreDiv::DIV2 { + panic!("if PLL source is HSI, PLL prediv must be 2."); + } + (Pllsrc::HSI_DIV2, unwrap!(hsi)) + } + PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), + }; + let in_freq = src_freq / pll.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let out_freq = in_freq * pll.mul; + assert!(max::PLL_OUT.contains(&out_freq)); + + RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); + RCC.cfgr().modify(|w| { + w.set_pllmul(pll.mul); + w.set_pllsrc(src_val); + }); + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + + out_freq + }); + + let usb = match pll { + Some(Hertz(72_000_000)) => { + RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1_5)); + Some(Hertz(48_000_000)) + } + Some(Hertz(48_000_000)) => { + RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1)); + Some(Hertz(48_000_000)) + } + _ => None, + }; + + // Configure sysclk + let sys = match config.sys { + Sysclk::HSI => unwrap!(hsi), + Sysclk::HSE => unwrap!(hse), + Sysclk::PLL1_P => unwrap!(pll), + _ => unreachable!(), + }; + + let hclk = sys / config.ahb_pre; + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); + + assert!(max::HCLK.contains(&hclk)); + assert!(max::PCLK1.contains(&pclk1)); + assert!(max::PCLK2.contains(&pclk2)); // Set latency based on HCLK frquency - // RM0316: "The prefetch buffer must be kept on when using a prescaler - // different from 1 on the AHB clock.", "Half-cycle access cannot be - // used when there is a prescaler different from 1 on the AHB clock" + let latency = match hclk.0 { + ..=24_000_000 => Latency::WS0, + ..=48_000_000 => Latency::WS1, + _ => Latency::WS2, + }; FLASH.acr().modify(|w| { - w.set_latency(if hclk <= Hertz(24_000_000) { - Latency::WS0 - } else if hclk <= Hertz(48_000_000) { - Latency::WS1 - } else { - Latency::WS2 - }); - if hpre != Hpre::DIV1 { + w.set_latency(latency); + // RM0316: "The prefetch buffer must be kept on when using a prescaler + // different from 1 on the AHB clock.", "Half-cycle access cannot be + // used when there is a prescaler different from 1 on the AHB clock" + if config.ahb_pre != AHBPrescaler::DIV1 { w.set_hlfcya(false); w.set_prftbe(true); } }); - // Enable HSE - // RM0316: "Bits 31:26 Reserved, must be kept at reset value." - if config.hse.is_some() { - RCC.cr().modify(|w| { - w.set_hsebyp(config.bypass_hse); - // We turn on clock security to switch to HSI when HSE fails - w.set_csson(true); - w.set_hseon(true); - }); - while !RCC.cr().read().hserdy() {} - } - - // Enable PLL - // RM0316: "Reserved, must be kept at reset value." - if let Some(ref pll_config) = pll_config { - RCC.cfgr().modify(|w| { - w.set_pllmul(pll_config.pll_mul); - w.set_pllsrc(pll_config.pll_src); - }); - if let Some(pll_div) = pll_config.pll_div { - RCC.cfgr2().modify(|w| w.set_prediv(pll_div)); - } - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - } - - // CFGR has been written before (PLL) don't overwrite these settings - if config.pll48 { - let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config); - RCC.cfgr().modify(|w| { - w.set_usbpre(usb_pre); - }); - } - // Set prescalers // CFGR has been written before (PLL, PLL48) don't overwrite these settings RCC.cfgr().modify(|w| { - w.set_ppre2(ppre2); - w.set_ppre1(ppre1); - w.set_hpre(hpre); + w.set_ppre2(config.apb1_pre); + w.set_ppre1(config.apb2_pre); + w.set_hpre(config.ahb_pre); }); // Wait for the new prescalers to kick in @@ -211,53 +233,60 @@ pub(crate) unsafe fn init(config: Config) { cortex_m::asm::delay(16); // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings - RCC.cfgr().modify(|w| { - w.set_sw(match (pll_config, config.hse) { - (Some(_), _) => Sw::PLL1_P, - (None, Some(_)) => Sw::HSE, - (None, None) => Sw::HSI, - }) - }); + RCC.cfgr().modify(|w| w.set_sw(config.sys)); - #[cfg(rcc_f3)] - let adc = config.adc.map(|adc| match adc { + let rtc = config.ls.init(); + + #[cfg(not(rcc_f37))] + use crate::pac::adccommon::vals::Ckmode; + + #[cfg(not(rcc_f37))] + let adc = match config.adc { AdcClockSource::Pll(adcpres) => { - RCC.cfgr2().modify(|w| { - // Make sure that we're using the PLL - pll_config.unwrap(); - w.set_adc12pres(adcpres); + RCC.cfgr2().modify(|w| w.set_adc12pres(adcpres)); + crate::pac::ADC_COMMON + .ccr() + .modify(|w| w.set_ckmode(Ckmode::ASYNCHRONOUS)); - sysclk / adcpres - }) + unwrap!(pll) / adcpres } - _ => crate::pac::ADC_COMMON.ccr().modify(|w| { - assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1)); + AdcClockSource::Hclk(adcpres) => { + assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); - w.set_ckmode(adc.into()); + let (div, ckmode) = match adcpres { + AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), + AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), + AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), + }; + crate::pac::ADC_COMMON.ccr().modify(|w| w.set_ckmode(ckmode)); - sysclk / adc.bus_div() - }), - }); + hclk / div + } + }; - #[cfg(all(rcc_f3, adc3_common))] - let adc34 = config.adc34.map(|adc| match adc { + #[cfg(all(not(rcc_f37), adc3_common))] + let adc34 = match config.adc34 { AdcClockSource::Pll(adcpres) => { - RCC.cfgr2().modify(|w| { - // Make sure that we're using the PLL - pll_config.unwrap(); - w.set_adc34pres(adcpres); + RCC.cfgr2().modify(|w| w.set_adc34pres(adcpres)); + crate::pac::ADC3_COMMON + .ccr() + .modify(|w| w.set_ckmode(Ckmode::ASYNCHRONOUS)); - sysclk / adcpres - }) + unwrap!(pll) / adcpres } - _ => crate::pac::ADC_COMMON.ccr().modify(|w| { - assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1)); + AdcClockSource::Hclk(adcpres) => { + assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); - w.set_ckmode(adc.into()); + let (div, ckmode) = match adcpres { + AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), + AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), + AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), + }; + crate::pac::ADC3_COMMON.ccr().modify(|w| w.set_ckmode(ckmode)); - sysclk / adc.bus_div() - }), - }); + hclk / div + } + }; #[cfg(stm32f334)] let hrtim = match config.hrtim { @@ -267,195 +296,49 @@ pub(crate) unsafe fn init(config: Config) { use crate::pac::rcc::vals::Timsw; // Make sure that we're using the PLL - pll_config.unwrap(); - assert!((pclk2 == sysclk) || (pclk2 * 2u32 == sysclk)); + let pll = unwrap!(pll); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL1_P)); - Some(sysclk * 2u32) + Some(pll * 2u32) } }; - let rtc = config.ls.init(); - set_clocks!( - hsi: None, - lse: None, - pll1_p: None, - sys: Some(sysclk), + hsi: hsi, + hse: hse, + pll1_p: pll, + sys: Some(sys), pclk1: Some(pclk1), pclk2: Some(pclk2), - pclk1_tim: Some(pclk1 * timer_mul1), - pclk2_tim: Some(pclk2 * timer_mul2), + pclk1_tim: Some(pclk1_tim), + pclk2_tim: Some(pclk2_tim), hclk1: Some(hclk), - #[cfg(rcc_f3)] - adc: adc, - #[cfg(all(rcc_f3, adc3_common))] - adc34: adc34, - #[cfg(all(rcc_f3, not(adc3_common)))] - adc34: None, + #[cfg(not(rcc_f37))] + adc: Some(adc), + #[cfg(all(not(rcc_f37), adc3_common))] + adc34: Some(adc34), #[cfg(stm32f334)] hrtim: hrtim, rtc: rtc, + usb: usb, + lse: None, ); } -#[inline] -fn get_sysclk(config: &Config) -> (Hertz, Option) { - match (config.sysclk, config.hse) { - (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), - (Some(sysclk), None) if sysclk == HSI_FREQ => (HSI_FREQ, None), - // If the user selected System clock is different from HSI or HSE - // we will have to setup PLL clock source - (Some(sysclk), _) => { - let (sysclk, pll_config) = calc_pll(config, sysclk); - (sysclk, Some(pll_config)) - } - (None, Some(hse)) => (hse, None), - (None, None) => (HSI_FREQ, None), - } -} +mod max { + use core::ops::RangeInclusive; -#[inline] -fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { - // Calculates the Multiplier and the Divisor to arrive at - // the required System clock from PLL source frequency - let get_mul_div = |sysclk, pllsrcclk| { - let bus_div = gcd(sysclk, pllsrcclk); - let mut multiplier = sysclk / bus_div; - let mut divisor = pllsrcclk / bus_div; - // Minimum PLL multiplier is two - if multiplier == 1 { - multiplier *= 2; - divisor *= 2; - } - assert!(multiplier <= 16); - assert!(divisor <= 16); - (multiplier, divisor) - }; - // Based on the source of Pll, we calculate the actual system clock - // frequency, PLL's source identifier, multiplier and divisor - let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse { - Some(Hertz(hse)) => { - let (multiplier, divisor) = get_mul_div(sysclk, hse); - ( - Hertz((hse / divisor) * multiplier), - Pllsrc::HSE_DIV_PREDIV, - into_pll_mul(multiplier), - Some(into_pre_div(divisor)), - ) - } - None => { - cfg_if::cfg_if! { - // For some chips PREDIV is always two, and cannot be changed - if #[cfg(any(flashsize_d, flashsize_e))] { - let (multiplier, divisor) = get_mul_div(sysclk, HSI_FREQ.0); - ( - Hertz((HSI_FREQ.0 / divisor) * multiplier), - Pllsrc::HSI_DIV_PREDIV, - into_pll_mul(multiplier), - Some(into_pre_div(divisor)), - ) - } else { - let pllsrcclk = HSI_FREQ.0 / 2; - let multiplier = sysclk / pllsrcclk; - assert!(multiplier <= 16); - ( - Hertz(pllsrcclk * multiplier), - Pllsrc::HSI_DIV2, - into_pll_mul(multiplier), - None, - ) - } - } - } - }; - ( - act_sysclk, - PllConfig { - pll_src, - pll_mul, - pll_div, - }, - ) -} + use crate::time::Hertz; -#[inline] -#[allow(unused_variables)] -fn get_usb_pre(config: &Config, sysclk: Hertz, pclk1: Hertz, pll_config: &Option) -> Usbpre { - cfg_if::cfg_if! { - // Some chips do not have USB - if #[cfg(any(stm32f301, stm32f318, stm32f334))] { - panic!("USB clock not supported by the chip"); - } else { - let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= Hertz(10_000_000)); - match (usb_ok, sysclk) { - (true, Hertz(72_000_000)) => Usbpre::DIV1_5, - (true, Hertz(48_000_000)) => Usbpre::DIV1, - _ => panic!( - "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" - ), - } - } - } -} + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(32_000_000); + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(32_000_000); -// This function assumes cases when multiplier is one and it -// being greater than 16 is made impossible -#[inline] -fn into_pll_mul(multiplier: u32) -> Pllmul { - match multiplier { - 2 => Pllmul::MUL2, - 3 => Pllmul::MUL3, - 4 => Pllmul::MUL4, - 5 => Pllmul::MUL5, - 6 => Pllmul::MUL6, - 7 => Pllmul::MUL7, - 8 => Pllmul::MUL8, - 9 => Pllmul::MUL9, - 10 => Pllmul::MUL10, - 11 => Pllmul::MUL11, - 12 => Pllmul::MUL12, - 13 => Pllmul::MUL13, - 14 => Pllmul::MUL14, - 15 => Pllmul::MUL15, - 16 => Pllmul::MUL16, - _ => unreachable!(), - } -} + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(72_000_000); + pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(36_000_000); + pub(crate) const PCLK2: RangeInclusive = Hertz(0)..=Hertz(72_000_000); -// This function assumes the incoming divisor cannot be greater -// than 16 -#[inline] -fn into_pre_div(divisor: u32) -> Prediv { - match divisor { - 1 => Prediv::DIV1, - 2 => Prediv::DIV2, - 3 => Prediv::DIV3, - 4 => Prediv::DIV4, - 5 => Prediv::DIV5, - 6 => Prediv::DIV6, - 7 => Prediv::DIV7, - 8 => Prediv::DIV8, - 9 => Prediv::DIV9, - 10 => Prediv::DIV10, - 11 => Prediv::DIV11, - 12 => Prediv::DIV12, - 13 => Prediv::DIV13, - 14 => Prediv::DIV14, - 15 => Prediv::DIV15, - 16 => Prediv::DIV16, - _ => unreachable!(), - } -} - -// Determine GCD using Euclidean algorithm -#[inline] -fn gcd(mut a: u32, mut b: u32) -> u32 { - while b != 0 { - let r = a % b; - a = b; - b = r; - } - a + pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(24_000_000); + pub(crate) const PLL_OUT: RangeInclusive = Hertz(16_000_000)..=Hertz(72_000_000); } diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index eaaf8071c..db0df9fac 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -4,7 +4,7 @@ use embassy_hal_internal::into_ref; use crate::gpio::sealed::AFType; use crate::gpio::Speed; -#[cfg(not(stm32f1))] +#[cfg(not(any(stm32f1, rcc_f3v1, rcc_f37)))] pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; #[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] pub use crate::pac::rcc::vals::Mcosel as McoSource; @@ -13,10 +13,16 @@ pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; use crate::pac::RCC; use crate::{peripherals, Peripheral}; +#[cfg(any(stm32f1, rcc_f3v1, rcc_f37))] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum McoPrescaler { + DIV1, +} + pub(crate) mod sealed { pub trait McoInstance { type Source; - unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: super::McoPrescaler); + unsafe fn apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler); } } @@ -29,7 +35,7 @@ macro_rules! impl_peri { impl sealed::McoInstance for peripherals::$peri { type Source = $source; - unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: McoPrescaler) { + unsafe fn apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { #[cfg(not(any(stm32u5, stm32wba)))] let r = RCC.cfgr(); #[cfg(any(stm32u5, stm32wba))] @@ -37,8 +43,8 @@ macro_rules! impl_peri { r.modify(|w| { w.$set_source(source); - #[cfg(not(stm32f1))] - w.$set_prescaler(prescaler); + #[cfg(not(any(stm32f1, rcc_f3v1, rcc_f37)))] + w.$set_prescaler(_prescaler); }); } } @@ -68,16 +74,12 @@ impl<'d, T: McoInstance> Mco<'d, T> { _peri: impl Peripheral

+ 'd, pin: impl Peripheral

> + 'd, source: T::Source, - #[cfg(not(stm32f1))] prescaler: McoPrescaler, + prescaler: McoPrescaler, ) -> Self { into_ref!(pin); critical_section::with(|_| unsafe { - T::apply_clock_settings( - source, - #[cfg(not(stm32f1))] - prescaler, - ); + T::apply_clock_settings(source, prescaler); pin.set_as_af(pin.af_num(), AFType::OutputPushPull); pin.set_speed(Speed::VeryHigh); }); diff --git a/examples/stm32f3/src/bin/hello.rs b/examples/stm32f3/src/bin/hello.rs index fd54da53d..3c295612c 100644 --- a/examples/stm32f3/src/bin/hello.rs +++ b/examples/stm32f3/src/bin/hello.rs @@ -3,16 +3,13 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::time::Hertz; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { - let mut config = Config::default(); - config.rcc.hse = Some(Hertz(8_000_000)); - config.rcc.sysclk = Some(Hertz(16_000_000)); + let config = Config::default(); let _p = embassy_stm32::init(config); loop { diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index cf9ecedfa..ee1c43afd 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs @@ -21,11 +21,22 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.hse = Some(mhz(8)); - config.rcc.sysclk = Some(mhz(48)); - config.rcc.pclk1 = Some(mhz(24)); - config.rcc.pclk2 = Some(mhz(24)); - config.rcc.pll48 = true; + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index 063ee9dac..a9fb7f1a6 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -5,7 +5,6 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC1; -use embassy_stm32::rcc::{AdcClockSource, Adcpres}; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Timer}; @@ -18,12 +17,23 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.sysclk = Some(mhz(64)); - config.rcc.hclk = Some(mhz(64)); - config.rcc.pclk1 = Some(mhz(32)); - config.rcc.pclk2 = Some(mhz(64)); - config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); - + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.adc = AdcClockSource::Pll(AdcPllPrescaler::DIV1); + } let mut p = embassy_stm32::init(config); info!("create adc..."); diff --git a/examples/stm32f334/src/bin/hello.rs b/examples/stm32f334/src/bin/hello.rs index fd54da53d..3c295612c 100644 --- a/examples/stm32f334/src/bin/hello.rs +++ b/examples/stm32f334/src/bin/hello.rs @@ -3,16 +3,13 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::time::Hertz; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { - let mut config = Config::default(); - config.rcc.hse = Some(Hertz(8_000_000)); - config.rcc.sysclk = Some(Hertz(16_000_000)); + let config = Config::default(); let _p = embassy_stm32::init(config); loop { diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 850a0e335..6f25191be 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -6,7 +6,6 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::opamp::{OpAmp, OpAmpGain}; use embassy_stm32::peripherals::ADC2; -use embassy_stm32::rcc::{AdcClockSource, Adcpres}; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Timer}; @@ -19,12 +18,23 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.sysclk = Some(mhz(64)); - config.rcc.hclk = Some(mhz(64)); - config.rcc.pclk1 = Some(mhz(32)); - config.rcc.pclk2 = Some(mhz(64)); - config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); - + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.adc = AdcClockSource::Pll(AdcPllPrescaler::DIV1); + } let mut p = embassy_stm32::init(config); info!("create adc..."); diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index c149cad92..7fc1ea926 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::hrtim::*; -use embassy_stm32::rcc::HrtimClockSource; use embassy_stm32::time::{khz, mhz}; use embassy_stm32::Config; use embassy_time::Timer; @@ -12,14 +11,26 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut config: Config = Default::default(); - config.rcc.sysclk = Some(mhz(64)); - config.rcc.hclk = Some(mhz(64)); - config.rcc.pclk1 = Some(mhz(32)); - config.rcc.pclk2 = Some(mhz(64)); - config.rcc.hrtim = HrtimClockSource::PllClk; - + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.hrtim = HrtimClockSource::PllClk; + } let p = embassy_stm32::init(config); + info!("Hello World!"); let ch1 = PwmPin::new_cha(p.PA8); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index fefe72c86..36fe8a235 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -276,6 +276,24 @@ pub fn config() -> Config { config.rcc.apb2_pre = APBPrescaler::DIV2; } + #[cfg(feature = "stm32f303ze")] + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + } + #[cfg(feature = "stm32f429zi")] { use embassy_stm32::rcc::*; From b4f0f575388df405e4e7330f2e8cdac30c4d60d9 Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Mon, 12 Feb 2024 13:21:01 +0100 Subject: [PATCH 439/760] remove first person comments --- embassy-nrf/src/lib.rs | 3 ++- embassy-nrf/src/radio/ble.rs | 22 +++++----------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 5dba6f975..04a6293a4 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -46,7 +46,8 @@ pub mod gpio; #[cfg(feature = "gpiote")] pub mod gpiote; -#[cfg(any(feature = "nrf52840"))] // needs to be tested on other chips +// TODO: tested on other chips +#[cfg(any(feature = "nrf52840"))] pub mod radio; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index ba9ac5f2e..81ef96b65 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -1,15 +1,4 @@ //! Radio driver implementation focused on Bluetooth Low-Energy transmission. -//! -//! The radio can calculate the CRC, perform data whitening, -//! automatically send the right preamble. -//! Most of the configuration is done automatically when you choose the mode and this driver. -//! -//! Some configuration can just be done when de device is disabled, -//! and the configuration varies depending if is a transmitter or a receiver. -//! Because of that we have a state machine to keep track of the state of the radio. -//! The Radio is the disable radio which configure the common parameters between -//! the bluetooth protocols, like the package format, the CRC and the whitening. -//! The TxRadio radio enable and configured as a transmitter with the specific parameters. use core::future::poll_fn; use core::sync::atomic::{compiler_fence, Ordering}; @@ -241,7 +230,7 @@ impl<'d, T: Instance> Radio<'d, T> { .write(|w| unsafe { w.ap0().bits((access_address >> 24) as u8) }); // The base address is truncated from the least significant byte (because the BALEN is less than 4) - // So we need to shift the address to the right + // So it shifts the address to the right r.base0.write(|w| unsafe { w.bits(access_address << 8) }); // Don't match tx address @@ -317,13 +306,12 @@ impl<'d, T: Instance> Radio<'d, T> { /// Also if the buffer is smaller than the packet length, the radio will /// read/write memory out of the buffer bounds. fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { - // Because we are serializing the buffer, we should always have the buffer in RAM slice_in_ram_or(buffer, Error::BufferNotInRAM)?; let r = T::regs(); - // Here we are considering that the length of the packet is - // correctly set in the buffer, otherwise we will sending + // Here it consider that the length of the packet is + // correctly set in the buffer, otherwise it will send // unowned regions of memory let ptr = buffer.as_ptr(); @@ -374,7 +362,7 @@ impl<'d, T: Instance> Radio<'d, T> { let s = T::state(); // If the Future is dropped before the end of the transmission - // we need to disable the interrupt and stop the transmission + // it disable the interrupt and stop the transmission // to keep the state consistent let drop = OnDrop::new(|| { trace!("radio drop: stopping"); @@ -417,7 +405,7 @@ impl<'d, T: Instance> Radio<'d, T> { compiler_fence(Ordering::SeqCst); r.events_disabled.reset(); // ACK - // Everthing ends fine, so we can disable the drop + // Everthing ends fine, so it disable the drop drop.defuse(); } From 16ed0b1e37a6106596efb2f3fa26344d550fc1ff Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Mon, 12 Feb 2024 19:01:22 +0100 Subject: [PATCH 440/760] Move usb clas loop to private function Move const to the outside of the logger --- embassy-usb-logger/src/lib.rs | 75 +++++++++++++++-------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index a057fcf32..da5ff0f36 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -6,7 +6,7 @@ use core::fmt::Write as _; use embassy_futures::join::join; use embassy_sync::pipe::Pipe; -use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; use embassy_usb::driver::Driver; use embassy_usb::{Builder, Config}; use log::{Metadata, Record}; @@ -37,6 +37,9 @@ impl<'d> LoggerState<'d> { } } +/// The packet size used in the usb logger, to be used with `create_future_from_class` +pub const MAX_PACKET_SIZE: u8 = 64; + /// The logger handle, which contains a pipe with configurable size for buffering log messages. pub struct UsbLogger { buffer: Pipe, @@ -54,7 +57,6 @@ impl UsbLogger { D: Driver<'d>, Self: 'd, { - const MAX_PACKET_SIZE: u8 = 64; let mut config = Config::new(0xc0de, 0xcafe); config.manufacturer = Some("Embassy"); config.product = Some("USB-serial logger"); @@ -87,57 +89,46 @@ impl UsbLogger { let mut device = builder.build(); loop { let run_fut = device.run(); - let log_fut = async { - let mut rx: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; - sender.wait_connection().await; - loop { - let len = self.buffer.read(&mut rx[..]).await; - let _ = sender.write_packet(&rx[..len]).await; - if len as u8 == MAX_PACKET_SIZE { - let _ = sender.write_packet(&[]).await; - } - } - }; - let discard_fut = async { - let mut discard_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; - receiver.wait_connection().await; - loop { - let _ = receiver.read_packet(&mut discard_buf).await; - } - }; - join(run_fut, join(log_fut, discard_fut)).await; + let class_fut = self.run_logger_class(&mut sender, &mut receiver); + join(run_fut, class_fut).await; } } + async fn run_logger_class<'d, D>(&self, sender: &mut Sender<'d, D>, receiver: &mut Receiver<'d, D>) + where + D: Driver<'d>, + { + let log_fut = async { + let mut rx: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; + sender.wait_connection().await; + loop { + let len = self.buffer.read(&mut rx[..]).await; + let _ = sender.write_packet(&rx[..len]).await; + if len as u8 == MAX_PACKET_SIZE { + let _ = sender.write_packet(&[]).await; + } + } + }; + let discard_fut = async { + let mut discard_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; + receiver.wait_connection().await; + loop { + let _ = receiver.read_packet(&mut discard_buf).await; + } + }; + + join(log_fut, discard_fut).await; + } + /// Creates the futures needed for the logger from a given class /// This can be used in cases where the usb device is already in use for another connection pub async fn create_future_from_class<'d, D>(&'d self, class: CdcAcmClass<'d, D>) where D: Driver<'d>, { - const MAX_PACKET_SIZE: u8 = 64; let (mut sender, mut receiver) = class.split(); - loop { - let log_fut = async { - let mut rx: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; - sender.wait_connection().await; - loop { - let len = self.buffer.read(&mut rx[..]).await; - let _ = sender.write_packet(&rx[..len]).await; - if len as u8 == MAX_PACKET_SIZE { - let _ = sender.write_packet(&[]).await; - } - } - }; - let discard_fut = async { - let mut discard_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; - receiver.wait_connection().await; - loop { - let _ = receiver.read_packet(&mut discard_buf).await; - } - }; - join(log_fut, discard_fut).await; + self.run_logger_class(&mut sender, &mut receiver).await; } } } From affaf2be1f7e351312e3e34e32c6707b43a23843 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Feb 2024 20:50:06 +0100 Subject: [PATCH 441/760] net: enable dhcpv4-hostname feature in docs. --- embassy-net/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 44bd2e8f3..be9f1d784 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"] +features = ["defmt", "tcp", "udp", "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"] +features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] [features] default = [] From 937a9e7955210b5e5467ba4e049d4fa86ec0c42b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Feb 2024 20:58:04 +0100 Subject: [PATCH 442/760] stm32/rcc: use h7 sdlevel enum from pac. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/rcc/h.rs | 27 ++++++--------------------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 24af17327..cc76408f3 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-8ae5bb5fe696a7e61fb41b8b797372aed8103a82" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8a3ad0b738292ae40af201d79b28db60fe876e11" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-8ae5bb5fe696a7e61fb41b8b797372aed8103a82", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8a3ad0b738292ae40af201d79b28db60fe876e11", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 474c44115..c2a71eaf1 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -170,22 +170,7 @@ pub enum SupplyConfig { /// This is only used in certain power supply configurations: /// SMPSLDO, SMPSExternalLDO, SMPSExternalLDOBypass. #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] -#[derive(PartialEq)] -pub enum SMPSSupplyVoltage { - V1_8, - V2_5, -} - -#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] -impl SMPSSupplyVoltage { - /// Convert SMPSSupplyVoltage to u8 representation. - fn to_u8(&self) -> u8 { - match self { - SMPSSupplyVoltage::V1_8 => 0b01, - SMPSSupplyVoltage::V2_5 => 0b10, - } - } -} +pub use pac::pwr::vals::Sdlevel as SMPSSupplyVoltage; /// Configuration of the core clocks #[non_exhaustive] @@ -279,7 +264,7 @@ pub(crate) unsafe fn init(config: Config) { match config.supply_config { SupplyConfig::Default => { PWR.cr3().modify(|w| { - w.set_sdlevel(0b00); + w.set_sdlevel(SMPSSupplyVoltage::RESET); w.set_sdexthp(false); w.set_sden(true); w.set_ldoen(true); @@ -301,11 +286,11 @@ pub(crate) unsafe fn init(config: Config) { w.set_bypass(false); }); } - SupplyConfig::SMPSLDO(ref smps_supply_voltage) - | SupplyConfig::SMPSExternalLDO(ref smps_supply_voltage) - | SupplyConfig::SMPSExternalLDOBypass(ref smps_supply_voltage) => { + SupplyConfig::SMPSLDO(smps_supply_voltage) + | SupplyConfig::SMPSExternalLDO(smps_supply_voltage) + | SupplyConfig::SMPSExternalLDOBypass(smps_supply_voltage) => { PWR.cr3().modify(|w| { - w.set_sdlevel(smps_supply_voltage.to_u8()); + w.set_sdlevel(smps_supply_voltage); w.set_sdexthp(matches!( config.supply_config, SupplyConfig::SMPSExternalLDO(_) | SupplyConfig::SMPSExternalLDOBypass(_) From 6e24f0562d4dc3aae66d7fa16366e7b7a5aabcb9 Mon Sep 17 00:00:00 2001 From: Nils Bars Date: Mon, 12 Feb 2024 21:18:50 +0100 Subject: [PATCH 443/760] Print panics via defmt per default for the stm32f0 example --- examples/stm32f0/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 71b0eb683..c74980dc4 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -13,7 +13,7 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" defmt = "0.3" defmt-rtt = "0.4" -panic-probe = "0.3" +panic-probe = { version = "0.3", features = ["print-defmt"] } 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", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } From 56e6b6bee6bd6087b35857e8aa1a011f6e83f703 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Mon, 12 Feb 2024 23:24:21 +0100 Subject: [PATCH 444/760] refactor(boot): move page erase index out of state --- embassy-boot/src/firmware_updater/asynch.rs | 14 +++++--------- embassy-boot/src/firmware_updater/blocking.rs | 14 +++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index d31eff005..b76668136 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -13,6 +13,7 @@ use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERA pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { dfu: DFU, state: FirmwareState<'d, STATE>, + last_erased_dfu_page_index: Option, } #[cfg(target_os = "none")] @@ -56,6 +57,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { Self { dfu: config.dfu, state: FirmwareState::new(config.state, aligned), + last_erased_dfu_page_index: None, } } @@ -72,7 +74,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { /// proceed with updating the firmware as it must be signed with a /// corresponding private key (otherwise it could be malicious firmware). /// - /// Mark to trigger firmware swap on next boot if verify suceeds. + /// Mark to trigger firmware swap on next boot if verify succeeds. /// /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have /// been generated from a SHA-512 digest of the firmware bytes. @@ -213,14 +215,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { let sector_end = sector_start + DFU::ERASE_SIZE; // Determine if the current sector needs to be erased before writing. let need_erase = self - .state .last_erased_dfu_page_index .map_or(true, |last_erased_sector| current_sector != last_erased_sector); // If the sector needs to be erased, erase it and update the last erased sector index. if need_erase { self.dfu.erase(sector_start as u32, sector_end as u32).await?; - self.state.last_erased_dfu_page_index = Some(current_sector); + self.last_erased_dfu_page_index = Some(current_sector); } // Calculate the size of the data chunk that can be written in the current iteration. @@ -258,7 +259,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { pub struct FirmwareState<'d, STATE> { state: STATE, aligned: &'d mut [u8], - last_erased_dfu_page_index: Option, } impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { @@ -280,11 +280,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { /// and follow the alignment rules for the flash being read from and written to. pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { assert_eq!(aligned.len(), STATE::WRITE_SIZE.max(STATE::READ_SIZE)); - Self { - state, - aligned, - last_erased_dfu_page_index: None, - } + Self { state, aligned } } // Make sure we are running a booted firmware to avoid reverting to a bad state. diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 5b8076f81..eb96a9523 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -13,6 +13,7 @@ use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERA pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { dfu: DFU, state: BlockingFirmwareState<'d, STATE>, + last_erased_dfu_page_index: Option, } #[cfg(target_os = "none")] @@ -91,6 +92,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> Self { dfu: config.dfu, state: BlockingFirmwareState::new(config.state, aligned), + last_erased_dfu_page_index: None, } } @@ -107,7 +109,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> /// proceed with updating the firmware as it must be signed with a /// corresponding private key (otherwise it could be malicious firmware). /// - /// Mark to trigger firmware swap on next boot if verify suceeds. + /// Mark to trigger firmware swap on next boot if verify succeeds. /// /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have /// been generated from a SHA-512 digest of the firmware bytes. @@ -248,14 +250,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> let sector_end = sector_start + DFU::ERASE_SIZE; // Determine if the current sector needs to be erased before writing. let need_erase = self - .state .last_erased_dfu_page_index .map_or(true, |last_erased_sector| current_sector != last_erased_sector); // If the sector needs to be erased, erase it and update the last erased sector index. if need_erase { self.dfu.erase(sector_start as u32, sector_end as u32)?; - self.state.last_erased_dfu_page_index = Some(current_sector); + self.last_erased_dfu_page_index = Some(current_sector); } // Calculate the size of the data chunk that can be written in the current iteration. @@ -293,7 +294,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> pub struct BlockingFirmwareState<'d, STATE> { state: STATE, aligned: &'d mut [u8], - last_erased_dfu_page_index: Option, } impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { @@ -315,11 +315,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { /// and written to. pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { assert_eq!(aligned.len(), STATE::WRITE_SIZE); - Self { - state, - aligned, - last_erased_dfu_page_index: None, - } + Self { state, aligned } } // Make sure we are running a booted firmware to avoid reverting to a bad state. From 7dd974aa0dd88ad319971b81083f63a190d278bf Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Mon, 12 Feb 2024 23:28:04 +0100 Subject: [PATCH 445/760] refactor(boot): use sector instead of page for consistency --- embassy-boot/src/firmware_updater/asynch.rs | 16 ++++++++-------- embassy-boot/src/firmware_updater/blocking.rs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index b76668136..3d211be65 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -13,7 +13,7 @@ use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERA pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { dfu: DFU, state: FirmwareState<'d, STATE>, - last_erased_dfu_page_index: Option, + last_erased_dfu_sector_index: Option, } #[cfg(target_os = "none")] @@ -57,7 +57,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { Self { dfu: config.dfu, state: FirmwareState::new(config.state, aligned), - last_erased_dfu_page_index: None, + last_erased_dfu_sector_index: None, } } @@ -180,7 +180,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { /// It handles sector erasures and data writes while verifying the device is in a proper state /// for firmware updates. The function ensures that only unerased sectors are erased before /// writing and efficiently handles the writing process across sector boundaries and in - /// various configurations (data size, page size, etc.). + /// various configurations (data size, sector size, etc.). /// /// # Arguments /// @@ -215,13 +215,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { let sector_end = sector_start + DFU::ERASE_SIZE; // Determine if the current sector needs to be erased before writing. let need_erase = self - .last_erased_dfu_page_index + .last_erased_dfu_sector_index .map_or(true, |last_erased_sector| current_sector != last_erased_sector); // If the sector needs to be erased, erase it and update the last erased sector index. if need_erase { self.dfu.erase(sector_start as u32, sector_end as u32).await?; - self.last_erased_dfu_page_index = Some(current_sector); + self.last_erased_dfu_sector_index = Some(current_sector); } // Calculate the size of the data chunk that can be written in the current iteration. @@ -380,7 +380,7 @@ mod tests { } #[test] - fn can_verify_sha1_page_bigger_than_chunk() { + fn can_verify_sha1_sector_bigger_than_chunk() { let flash = Mutex::::new(MemFlash::<131072, 4096, 8>::default()); let state = Partition::new(&flash, 0, 4096); let dfu = Partition::new(&flash, 65536, 65536); @@ -404,7 +404,7 @@ mod tests { } #[test] - fn can_verify_sha1_page_smaller_than_chunk() { + fn can_verify_sha1_sector_smaller_than_chunk() { let flash = Mutex::::new(MemFlash::<131072, 1024, 8>::default()); let state = Partition::new(&flash, 0, 4096); let dfu = Partition::new(&flash, 65536, 65536); @@ -428,7 +428,7 @@ mod tests { } #[test] - fn can_verify_sha1_cross_page_boundary() { + fn can_verify_sha1_cross_sector_boundary() { let flash = Mutex::::new(MemFlash::<131072, 1024, 8>::default()); let state = Partition::new(&flash, 0, 4096); let dfu = Partition::new(&flash, 65536, 65536); diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index eb96a9523..35772a856 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -13,7 +13,7 @@ use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERA pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { dfu: DFU, state: BlockingFirmwareState<'d, STATE>, - last_erased_dfu_page_index: Option, + last_erased_dfu_sector_index: Option, } #[cfg(target_os = "none")] @@ -92,7 +92,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> Self { dfu: config.dfu, state: BlockingFirmwareState::new(config.state, aligned), - last_erased_dfu_page_index: None, + last_erased_dfu_sector_index: None, } } @@ -215,7 +215,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> /// It handles sector erasures and data writes while verifying the device is in a proper state /// for firmware updates. The function ensures that only unerased sectors are erased before /// writing and efficiently handles the writing process across sector boundaries and in - /// various configurations (data size, page size, etc.). + /// various configurations (data size, sector size, etc.). /// /// # Arguments /// @@ -250,13 +250,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> let sector_end = sector_start + DFU::ERASE_SIZE; // Determine if the current sector needs to be erased before writing. let need_erase = self - .last_erased_dfu_page_index + .last_erased_dfu_sector_index .map_or(true, |last_erased_sector| current_sector != last_erased_sector); // If the sector needs to be erased, erase it and update the last erased sector index. if need_erase { self.dfu.erase(sector_start as u32, sector_end as u32)?; - self.last_erased_dfu_page_index = Some(current_sector); + self.last_erased_dfu_sector_index = Some(current_sector); } // Calculate the size of the data chunk that can be written in the current iteration. @@ -420,7 +420,7 @@ mod tests { } #[test] - fn can_verify_sha1_page_bigger_than_chunk() { + fn can_verify_sha1_sector_bigger_than_chunk() { let flash = Mutex::::new(RefCell::new(MemFlash::<131072, 4096, 8>::default())); let state = BlockingPartition::new(&flash, 0, 4096); let dfu = BlockingPartition::new(&flash, 65536, 65536); @@ -446,7 +446,7 @@ mod tests { } #[test] - fn can_verify_sha1_page_smaller_than_chunk() { + fn can_verify_sha1_sector_smaller_than_chunk() { let flash = Mutex::::new(RefCell::new(MemFlash::<131072, 1024, 8>::default())); let state = BlockingPartition::new(&flash, 0, 4096); let dfu = BlockingPartition::new(&flash, 65536, 65536); @@ -472,7 +472,7 @@ mod tests { } #[test] - fn can_verify_sha1_cross_page_boundary() { + fn can_verify_sha1_cross_sector_boundary() { let flash = Mutex::::new(RefCell::new(MemFlash::<131072, 1024, 8>::default())); let state = BlockingPartition::new(&flash, 0, 4096); let dfu = BlockingPartition::new(&flash, 65536, 65536); From 739c69bd637baf471585648db4d253089301d6c8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Feb 2024 00:58:18 +0100 Subject: [PATCH 446/760] stm32/rcc: some f3 fixes. --- embassy-stm32/src/rcc/f3.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 0a5e67b4a..580aa389f 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -222,8 +222,8 @@ pub(crate) unsafe fn init(config: Config) { // Set prescalers // CFGR has been written before (PLL, PLL48) don't overwrite these settings RCC.cfgr().modify(|w| { - w.set_ppre2(config.apb1_pre); - w.set_ppre1(config.apb2_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); w.set_hpre(config.ahb_pre); }); @@ -234,6 +234,7 @@ pub(crate) unsafe fn init(config: Config) { // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings RCC.cfgr().modify(|w| w.set_sw(config.sys)); + while RCC.cfgr().read().sws() != config.sys {} let rtc = config.ls.init(); From b7c147445a98ced9557ca6c0950f6083d0cf09af Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Feb 2024 21:54:53 +0100 Subject: [PATCH 447/760] stm32/rcc: port F1 to new API. --- embassy-stm32/src/rcc/f1.rs | 390 +++++++++++++++---------- examples/stm32f1/src/bin/hello.rs | 4 +- examples/stm32f1/src/bin/usb_serial.rs | 20 +- tests/stm32/.cargo/config.toml | 4 +- tests/stm32/src/common.rs | 18 ++ 5 files changed, 266 insertions(+), 170 deletions(-) diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index 7f0adab27..9fdd4c11c 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -1,191 +1,257 @@ -use core::convert::TryFrom; - use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::*; +use crate::pac::rcc::vals::Pllsrc; +#[cfg(any(rcc_f1, rcc_f1cl))] +use crate::pac::rcc::vals::Usbpre; +pub use crate::pac::rcc::vals::{ + Adcpre as ADCPrescaler, Hpre as AHBPrescaler, Pllmul as PllMul, Pllxtpre as PllPreDiv, Ppre as APBPrescaler, + Sw as Sysclk, +}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(8_000_000); -/// Configuration of the clocks -/// -#[non_exhaustive] -#[derive(Default)] -pub struct Config { - pub hse: Option, +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1) + Bypass, +} - pub sys_ck: Option, - pub hclk: Option, - pub pclk1: Option, - pub pclk2: Option, - pub adcclk: Option, - pub pllxtpre: bool, +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum PllSource { + HSE, + HSI, +} + +#[derive(Clone, Copy)] +pub struct Pll { + pub src: PllSource, + + /// PLL pre-divider. + /// + /// On some F3 chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. + pub prediv: PllPreDiv, + + /// PLL multiplication factor. + pub mul: PllMul, +} + +/// Clocks configutation +#[non_exhaustive] +pub struct Config { + pub hsi: bool, + pub hse: Option, + pub sys: Sysclk, + + pub pll: Option, + + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + pub apb2_pre: APBPrescaler, + + pub adc_pre: ADCPrescaler, pub ls: super::LsConfig, } -pub(crate) unsafe fn init(config: Config) { - let pllxtpre_div = if config.pllxtpre { 2 } else { 1 }; - let pllsrcclk = config.hse.map(|hse| hse.0 / pllxtpre_div).unwrap_or(HSI_FREQ.0 / 2); +impl Default for Config { + fn default() -> Self { + Self { + hsi: true, + hse: None, + sys: Sysclk::HSI, + pll: None, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + ls: Default::default(), - let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); - let pllmul = sysclk / pllsrcclk; - - let (pllmul_bits, real_sysclk) = if pllmul == 1 { - (None, config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0)) - } else { - let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); - (Some(pllmul as u8 - 2), pllsrcclk * pllmul) - }; - - assert!(real_sysclk <= 72_000_000); - - let hpre_bits = config - .hclk - .map(|hclk| match real_sysclk / hclk.0 { - 0 => unreachable!(), - 1 => 0b0111, - 2 => 0b1000, - 3..=5 => 0b1001, - 6..=11 => 0b1010, - 12..=39 => 0b1011, - 40..=95 => 0b1100, - 96..=191 => 0b1101, - 192..=383 => 0b1110, - _ => 0b1111, - }) - .unwrap_or(0b0111); - - let hclk = if hpre_bits >= 0b1100 { - real_sysclk / (1 << (hpre_bits - 0b0110)) - } else { - real_sysclk / (1 << (hpre_bits - 0b0111)) - }; - - assert!(hclk <= 72_000_000); - - let ppre1_bits = config - .pclk1 - .map(|pclk1| match hclk / pclk1.0 { - 0 => unreachable!(), - 1 => 0b011, - 2 => 0b100, - 3..=5 => 0b101, - 6..=11 => 0b110, - _ => 0b111, - }) - .unwrap_or(0b011); - - let ppre1 = 1 << (ppre1_bits - 0b011); - let pclk1 = hclk / u32::try_from(ppre1).unwrap(); - let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; - - assert!(pclk1 <= 36_000_000); - - let ppre2_bits = config - .pclk2 - .map(|pclk2| match hclk / pclk2.0 { - 0 => unreachable!(), - 1 => 0b011, - 2 => 0b100, - 3..=5 => 0b101, - 6..=11 => 0b110, - _ => 0b111, - }) - .unwrap_or(0b011); - - let ppre2 = 1 << (ppre2_bits - 0b011); - let pclk2 = hclk / u32::try_from(ppre2).unwrap(); - let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; - - assert!(pclk2 <= 72_000_000); - - FLASH.acr().write(|w| { - w.set_latency(if real_sysclk <= 24_000_000 { - Latency::WS0 - } else if real_sysclk <= 48_000_000 { - Latency::WS1 - } else { - Latency::WS2 - }); - // the prefetch buffer is enabled by default, let's keep it enabled - w.set_prftbe(true); - }); - - // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the - // PLL output frequency is a supported one. - // usbpre == false: divide clock by 1.5, otherwise no division - #[cfg(not(rcc_f100))] - let (usbpre, _usbclk_valid) = match (config.hse, pllmul_bits, real_sysclk) { - (Some(_), Some(_), 72_000_000) => (false, true), - (Some(_), Some(_), 48_000_000) => (true, true), - _ => (true, false), - }; - - let apre_bits: u8 = config - .adcclk - .map(|adcclk| match pclk2 / adcclk.0 { - 0..=2 => 0b00, - 3..=4 => 0b01, - 5..=7 => 0b10, - _ => 0b11, - }) - .unwrap_or(0b11); - - let apre = (apre_bits + 1) << 1; - let adcclk = pclk2 / unwrap!(u32::try_from(apre)); - - assert!(adcclk <= 14_000_000); - - if config.hse.is_some() { - // enable HSE and wait for it to be ready - RCC.cr().modify(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} + // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz) + adc_pre: ADCPrescaler::DIV6, + } } +} - if let Some(pllmul_bits) = pllmul_bits { - let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 }; - RCC.cfgr() - .modify(|w| w.set_pllxtpre(Pllxtpre::from_bits(pllctpre_flag))); +/// Initialize and Set the clock frequencies +pub(crate) unsafe fn init(config: Config) { + // Configure HSI + let hsi = match config.hsi { + false => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + true => { + RCC.cr().modify(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + Some(HSI_FREQ) + } + }; + + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } + + RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } + }; + + // Enable PLL + let pll = config.pll.map(|pll| { + let (src_val, src_freq) = match pll.src { + PllSource::HSI => { + if pll.prediv != PllPreDiv::DIV2 { + panic!("if PLL source is HSI, PLL prediv must be 2."); + } + (Pllsrc::HSI_DIV2, unwrap!(hsi)) + } + PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), + }; + let in_freq = src_freq / pll.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let out_freq = in_freq * pll.mul; + assert!(max::PLL_OUT.contains(&out_freq)); - // enable PLL and wait for it to be ready RCC.cfgr().modify(|w| { - w.set_pllmul(Pllmul::from_bits(pllmul_bits)); - w.set_pllsrc(Pllsrc::from_bits(config.hse.is_some() as u8)); + w.set_pllmul(pll.mul); + w.set_pllsrc(src_val); + w.set_pllxtpre(pll.prediv); }); - RCC.cr().modify(|w| w.set_pllon(true)); while !RCC.cr().read().pllrdy() {} - } - // Only needed for stm32f103? - RCC.cfgr().modify(|w| { - w.set_adcpre(Adcpre::from_bits(apre_bits)); - w.set_ppre2(Ppre::from_bits(ppre2_bits)); - w.set_ppre1(Ppre::from_bits(ppre1_bits)); - w.set_hpre(Hpre::from_bits(hpre_bits)); - #[cfg(not(rcc_f100))] - w.set_usbpre(Usbpre::from_bits(usbpre as u8)); - w.set_sw(if pllmul_bits.is_some() { - Sw::PLL1_P - } else if config.hse.is_some() { - Sw::HSE - } else { - Sw::HSI - }); + out_freq }); + #[cfg(any(rcc_f1, rcc_f1cl))] + let usb = match pll { + Some(Hertz(72_000_000)) => { + RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1_5)); + Some(Hertz(48_000_000)) + } + Some(Hertz(48_000_000)) => { + RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1)); + Some(Hertz(48_000_000)) + } + _ => None, + }; + + // Configure sysclk + let sys = match config.sys { + Sysclk::HSI => unwrap!(hsi), + Sysclk::HSE => unwrap!(hse), + Sysclk::PLL1_P => unwrap!(pll), + _ => unreachable!(), + }; + + let hclk = sys / config.ahb_pre; + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); + + assert!(max::HCLK.contains(&hclk)); + assert!(max::PCLK1.contains(&pclk1)); + assert!(max::PCLK2.contains(&pclk2)); + + let adc = pclk2 / config.adc_pre; + assert!(max::ADC.contains(&adc)); + + // Set latency based on HCLK frquency + let latency = match hclk.0 { + ..=24_000_000 => Latency::WS0, + ..=48_000_000 => Latency::WS1, + _ => Latency::WS2, + }; + FLASH.acr().modify(|w| { + w.set_latency(latency); + // RM0316: "The prefetch buffer must be kept on when using a prescaler + // different from 1 on the AHB clock.", "Half-cycle access cannot be + // used when there is a prescaler different from 1 on the AHB clock" + if config.ahb_pre != AHBPrescaler::DIV1 { + w.set_hlfcya(false); + w.set_prftbe(true); + } + }); + + // Set prescalers + // CFGR has been written before (PLL, PLL48) don't overwrite these settings + RCC.cfgr().modify(|w| { + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); + w.set_hpre(config.ahb_pre); + w.set_adcpre(config.adc_pre); + }); + + // Wait for the new prescalers to kick in + // "The clocks are divided with the new prescaler factor from + // 1 to 16 AHB cycles after write" + cortex_m::asm::delay(16); + + // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings + RCC.cfgr().modify(|w| w.set_sw(config.sys)); + while RCC.cfgr().read().sws() != config.sys {} + let rtc = config.ls.init(); set_clocks!( - sys: Some(Hertz(real_sysclk)), - pclk1: Some(Hertz(pclk1)), - pclk2: Some(Hertz(pclk2)), - pclk1_tim: Some(Hertz(pclk1 * timer_mul1)), - pclk2_tim: Some(Hertz(pclk2 * timer_mul2)), - hclk1: Some(Hertz(hclk)), - adc: Some(Hertz(adcclk)), + hsi: hsi, + hse: hse, + pll1_p: pll, + sys: Some(sys), + pclk1: Some(pclk1), + pclk2: Some(pclk2), + pclk1_tim: Some(pclk1_tim), + pclk2_tim: Some(pclk2_tim), + hclk1: Some(hclk), + adc: Some(adc), rtc: rtc, + #[cfg(any(rcc_f1, rcc_f1cl))] + usb: usb, + lse: None, ); } + +mod max { + use core::ops::RangeInclusive; + + use crate::time::Hertz; + + #[cfg(not(rcc_f1cl))] + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(16_000_000); + #[cfg(not(rcc_f1cl))] + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(25_000_000); + + #[cfg(rcc_f1cl)] + pub(crate) const HSE_OSC: RangeInclusive = Hertz(3_000_000)..=Hertz(25_000_000); + #[cfg(rcc_f1cl)] + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(50_000_000); + + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(72_000_000); + pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(36_000_000); + pub(crate) const PCLK2: RangeInclusive = Hertz(0)..=Hertz(72_000_000); + + pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(25_000_000); + pub(crate) const PLL_OUT: RangeInclusive = Hertz(16_000_000)..=Hertz(72_000_000); + + pub(crate) const ADC: RangeInclusive = Hertz(0)..=Hertz(14_000_000); +} diff --git a/examples/stm32f1/src/bin/hello.rs b/examples/stm32f1/src/bin/hello.rs index 7b761ecc1..3c295612c 100644 --- a/examples/stm32f1/src/bin/hello.rs +++ b/examples/stm32f1/src/bin/hello.rs @@ -3,15 +3,13 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::time::Hertz; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { - let mut config = Config::default(); - config.rcc.sys_ck = Some(Hertz(36_000_000)); + let config = Config::default(); let _p = embassy_stm32::init(config); loop { diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index e28381893..1ae6c1dee 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs @@ -21,9 +21,23 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.hse = Some(Hertz(8_000_000)); - config.rcc.sys_ck = Some(Hertz(48_000_000)); - config.rcc.pclk1 = Some(Hertz(24_000_000)); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + // Oscillator for bluepill, Bypass for nucleos. + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + } let mut p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml index 8e32b4cee..528bd3451 100644 --- a/tests/stm32/.cargo/config.toml +++ b/tests/stm32/.cargo/config.toml @@ -14,9 +14,9 @@ rustflags = [ ] [build] -target = "thumbv6m-none-eabi" +#target = "thumbv6m-none-eabi" #target = "thumbv7m-none-eabi" -#target = "thumbv7em-none-eabi" +target = "thumbv7em-none-eabi" #target = "thumbv8m.main-none-eabihf" [env] diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 36fe8a235..182ad6298 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -247,6 +247,24 @@ pub fn config() -> Config { config.rcc = embassy_stm32::rcc::WPAN_DEFAULT; } + #[cfg(feature = "stm32f103c8")] + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + } + #[cfg(feature = "stm32f207zg")] { use embassy_stm32::rcc::*; From ccd2c574c37d26d09f67d6410d79e7e3e16e6119 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Feb 2024 01:15:20 +0100 Subject: [PATCH 448/760] stm32/rcc: port F0 to new API. --- ci.sh | 7 + embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/f0.rs | 338 +++++++++++++++++++---------------- embassy-stm32/src/rcc/mco.rs | 6 +- embassy-stm32/src/rcc/mod.rs | 16 +- 5 files changed, 207 insertions(+), 164 deletions(-) diff --git a/ci.sh b/ci.sh index 58a288441..7ecca92af 100755 --- a/ci.sh +++ b/ci.sh @@ -88,6 +88,13 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f030r8,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f031k6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f030rc,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f070f6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f078vb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f042g4,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f072c8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index cc76408f3..4c27164ce 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-8a3ad0b738292ae40af201d79b28db60fe876e11" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7734584b2007766b1c5a6a7f2654fdb442fa211a" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-8a3ad0b738292ae40af201d79b28db60fe876e11", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7734584b2007766b1c5a6a7f2654fdb442fa211a", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index 1042a1cb2..d6f995e45 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs @@ -1,27 +1,64 @@ -use stm32_metapac::flash::vals::Latency; - -use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; +use crate::pac::flash::vals::Latency; +use crate::pac::rcc::vals::Pllsrc; +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Prediv as PllPreDiv, Sw as Sysclk, +}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(8_000_000); -/// Configuration of the clocks -/// -/// hse takes precedence over hsi48 if both are enabled +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1) + Bypass, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum PllSource { + HSE, + HSI, + #[cfg(rcc_f0v4)] + HSI48, +} + +#[derive(Clone, Copy)] +pub struct Pll { + pub src: PllSource, + + /// PLL pre-divider. + /// + /// On some chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. + pub prediv: PllPreDiv, + + /// PLL multiplication factor. + pub mul: PllMul, +} + +/// Clocks configutation #[non_exhaustive] pub struct Config { - pub hse: Option, - pub bypass_hse: bool, - pub usb_pll: bool, - + pub hsi: bool, + pub hse: Option, #[cfg(crs)] pub hsi48: Option, + pub sys: Sysclk, - pub sys_ck: Option, - pub hclk: Option, - pub pclk: Option, + pub pll: Option, + + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, pub ls: super::LsConfig, } @@ -29,168 +66,167 @@ pub struct Config { impl Default for Config { fn default() -> Self { Self { - hse: Default::default(), - bypass_hse: Default::default(), - usb_pll: Default::default(), + hsi: true, + hse: None, #[cfg(crs)] hsi48: Some(Default::default()), - sys_ck: Default::default(), - hclk: Default::default(), - pclk: Default::default(), + sys: Sysclk::HSI, + pll: None, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, ls: Default::default(), } } } +/// Initialize and Set the clock frequencies pub(crate) unsafe fn init(config: Config) { - let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI_FREQ.0); + // Configure HSI + let hsi = match config.hsi { + false => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + true => { + RCC.cr().modify(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + Some(HSI_FREQ) + } + }; + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } + + RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } + }; + + // configure HSI48 #[cfg(crs)] let hsi48 = config.hsi48.map(|config| super::init_hsi48(config)); #[cfg(not(crs))] let hsi48: Option = None; - let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| { - if hsi48.is_some() { - return (48_000_000, true); - } - (HSI_FREQ.0, false) - }); + // Enable PLL + let pll = config.pll.map(|pll| { + let (src_val, src_freq) = match pll.src { + #[cfg(not(any(rcc_f0v1, rcc_f0v2)))] + PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)), + #[cfg(any(rcc_f0v1, rcc_f0v2))] + PllSource::HSI => { + if pll.prediv != PllPreDiv::DIV2 { + panic!("if PLL source is HSI, PLL prediv must be 2."); + } + (Pllsrc::HSI_DIV2, unwrap!(hsi)) + } + PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), + #[cfg(rcc_f0v4)] + PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), + }; + let in_freq = src_freq / pll.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let out_freq = in_freq * pll.mul; + assert!(max::PLL_OUT.contains(&out_freq)); - let (pllmul_bits, real_sysclk) = if sysclk == src_clk { - (None, sysclk) - } else { - let prediv = if config.hse.is_some() { 1 } else { 2 }; - let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2; - let pllmul = pllmul.max(2).min(16); - - let pllmul_bits = pllmul as u8 - 2; - let real_sysclk = pllmul * src_clk / prediv; - (Some(pllmul_bits), real_sysclk) - }; - - let hpre_bits = config - .hclk - .map(|hclk| match real_sysclk / hclk.0 { - 0 => unreachable!(), - 1 => 0b0111, - 2 => 0b1000, - 3..=5 => 0b1001, - 6..=11 => 0b1010, - 12..=39 => 0b1011, - 40..=95 => 0b1100, - 96..=191 => 0b1101, - 192..=383 => 0b1110, - _ => 0b1111, - }) - .unwrap_or(0b0111); - let hclk = real_sysclk / (1 << (hpre_bits - 0b0111)); - - let ppre_bits = config - .pclk - .map(|pclk| match hclk / pclk.0 { - 0 => unreachable!(), - 1 => 0b011, - 2 => 0b100, - 3..=5 => 0b101, - 6..=11 => 0b110, - _ => 0b111, - }) - .unwrap_or(0b011); - - let ppre: u8 = 1 << (ppre_bits - 0b011); - let pclk = hclk / u32::from(ppre); - - let timer_mul = if ppre == 1 { 1 } else { 2 }; - - FLASH.acr().write(|w| { - w.set_latency(if real_sysclk <= 24_000_000 { - Latency::WS0 - } else { - Latency::WS1 + RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); + RCC.cfgr().modify(|w| { + w.set_pllmul(pll.mul); + w.set_pllsrc(src_val); }); - }); - - match (config.hse.is_some(), use_hsi48) { - (true, _) => { - RCC.cr().modify(|w| { - w.set_csson(true); - w.set_hseon(true); - w.set_hsebyp(config.bypass_hse); - }); - while !RCC.cr().read().hserdy() {} - - if pllmul_bits.is_some() { - RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV)) - } - } - // use_hsi48 will always be false for stm32f0x0 - #[cfg(not(stm32f0x0))] - (false, true) => { - RCC.cr2().modify(|w| w.set_hsi48on(true)); - while !RCC.cr2().read().hsi48rdy() {} - - if pllmul_bits.is_some() { - RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV)) - } - } - _ => { - RCC.cr().modify(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - - if pllmul_bits.is_some() { - RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2)) - } - } - } - - if config.usb_pll { - RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLL1_P)); - } - // TODO: Option to use CRS (Clock Recovery) - - if let Some(pllmul_bits) = pllmul_bits { - RCC.cfgr().modify(|w| w.set_pllmul(Pllmul::from_bits(pllmul_bits))); - RCC.cr().modify(|w| w.set_pllon(true)); while !RCC.cr().read().pllrdy() {} - RCC.cfgr().modify(|w| { - w.set_ppre(Ppre::from_bits(ppre_bits)); - w.set_hpre(Hpre::from_bits(hpre_bits)); - w.set_sw(Sw::PLL1_P) - }); - } else { - RCC.cfgr().modify(|w| { - w.set_ppre(Ppre::from_bits(ppre_bits)); - w.set_hpre(Hpre::from_bits(hpre_bits)); + out_freq + }); - if config.hse.is_some() { - w.set_sw(Sw::HSE); - } else if use_hsi48 { - #[cfg(not(stm32f0x0))] - w.set_sw(Sw::HSI48); - } else { - w.set_sw(Sw::HSI) - } - }) - } + // Configure sysclk + let sys = match config.sys { + Sysclk::HSI => unwrap!(hsi), + Sysclk::HSE => unwrap!(hse), + Sysclk::PLL1_P => unwrap!(pll), + #[cfg(rcc_f0v4)] + Sysclk::HSI48 => unwrap!(hsi48), + #[allow(unreachable_patterns)] + _ => unreachable!(), + }; + + let hclk = sys / config.ahb_pre; + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + + assert!(max::HCLK.contains(&hclk)); + assert!(max::PCLK1.contains(&pclk1)); + + // Set latency based on HCLK frquency + let latency = match hclk.0 { + ..=24_000_000 => Latency::WS0, + _ => Latency::WS1, + }; + FLASH.acr().modify(|w| { + w.set_latency(latency); + w.set_prftbe(true); + }); + + // Set prescalers + // CFGR has been written before (PLL, PLL48) don't overwrite these settings + RCC.cfgr().modify(|w| { + w.set_ppre(config.apb1_pre); + w.set_hpre(config.ahb_pre); + }); + + // Wait for the new prescalers to kick in + // "The clocks are divided with the new prescaler factor from + // 1 to 16 AHB cycles after write" + cortex_m::asm::delay(16); + + // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings + RCC.cfgr().modify(|w| w.set_sw(config.sys)); + while RCC.cfgr().read().sws() != config.sys {} let rtc = config.ls.init(); set_clocks!( - hsi: None, - lse: None, - sys: Some(Hertz(real_sysclk)), - pclk1: Some(Hertz(pclk)), - pclk2: Some(Hertz(pclk)), - pclk1_tim: Some(Hertz(pclk * timer_mul)), - pclk2_tim: Some(Hertz(pclk * timer_mul)), - hclk1: Some(Hertz(hclk)), - rtc: rtc, + hsi: hsi, + hse: hse, + pll1_p: pll, + sys: Some(sys), + pclk1: Some(pclk1), + pclk2: Some(pclk1), + pclk1_tim: Some(pclk1_tim), + pclk2_tim: Some(pclk1_tim), + hclk1: Some(hclk), + #[cfg(all(not(rcc_f37), adc3_common))] + adc34: Some(adc34), + #[cfg(stm32f334)] + hrtim: hrtim, hsi48: hsi48, - - // TODO: - pll1_p: None, + rtc: rtc, + lse: None, ); } + +mod max { + use core::ops::RangeInclusive; + + use crate::time::Hertz; + + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(32_000_000); + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(32_000_000); + + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(48_000_000); + pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(48_000_000); + + pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(24_000_000); + pub(crate) const PLL_OUT: RangeInclusive = Hertz(16_000_000)..=Hertz(48_000_000); +} diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index db0df9fac..654943bc1 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -4,7 +4,7 @@ use embassy_hal_internal::into_ref; use crate::gpio::sealed::AFType; use crate::gpio::Speed; -#[cfg(not(any(stm32f1, rcc_f3v1, rcc_f37)))] +#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; #[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] pub use crate::pac::rcc::vals::Mcosel as McoSource; @@ -13,7 +13,7 @@ pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; use crate::pac::RCC; use crate::{peripherals, Peripheral}; -#[cfg(any(stm32f1, rcc_f3v1, rcc_f37))] +#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum McoPrescaler { DIV1, @@ -43,7 +43,7 @@ macro_rules! impl_peri { r.modify(|w| { w.$set_source(source); - #[cfg(not(any(stm32f1, rcc_f3v1, rcc_f37)))] + #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] w.$set_prescaler(_prescaler); }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 05937cc5d..b7eca0615 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -18,17 +18,17 @@ mod hsi48; #[cfg(crs)] pub use hsi48::*; -#[cfg_attr(rcc_f0, path = "f0.rs")] -#[cfg_attr(any(stm32f1), path = "f1.rs")] -#[cfg_attr(any(stm32f3), path = "f3.rs")] +#[cfg_attr(stm32f0, path = "f0.rs")] +#[cfg_attr(stm32f1, path = "f1.rs")] +#[cfg_attr(stm32f3, path = "f3.rs")] #[cfg_attr(any(stm32f2, stm32f4, stm32f7), path = "f.rs")] -#[cfg_attr(rcc_c0, path = "c0.rs")] -#[cfg_attr(rcc_g0, path = "g0.rs")] -#[cfg_attr(rcc_g4, path = "g4.rs")] +#[cfg_attr(stm32c0, path = "c0.rs")] +#[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(rcc_u5, path = "u5.rs")] -#[cfg_attr(rcc_wba, path = "wba.rs")] +#[cfg_attr(stm32u5, path = "u5.rs")] +#[cfg_attr(stm32wba, path = "wba.rs")] mod _version; pub use _version::*; From d8b4922b3ced8645a6225dcb0e8b873364bc8337 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:33:04 -0500 Subject: [PATCH 449/760] Add STM32 HMAC function. --- embassy-stm32/src/hash/mod.rs | 73 ++++++++++++++++++++++++++------ examples/stm32f7/src/bin/hash.rs | 2 +- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index f0c2c839a..bae538b5f 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -100,8 +100,9 @@ pub enum DataType { /// Stores the state of the HASH peripheral for suspending/resuming /// digest calculation. -pub struct Context { +pub struct Context<'c> { first_word_sent: bool, + key_sent: bool, buffer: [u8; HASH_BUFFER_LEN], buflen: usize, algo: Algorithm, @@ -110,8 +111,11 @@ pub struct Context { str: u32, cr: u32, csr: [u32; NUM_CONTEXT_REGS], + key: HmacKey<'c>, } +type HmacKey<'k> = Option<&'k [u8]>; + /// HASH driver. pub struct Hash<'d, T: Instance, D = NoDma> { _peripheral: PeripheralRef<'d, T>, @@ -140,10 +144,11 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { } /// Starts computation of a new hash and returns the saved peripheral state. - pub fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { + pub fn start<'c>(&mut self, algorithm: Algorithm, format: DataType, key: HmacKey<'c>) -> Context<'c> { // Define a context for this new computation. let mut ctx = Context { first_word_sent: false, + key_sent: false, buffer: [0; HASH_BUFFER_LEN], buflen: 0, algo: algorithm, @@ -152,6 +157,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { str: 0, cr: 0, csr: [0; NUM_CONTEXT_REGS], + key, }; // Set the data type in the peripheral. @@ -181,6 +187,14 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { #[cfg(any(hash_v3, hash_v4))] T::regs().cr().modify(|w| w.set_algo(ctx.algo as u8)); + // Configure HMAC mode if a key is provided. + if let Some(key) = ctx.key { + T::regs().cr().modify(|w| w.set_mode(true)); + if key.len() > 64 { + T::regs().cr().modify(|w| w.set_lkey(true)); + } + } + T::regs().cr().modify(|w| w.set_init(true)); // Store and return the state of the peripheral. @@ -191,18 +205,30 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { /// Restores the peripheral state using the given context, /// then updates the state with the provided data. /// Peripheral state is saved upon return. - pub fn update_blocking(&mut self, ctx: &mut Context, input: &[u8]) { + pub fn update_blocking<'c>(&mut self, ctx: &mut Context<'c>, input: &[u8]) { + // Restore the peripheral state. + self.load_context(&ctx); + + // Load the HMAC key if provided. + if !ctx.key_sent { + if let Some(key) = ctx.key { + self.accumulate_blocking(key); + T::regs().str().write(|w| w.set_dcal(true)); + // Block waiting for digest. + while !T::regs().sr().read().dcis() {} + } + ctx.key_sent = true; + } + let mut data_waiting = input.len() + ctx.buflen; if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) { // There isn't enough data to digest a block, so append it to the buffer. ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); ctx.buflen += input.len(); + self.store_context(ctx); return; } - // Restore the peripheral state. - self.load_context(&ctx); - let mut ilen_remaining = input.len(); let mut input_start = 0; @@ -261,21 +287,30 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { /// then updates the state with the provided data. /// Peripheral state is saved upon return. #[cfg(hash_v2)] - pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) + pub async fn update<'c>(&mut self, ctx: &mut Context<'c>, input: &[u8]) where D: crate::hash::Dma, { + // Restore the peripheral state. + self.load_context(&ctx); + + // Load the HMAC key if provided. + if !ctx.key_sent { + if let Some(key) = ctx.key { + self.accumulate(key).await; + } + ctx.key_sent = true; + } + let data_waiting = input.len() + ctx.buflen; if data_waiting < DIGEST_BLOCK_SIZE { // There isn't enough data to digest a block, so append it to the buffer. ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); ctx.buflen += input.len(); + self.store_context(ctx); return; } - // Restore the peripheral state. - self.load_context(&ctx); - // Enable multiple DMA transfers. T::regs().cr().modify(|w| w.set_mdmat(true)); @@ -319,7 +354,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. /// The largest returned digest size is 128 bytes for SHA-512. /// Panics if the supplied digest buffer is too short. - pub fn finish_blocking(&mut self, mut ctx: Context, digest: &mut [u8]) -> usize { + pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { // Restore the peripheral state. self.load_context(&ctx); @@ -333,6 +368,13 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { // Block waiting for digest. while !T::regs().sr().read().dcis() {} + // Load the HMAC key if provided. + if let Some(key) = ctx.key { + self.accumulate_blocking(key); + T::regs().str().write(|w| w.set_dcal(true)); + while !T::regs().sr().read().dcis() {} + } + // Return the digest. let digest_words = match ctx.algo { Algorithm::SHA1 => 5, @@ -370,7 +412,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { /// The largest returned digest size is 128 bytes for SHA-512. /// Panics if the supplied digest buffer is too short. #[cfg(hash_v2)] - pub async fn finish(&mut self, mut ctx: Context, digest: &mut [u8]) -> usize + pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize where D: crate::hash::Dma, { @@ -384,6 +426,11 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { self.accumulate(&ctx.buffer[0..ctx.buflen]).await; ctx.buflen = 0; + // Load the HMAC key if provided. + if let Some(key) = ctx.key { + self.accumulate(key).await; + } + // Wait for completion. poll_fn(|cx| { // Check if already done. @@ -484,7 +531,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { } /// Save the peripheral state to a context. - fn store_context(&mut self, ctx: &mut Context) { + fn store_context<'c>(&mut self, ctx: &mut Context<'c>) { // Block waiting for data in ready. while !T::regs().sr().read().dinis() {} diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index 96e50f84b..cbb880353 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -26,7 +26,7 @@ async fn main(_spawner: Spawner) -> ! { let hw_start_time = Instant::now(); // Compute a digest in hardware. - let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); + let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, None); hw_hasher.update(&mut context, test_1).await; hw_hasher.update(&mut context, test_2).await; let mut hw_digest: [u8; 32] = [0; 32]; From 37c869827e96fb17838f89a082f12c08f3177fff Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:33:04 -0500 Subject: [PATCH 450/760] Update STM32 hash test. --- tests/stm32/src/bin/hash.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index cfcf3d976..1b89f46e8 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -38,11 +38,11 @@ async fn main(_spawner: Spawner) { let test_3: &[u8] = b"a.ewtkluGWEBR.KAJRBTA,RMNRBG,FDMGB.kger.tkasjrbt.akrjtba.krjtba.ktmyna,nmbvtyliasd;gdrtba,sfvs.kgjzshd.gkbsr.tksejb.SDkfBSE.gkfgb>ESkfbSE>gkJSBESE>kbSE>fk"; // Start an SHA-256 digest. - let mut sha256context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); + let mut sha256context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, None); hw_hasher.update_blocking(&mut sha256context, test_1); // Interrupt the SHA-256 digest to compute an SHA-224 digest. - let mut sha224context = hw_hasher.start(Algorithm::SHA224, DataType::Width8); + let mut sha224context = hw_hasher.start(Algorithm::SHA224, DataType::Width8, None); hw_hasher.update_blocking(&mut sha224context, test_3); let mut sha224_digest_buffer: [u8; 28] = [0; 28]; let _ = hw_hasher.finish_blocking(sha224context, &mut sha224_digest_buffer); From f0f1f2d14c6cb82ee1a4f452bdece2f98479c39f Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:33:04 -0500 Subject: [PATCH 451/760] Added HMAC example. --- examples/stm32f7/Cargo.toml | 1 + examples/stm32f7/src/bin/hash.rs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index a612c2554..736e81723 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -29,6 +29,7 @@ critical-section = "1.1" embedded-storage = "0.3.1" static_cell = "2" sha2 = { version = "0.10.8", default-features = false } +hmac = "0.12.1" [profile.release] debug = 2 diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index cbb880353..c2d1a7158 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -6,9 +6,12 @@ use embassy_executor::Spawner; use embassy_stm32::hash::*; use embassy_stm32::{bind_interrupts, hash, peripherals, Config}; use embassy_time::Instant; +use hmac::{Hmac, Mac}; use sha2::{Digest, Sha256}; use {defmt_rtt as _, panic_probe as _}; +type HmacSha256 = Hmac; + bind_interrupts!(struct Irqs { HASH_RNG => hash::InterruptHandler; }); @@ -52,5 +55,24 @@ async fn main(_spawner: Spawner) -> ! { info!("Software Execution Time: {:?}", sw_execution_time); assert_eq!(hw_digest, sw_digest[..]); + let hmac_key: [u8; 64] = [0x55; 64]; + + // Compute HMAC in hardware. + let mut sha256hmac_context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, Some(&hmac_key)); + hw_hasher.update(&mut sha256hmac_context, test_1).await; + hw_hasher.update(&mut sha256hmac_context, test_2).await; + let mut hw_hmac: [u8; 32] = [0; 32]; + hw_hasher.finish(sha256hmac_context, &mut hw_hmac).await; + + // Compute HMAC in software. + let mut sw_mac = HmacSha256::new_from_slice(&hmac_key).unwrap(); + sw_mac.update(test_1); + sw_mac.update(test_2); + let sw_hmac = sw_mac.finalize().into_bytes(); + + info!("Hardware HMAC: {:?}", hw_hmac); + info!("Software HMAC: {:?}", sw_hmac[..]); + assert_eq!(hw_hmac, sw_hmac[..]); + loop {} } From 14a678fe4542d7c400d0d68b2859c54f2246abe4 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:33:04 -0500 Subject: [PATCH 452/760] Fixed HMAC blocking mode. --- embassy-stm32/src/hash/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index bae538b5f..b47814f8b 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -215,7 +215,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { self.accumulate_blocking(key); T::regs().str().write(|w| w.set_dcal(true)); // Block waiting for digest. - while !T::regs().sr().read().dcis() {} + while !T::regs().sr().read().dinis() {} } ctx.key_sent = true; } @@ -365,16 +365,16 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { //Start the digest calculation. T::regs().str().write(|w| w.set_dcal(true)); - // Block waiting for digest. - while !T::regs().sr().read().dcis() {} - // Load the HMAC key if provided. if let Some(key) = ctx.key { + while !T::regs().sr().read().dinis() {} self.accumulate_blocking(key); T::regs().str().write(|w| w.set_dcal(true)); - while !T::regs().sr().read().dcis() {} } + // Block until digest computation is complete. + while !T::regs().sr().read().dcis() {} + // Return the digest. let digest_words = match ctx.algo { Algorithm::SHA1 => 5, From f9af0096bd6cd74853b8e5406d6135de2f5c8274 Mon Sep 17 00:00:00 2001 From: Ralf Date: Mon, 12 Feb 2024 19:29:29 +0100 Subject: [PATCH 453/760] FAQ add hint to embassy-time linker error to include HAL in linking --- docs/modules/ROOT/pages/faq.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index 7fb81e2ca..d55e63130 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -118,6 +118,13 @@ features = [ ] ---- +If you are in the early project setup phase and not using anything from the HAL, make sure the HAL is passed to the linker by adding this line to your source: + +[source,rust] +---- +use embassy_stm32 as _; +---- + == Error: `Only one package in the dependency graph may specify the same links value.` You have multiple versions of the same crate in your dependency tree. This means that some of your From 4a0b1cbadb252f186ef41c465936bb3ac4dfcf3f Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 13 Feb 2024 15:23:50 +0100 Subject: [PATCH 454/760] Update docs/modules/ROOT/pages/faq.adoc --- docs/modules/ROOT/pages/faq.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index d55e63130..6b5e6d009 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -118,7 +118,7 @@ features = [ ] ---- -If you are in the early project setup phase and not using anything from the HAL, make sure the HAL is passed to the linker by adding this line to your source: +If you are in the early project setup phase and not using anything from the HAL, make sure the HAL is explicitly used to prevent the linker removing it as dead code by adding this line to your source: [source,rust] ---- From f0045b92173a46e45be1724d28e1a59045c9c3f6 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:17:19 -0500 Subject: [PATCH 455/760] Added HMAC to STM32 hash test. --- tests/stm32/Cargo.toml | 1 + tests/stm32/src/bin/hash.rs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index fc4420687..d94045737 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -76,6 +76,7 @@ portable-atomic = { version = "1.5", features = [] } chrono = { version = "^0.4", default-features = false, optional = true} sha2 = { version = "0.10.8", default-features = false } +hmac = "0.12.1" # BEGIN TESTS # Generated by gen_test.py. DO NOT EDIT. diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index 1b89f46e8..d1cfac5ce 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -9,9 +9,12 @@ use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; use embassy_stm32::hash::*; use embassy_stm32::{bind_interrupts, hash, peripherals}; +use hmac::{Hmac, Mac}; use sha2::{Digest, Sha224, Sha256}; use {defmt_rtt as _, panic_probe as _}; +type HmacSha256 = Hmac; + #[cfg(any(feature = "stm32l4a6zg", feature = "stm32h755zi", feature = "stm32h753zi"))] bind_interrupts!(struct Irqs { HASH_RNG => hash::InterruptHandler; @@ -73,6 +76,25 @@ async fn main(_spawner: Spawner) { info!("Software SHA-256 Digest: {:?}", sw_sha224_digest[..]); defmt::assert!(sha224_digest_buffer == sw_sha224_digest[..]); + let hmac_key: [u8; 64] = [0x55; 64]; + + // Compute HMAC in hardware. + let mut sha256hmac_context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, Some(&hmac_key)); + hw_hasher.update_blocking(&mut sha256hmac_context, test_1); + hw_hasher.update_blocking(&mut sha256hmac_context, test_2); + let mut hw_hmac: [u8; 32] = [0; 32]; + hw_hasher.finish_blocking(sha256hmac_context, &mut hw_hmac); + + // Compute HMAC in software. + let mut sw_mac = HmacSha256::new_from_slice(&hmac_key).unwrap(); + sw_mac.update(test_1); + sw_mac.update(test_2); + let sw_hmac = sw_mac.finalize().into_bytes(); + + info!("Hardware HMAC: {:?}", hw_hmac); + info!("Software HMAC: {:?}", sw_hmac[..]); + defmt::assert!(hw_hmac == sw_hmac[..]); + info!("Test OK"); cortex_m::asm::bkpt(); } From 0ceb313b6f0827c1b9544f8b87e721c616de8cc2 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Wed, 14 Feb 2024 07:22:52 +0530 Subject: [PATCH 456/760] FIX: Correct typo in stm32 gpio --- embassy-stm32/src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 1051a13c8..00e3e1727 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -249,7 +249,7 @@ impl From for vals::Pupdr { /// Speed settings /// -/// These vary dpeending on the chip, ceck the reference manual or datasheet for details. +/// These vary depending on the chip, check the reference manual or datasheet for details. #[allow(missing_docs)] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] From bbe1eebc534f57c74f1735e5d99ed3c4136636bd Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Wed, 14 Feb 2024 17:17:27 +0800 Subject: [PATCH 457/760] Add missing TIM for time-driver; reorder time-driver selection when use "time-drvier-any". --- embassy-stm32/build.rs | 41 ++++++++------------ embassy-stm32/src/time_driver.rs | 66 +++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 34 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 35023bf1f..5241dbb27 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -183,40 +183,33 @@ fn main() { let time_driver_singleton = match time_driver.as_ref().map(|x| x.as_ref()) { None => "", + Some("tim1") => "TIM1", Some("tim2") => "TIM2", Some("tim3") => "TIM3", Some("tim4") => "TIM4", Some("tim5") => "TIM5", + Some("tim8") => "TIM8", Some("tim9") => "TIM9", - Some("tim11") => "TIM11", Some("tim12") => "TIM12", Some("tim15") => "TIM15", + Some("tim20") => "TIM20", Some("tim21") => "TIM21", Some("tim22") => "TIM22", + Some("tim23") => "TIM23", + Some("tim24") => "TIM24", Some("any") => { - if singletons.contains(&"TIM2".to_string()) { - "TIM2" - } else if singletons.contains(&"TIM3".to_string()) { - "TIM3" - } else if singletons.contains(&"TIM4".to_string()) { - "TIM4" - } else if singletons.contains(&"TIM5".to_string()) { - "TIM5" - } else if singletons.contains(&"TIM9".to_string()) { - "TIM9" - } else if singletons.contains(&"TIM11".to_string()) { - "TIM11" - } else if singletons.contains(&"TIM12".to_string()) { - "TIM12" - } else if singletons.contains(&"TIM15".to_string()) { - "TIM15" - } else if singletons.contains(&"TIM21".to_string()) { - "TIM21" - } else if singletons.contains(&"TIM22".to_string()) { - "TIM22" - } else { - panic!("time-driver-any requested, but the chip doesn't have TIM2, TIM3, TIM4, TIM5, TIM9, TIM11, TIM12 or TIM15.") - } + // Order of TIM candidators: + // 1. 2CH -> 2CH_CMP -> GP16 -> GP32 -> ADV + // 2. In same catagory: larger TIM number first + [ + "TIM22", "TIM21", "TIM12", "TIM9", // 2CH + "TIM15", // 2CH_CMP + "TIM19", "TIM4", "TIM3", // GP16 + "TIM24", "TIM23", "TIM5", "TIM2", // GP32 + "TIM20", "TIM8", "TIM1", //ADV + ] + .iter() + .find(|tim| singletons.contains(&tim.to_string())).expect("time-driver-any requested, but the chip doesn't have TIM1, TIM2, TIM3, TIM4, TIM5, TIM8, TIM9, TIM12, TIM15, TIM20, TIM21, TIM22, TIM23 or TIM24.") } _ => panic!("unknown time_driver {:?}", time_driver), }; diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 29ff4a736..a1f54307d 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use core::cell::Cell; use core::convert::TryInto; use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; @@ -22,18 +24,22 @@ use crate::{interrupt, peripherals}; // As of 2023-12-04, this driver is implemented using CC1 as the halfway rollover interrupt, and any // additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST // one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not -// candidates for use as an embassy-time driver provider. +// candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.) // // The values of ALARM_COUNT below are not the TOTAL CC registers available, but rather the number // available after reserving CC1 for regular time keeping. For example, TIM2 has four CC registers: // CC1, CC2, CC3, and CC4, so it can provide ALARM_COUNT = 3. -#[cfg(not(any(time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22)))] -const ALARM_COUNT: usize = 3; - -#[cfg(any(time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] -const ALARM_COUNT: usize = 1; +cfg_if::cfg_if! { + if #[cfg(any(time_driver_tim9, time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] { + const ALARM_COUNT: usize = 1; + } else { + const ALARM_COUNT: usize = 3; + } +} +#[cfg(time_drvier_tim1)] +type T = peripherals::TIM1; #[cfg(time_driver_tim2)] type T = peripherals::TIM2; #[cfg(time_driver_tim3)] @@ -42,6 +48,8 @@ type T = peripherals::TIM3; type T = peripherals::TIM4; #[cfg(time_driver_tim5)] type T = peripherals::TIM5; +#[cfg(time_driver_tim8)] +type T = peripherals::TIM8; #[cfg(time_driver_tim9)] type T = peripherals::TIM9; #[cfg(time_driver_tim11)] @@ -50,12 +58,26 @@ type T = peripherals::TIM11; type T = peripherals::TIM12; #[cfg(time_driver_tim15)] type T = peripherals::TIM15; +#[cfg(time_driver_tim20)] +type T = peripherals::TIM20; #[cfg(time_driver_tim21)] type T = peripherals::TIM21; #[cfg(time_driver_tim22)] type T = peripherals::TIM22; +#[cfg(time_driver_tim23)] +type T = peripherals::TIM23; +#[cfg(time_driver_tim24)] +type T = peripherals::TIM24; foreach_interrupt! { + (TIM1, timer, $block:ident, UP, $irq:ident) => { + #[cfg(time_driver_tim1)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; (TIM2, timer, $block:ident, UP, $irq:ident) => { #[cfg(time_driver_tim2)] #[cfg(feature = "rt")] @@ -88,16 +110,16 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; - (TIM9, timer, $block:ident, UP, $irq:ident) => { - #[cfg(time_driver_tim9)] + (TIM8, timer, $block:ident, UP, $irq:ident) => { + #[cfg(time_driver_tim8)] #[cfg(feature = "rt")] #[interrupt] fn $irq() { DRIVER.on_interrupt() } }; - (TIM11, timer, $block:ident, UP, $irq:ident) => { - #[cfg(time_driver_tim11)] + (TIM9, timer, $block:ident, UP, $irq:ident) => { + #[cfg(time_driver_tim9)] #[cfg(feature = "rt")] #[interrupt] fn $irq() { @@ -120,6 +142,14 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; + (TIM20, timer, $block:ident, UP, $irq:ident) => { + #[cfg(time_driver_tim20)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; (TIM21, timer, $block:ident, UP, $irq:ident) => { #[cfg(time_driver_tim21)] #[cfg(feature = "rt")] @@ -136,6 +166,22 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; + (TIM23, timer, $block:ident, UP, $irq:ident) => { + #[cfg(time_driver_tim23)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; + (TIM24, timer, $block:ident, UP, $irq:ident) => { + #[cfg(time_driver_tim24)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; } // Clock timekeeping works with something we call "periods", which are time intervals From 1860e2269311df018a47a9a52f9f942c0285c97b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 14 Feb 2024 00:10:59 +0100 Subject: [PATCH 458/760] stm32/rcc: unify f0, f1, f3. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/f0.rs | 232 -------------------- embassy-stm32/src/rcc/{f3.rs => f013.rs} | 163 +++++++++++--- embassy-stm32/src/rcc/f1.rs | 257 ----------------------- embassy-stm32/src/rcc/{f.rs => f247.rs} | 0 embassy-stm32/src/rcc/mod.rs | 6 +- 6 files changed, 137 insertions(+), 525 deletions(-) delete mode 100644 embassy-stm32/src/rcc/f0.rs rename embassy-stm32/src/rcc/{f3.rs => f013.rs} (65%) delete mode 100644 embassy-stm32/src/rcc/f1.rs rename embassy-stm32/src/rcc/{f.rs => f247.rs} (100%) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4c27164ce..c384f14f1 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-7734584b2007766b1c5a6a7f2654fdb442fa211a" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cc1a1603e61881a6f0a1a47c12c16c57c245ba8" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-7734584b2007766b1c5a6a7f2654fdb442fa211a", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cc1a1603e61881a6f0a1a47c12c16c57c245ba8", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs deleted file mode 100644 index d6f995e45..000000000 --- a/embassy-stm32/src/rcc/f0.rs +++ /dev/null @@ -1,232 +0,0 @@ -use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::Pllsrc; -pub use crate::pac::rcc::vals::{ - Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Prediv as PllPreDiv, Sw as Sysclk, -}; -use crate::pac::{FLASH, RCC}; -use crate::time::Hertz; - -/// HSI speed -pub const HSI_FREQ: Hertz = Hertz(8_000_000); - -#[derive(Clone, Copy, Eq, PartialEq)] -pub enum HseMode { - /// crystal/ceramic oscillator (HSEBYP=0) - Oscillator, - /// external analog clock (low swing) (HSEBYP=1) - Bypass, -} - -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct Hse { - /// HSE frequency. - pub freq: Hertz, - /// HSE mode. - pub mode: HseMode, -} - -#[derive(Clone, Copy, Eq, PartialEq)] -pub enum PllSource { - HSE, - HSI, - #[cfg(rcc_f0v4)] - HSI48, -} - -#[derive(Clone, Copy)] -pub struct Pll { - pub src: PllSource, - - /// PLL pre-divider. - /// - /// On some chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. - pub prediv: PllPreDiv, - - /// PLL multiplication factor. - pub mul: PllMul, -} - -/// Clocks configutation -#[non_exhaustive] -pub struct Config { - pub hsi: bool, - pub hse: Option, - #[cfg(crs)] - pub hsi48: Option, - pub sys: Sysclk, - - pub pll: Option, - - pub ahb_pre: AHBPrescaler, - pub apb1_pre: APBPrescaler, - - pub ls: super::LsConfig, -} - -impl Default for Config { - fn default() -> Self { - Self { - hsi: true, - hse: None, - #[cfg(crs)] - hsi48: Some(Default::default()), - sys: Sysclk::HSI, - pll: None, - ahb_pre: AHBPrescaler::DIV1, - apb1_pre: APBPrescaler::DIV1, - ls: Default::default(), - } - } -} - -/// Initialize and Set the clock frequencies -pub(crate) unsafe fn init(config: Config) { - // Configure HSI - let hsi = match config.hsi { - false => { - RCC.cr().modify(|w| w.set_hsion(false)); - None - } - true => { - RCC.cr().modify(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - Some(HSI_FREQ) - } - }; - - // Configure HSE - let hse = match config.hse { - None => { - RCC.cr().modify(|w| w.set_hseon(false)); - None - } - Some(hse) => { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), - } - - RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); - RCC.cr().modify(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - Some(hse.freq) - } - }; - - // configure HSI48 - #[cfg(crs)] - let hsi48 = config.hsi48.map(|config| super::init_hsi48(config)); - #[cfg(not(crs))] - let hsi48: Option = None; - - // Enable PLL - let pll = config.pll.map(|pll| { - let (src_val, src_freq) = match pll.src { - #[cfg(not(any(rcc_f0v1, rcc_f0v2)))] - PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)), - #[cfg(any(rcc_f0v1, rcc_f0v2))] - PllSource::HSI => { - if pll.prediv != PllPreDiv::DIV2 { - panic!("if PLL source is HSI, PLL prediv must be 2."); - } - (Pllsrc::HSI_DIV2, unwrap!(hsi)) - } - PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), - #[cfg(rcc_f0v4)] - PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), - }; - let in_freq = src_freq / pll.prediv; - assert!(max::PLL_IN.contains(&in_freq)); - let out_freq = in_freq * pll.mul; - assert!(max::PLL_OUT.contains(&out_freq)); - - RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); - RCC.cfgr().modify(|w| { - w.set_pllmul(pll.mul); - w.set_pllsrc(src_val); - }); - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - - out_freq - }); - - // Configure sysclk - let sys = match config.sys { - Sysclk::HSI => unwrap!(hsi), - Sysclk::HSE => unwrap!(hse), - Sysclk::PLL1_P => unwrap!(pll), - #[cfg(rcc_f0v4)] - Sysclk::HSI48 => unwrap!(hsi48), - #[allow(unreachable_patterns)] - _ => unreachable!(), - }; - - let hclk = sys / config.ahb_pre; - let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); - - assert!(max::HCLK.contains(&hclk)); - assert!(max::PCLK1.contains(&pclk1)); - - // Set latency based on HCLK frquency - let latency = match hclk.0 { - ..=24_000_000 => Latency::WS0, - _ => Latency::WS1, - }; - FLASH.acr().modify(|w| { - w.set_latency(latency); - w.set_prftbe(true); - }); - - // Set prescalers - // CFGR has been written before (PLL, PLL48) don't overwrite these settings - RCC.cfgr().modify(|w| { - w.set_ppre(config.apb1_pre); - w.set_hpre(config.ahb_pre); - }); - - // Wait for the new prescalers to kick in - // "The clocks are divided with the new prescaler factor from - // 1 to 16 AHB cycles after write" - cortex_m::asm::delay(16); - - // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings - RCC.cfgr().modify(|w| w.set_sw(config.sys)); - while RCC.cfgr().read().sws() != config.sys {} - - let rtc = config.ls.init(); - - set_clocks!( - hsi: hsi, - hse: hse, - pll1_p: pll, - sys: Some(sys), - pclk1: Some(pclk1), - pclk2: Some(pclk1), - pclk1_tim: Some(pclk1_tim), - pclk2_tim: Some(pclk1_tim), - hclk1: Some(hclk), - #[cfg(all(not(rcc_f37), adc3_common))] - adc34: Some(adc34), - #[cfg(stm32f334)] - hrtim: hrtim, - hsi48: hsi48, - rtc: rtc, - lse: None, - ); -} - -mod max { - use core::ops::RangeInclusive; - - use crate::time::Hertz; - - pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(32_000_000); - pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(32_000_000); - - pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(48_000_000); - pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(48_000_000); - - pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(24_000_000); - pub(crate) const PLL_OUT: RangeInclusive = Hertz(16_000_000)..=Hertz(48_000_000); -} diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f013.rs similarity index 65% rename from embassy-stm32/src/rcc/f3.rs rename to embassy-stm32/src/rcc/f013.rs index 580aa389f..c2933186c 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -1,9 +1,14 @@ use crate::pac::flash::vals::Latency; -pub use crate::pac::rcc::vals::{ - Adcpres as AdcPllPrescaler, Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Prediv as PllPreDiv, - Sw as Sysclk, -}; -use crate::pac::rcc::vals::{Pllsrc, Usbpre}; +#[cfg(stm32f1)] +pub use crate::pac::rcc::vals::Adcpre as ADCPrescaler; +#[cfg(stm32f3)] +pub use crate::pac::rcc::vals::Adcpres as AdcPllPrescaler; +use crate::pac::rcc::vals::Pllsrc; +#[cfg(stm32f1)] +pub use crate::pac::rcc::vals::Pllxtpre as PllPreDiv; +#[cfg(any(stm32f0, stm32f3))] +pub use crate::pac::rcc::vals::Prediv as PllPreDiv; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Sw as Sysclk}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -30,6 +35,8 @@ pub struct Hse { pub enum PllSource { HSE, HSI, + #[cfg(rcc_f0v4)] + HSI48, } #[derive(Clone, Copy)] @@ -38,19 +45,21 @@ pub struct Pll { /// PLL pre-divider. /// - /// On some F3 chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. + /// On some chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. pub prediv: PllPreDiv, /// PLL multiplication factor. pub mul: PllMul, } +#[cfg(all(stm32f3, not(rcc_f37)))] #[derive(Clone, Copy)] pub enum AdcClockSource { Pll(AdcPllPrescaler), Hclk(AdcHclkPrescaler), } +#[cfg(all(stm32f3, not(rcc_f37)))] #[derive(Clone, Copy, PartialEq, Eq)] pub enum AdcHclkPrescaler { Div1, @@ -58,6 +67,7 @@ pub enum AdcHclkPrescaler { Div4, } +#[cfg(stm32f334)] #[derive(Clone, Copy, PartialEq, Eq)] pub enum HrtimClockSource { BusClk, @@ -69,17 +79,23 @@ pub enum HrtimClockSource { pub struct Config { pub hsi: bool, pub hse: Option, + #[cfg(crs)] + pub hsi48: Option, pub sys: Sysclk, pub pll: Option, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, + #[cfg(not(stm32f0))] pub apb2_pre: APBPrescaler, - #[cfg(not(rcc_f37))] + #[cfg(stm32f1)] + pub adc_pre: ADCPrescaler, + + #[cfg(all(stm32f3, not(rcc_f37)))] pub adc: AdcClockSource, - #[cfg(all(not(rcc_f37), adc3_common))] + #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] pub adc34: AdcClockSource, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, @@ -92,16 +108,24 @@ impl Default for Config { Self { hsi: true, hse: None, + #[cfg(crs)] + hsi48: Some(Default::default()), sys: Sysclk::HSI, pll: None, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, + #[cfg(not(stm32f0))] apb2_pre: APBPrescaler::DIV1, ls: Default::default(), - #[cfg(not(rcc_f37))] + #[cfg(stm32f1)] + // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz) + adc_pre: ADCPrescaler::DIV6, + + + #[cfg(all(stm32f3, not(rcc_f37)))] adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), - #[cfg(all(not(rcc_f37), adc3_common))] + #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(stm32f334)] hrtim: HrtimClockSource::BusClk, @@ -143,13 +167,18 @@ pub(crate) unsafe fn init(config: Config) { } }; + // configure HSI48 + #[cfg(crs)] + let hsi48 = config.hsi48.map(|config| super::init_hsi48(config)); + #[cfg(not(crs))] + let hsi48: Option = None; + // Enable PLL - // RM0316: "Reserved, must be kept at reset value." let pll = config.pll.map(|pll| { let (src_val, src_freq) = match pll.src { - #[cfg(rcc_f3v3)] + #[cfg(any(rcc_f0v3, rcc_f0v4, rcc_f3v3))] PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)), - #[cfg(not(rcc_f3v3))] + #[cfg(not(any(rcc_f0v3, rcc_f0v4, rcc_f3v3)))] PllSource::HSI => { if pll.prediv != PllPreDiv::DIV2 { panic!("if PLL source is HSI, PLL prediv must be 2."); @@ -157,16 +186,21 @@ pub(crate) unsafe fn init(config: Config) { (Pllsrc::HSI_DIV2, unwrap!(hsi)) } PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), + #[cfg(rcc_f0v4)] + PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), }; let in_freq = src_freq / pll.prediv; assert!(max::PLL_IN.contains(&in_freq)); let out_freq = in_freq * pll.mul; assert!(max::PLL_OUT.contains(&out_freq)); + #[cfg(not(stm32f1))] RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); RCC.cfgr().modify(|w| { w.set_pllmul(pll.mul); w.set_pllsrc(src_val); + #[cfg(stm32f1)] + w.set_pllxtpre(pll.prediv); }); RCC.cr().modify(|w| w.set_pllon(true)); while !RCC.cr().read().pllrdy() {} @@ -174,17 +208,16 @@ pub(crate) unsafe fn init(config: Config) { out_freq }); + #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] let usb = match pll { - Some(Hertz(72_000_000)) => { - RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1_5)); - Some(Hertz(48_000_000)) - } - Some(Hertz(48_000_000)) => { - RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1)); - Some(Hertz(48_000_000)) - } + Some(Hertz(72_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1_5), + Some(Hertz(48_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1), _ => None, - }; + } + .map(|usbpre| { + RCC.cfgr().modify(|w| w.set_usbpre(usbpre)); + Hertz(48_000_000) + }); // Configure sysclk let sys = match config.sys { @@ -196,13 +229,28 @@ pub(crate) unsafe fn init(config: Config) { let hclk = sys / config.ahb_pre; let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + #[cfg(not(stm32f0))] let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); + #[cfg(stm32f0)] + let (pclk2, pclk2_tim) = (pclk1, pclk1_tim); assert!(max::HCLK.contains(&hclk)); assert!(max::PCLK1.contains(&pclk1)); + #[cfg(not(stm32f0))] assert!(max::PCLK2.contains(&pclk2)); + #[cfg(stm32f1)] + let adc = pclk2 / config.adc_pre; + #[cfg(stm32f1)] + assert!(max::ADC.contains(&adc)); + // Set latency based on HCLK frquency + #[cfg(stm32f0)] + let latency = match hclk.0 { + ..=24_000_000 => Latency::WS0, + _ => Latency::WS1, + }; + #[cfg(any(stm32f1, stm32f3))] let latency = match hclk.0 { ..=24_000_000 => Latency::WS0, ..=48_000_000 => Latency::WS1, @@ -213,18 +261,28 @@ pub(crate) unsafe fn init(config: Config) { // RM0316: "The prefetch buffer must be kept on when using a prescaler // different from 1 on the AHB clock.", "Half-cycle access cannot be // used when there is a prescaler different from 1 on the AHB clock" + #[cfg(stm32f3)] if config.ahb_pre != AHBPrescaler::DIV1 { w.set_hlfcya(false); w.set_prftbe(true); } + #[cfg(not(stm32f3))] + w.set_prftbe(true); }); // Set prescalers // CFGR has been written before (PLL, PLL48) don't overwrite these settings - RCC.cfgr().modify(|w| { - w.set_ppre1(config.apb1_pre); - w.set_ppre2(config.apb2_pre); + RCC.cfgr().modify(|w: &mut stm32_metapac::rcc::regs::Cfgr| { + #[cfg(not(stm32f0))] + { + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); + } + #[cfg(stm32f0)] + w.set_ppre(config.apb1_pre); w.set_hpre(config.ahb_pre); + #[cfg(stm32f1)] + w.set_adcpre(config.adc_pre); }); // Wait for the new prescalers to kick in @@ -238,10 +296,10 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); - #[cfg(not(rcc_f37))] + #[cfg(all(stm32f3, not(rcc_f37)))] use crate::pac::adccommon::vals::Ckmode; - #[cfg(not(rcc_f37))] + #[cfg(all(stm32f3, not(rcc_f37)))] let adc = match config.adc { AdcClockSource::Pll(adcpres) => { RCC.cfgr2().modify(|w| w.set_adc12pres(adcpres)); @@ -265,7 +323,7 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(all(not(rcc_f37), adc3_common))] + #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] let adc34 = match config.adc34 { AdcClockSource::Pll(adcpres) => { RCC.cfgr2().modify(|w| w.set_adc34pres(adcpres)); @@ -316,18 +374,63 @@ pub(crate) unsafe fn init(config: Config) { pclk1_tim: Some(pclk1_tim), pclk2_tim: Some(pclk2_tim), hclk1: Some(hclk), - #[cfg(not(rcc_f37))] + #[cfg(all(stm32f3, not(rcc_f37)))] adc: Some(adc), - #[cfg(all(not(rcc_f37), adc3_common))] + #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] adc34: Some(adc34), #[cfg(stm32f334)] hrtim: hrtim, rtc: rtc, + hsi48: hsi48, + #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] usb: usb, lse: None, ); } +#[cfg(stm32f0)] +mod max { + use core::ops::RangeInclusive; + + use crate::time::Hertz; + + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(32_000_000); + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(32_000_000); + + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(48_000_000); + pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(48_000_000); + + pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(24_000_000); + pub(crate) const PLL_OUT: RangeInclusive = Hertz(16_000_000)..=Hertz(48_000_000); +} + +#[cfg(stm32f1)] +mod max { + use core::ops::RangeInclusive; + + use crate::time::Hertz; + + #[cfg(not(rcc_f1cl))] + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(16_000_000); + #[cfg(not(rcc_f1cl))] + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(25_000_000); + + #[cfg(rcc_f1cl)] + pub(crate) const HSE_OSC: RangeInclusive = Hertz(3_000_000)..=Hertz(25_000_000); + #[cfg(rcc_f1cl)] + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(50_000_000); + + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(72_000_000); + pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(36_000_000); + pub(crate) const PCLK2: RangeInclusive = Hertz(0)..=Hertz(72_000_000); + + pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(25_000_000); + pub(crate) const PLL_OUT: RangeInclusive = Hertz(16_000_000)..=Hertz(72_000_000); + + pub(crate) const ADC: RangeInclusive = Hertz(0)..=Hertz(14_000_000); +} + +#[cfg(stm32f3)] mod max { use core::ops::RangeInclusive; diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs deleted file mode 100644 index 9fdd4c11c..000000000 --- a/embassy-stm32/src/rcc/f1.rs +++ /dev/null @@ -1,257 +0,0 @@ -use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::Pllsrc; -#[cfg(any(rcc_f1, rcc_f1cl))] -use crate::pac::rcc::vals::Usbpre; -pub use crate::pac::rcc::vals::{ - Adcpre as ADCPrescaler, Hpre as AHBPrescaler, Pllmul as PllMul, Pllxtpre as PllPreDiv, Ppre as APBPrescaler, - Sw as Sysclk, -}; -use crate::pac::{FLASH, RCC}; -use crate::time::Hertz; - -/// HSI speed -pub const HSI_FREQ: Hertz = Hertz(8_000_000); - -#[derive(Clone, Copy, Eq, PartialEq)] -pub enum HseMode { - /// crystal/ceramic oscillator (HSEBYP=0) - Oscillator, - /// external analog clock (low swing) (HSEBYP=1) - Bypass, -} - -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct Hse { - /// HSE frequency. - pub freq: Hertz, - /// HSE mode. - pub mode: HseMode, -} - -#[derive(Clone, Copy, Eq, PartialEq)] -pub enum PllSource { - HSE, - HSI, -} - -#[derive(Clone, Copy)] -pub struct Pll { - pub src: PllSource, - - /// PLL pre-divider. - /// - /// On some F3 chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. - pub prediv: PllPreDiv, - - /// PLL multiplication factor. - pub mul: PllMul, -} - -/// Clocks configutation -#[non_exhaustive] -pub struct Config { - pub hsi: bool, - pub hse: Option, - pub sys: Sysclk, - - pub pll: Option, - - pub ahb_pre: AHBPrescaler, - pub apb1_pre: APBPrescaler, - pub apb2_pre: APBPrescaler, - - pub adc_pre: ADCPrescaler, - - pub ls: super::LsConfig, -} - -impl Default for Config { - fn default() -> Self { - Self { - hsi: true, - hse: None, - sys: Sysclk::HSI, - pll: None, - ahb_pre: AHBPrescaler::DIV1, - apb1_pre: APBPrescaler::DIV1, - apb2_pre: APBPrescaler::DIV1, - ls: Default::default(), - - // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz) - adc_pre: ADCPrescaler::DIV6, - } - } -} - -/// Initialize and Set the clock frequencies -pub(crate) unsafe fn init(config: Config) { - // Configure HSI - let hsi = match config.hsi { - false => { - RCC.cr().modify(|w| w.set_hsion(false)); - None - } - true => { - RCC.cr().modify(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - Some(HSI_FREQ) - } - }; - - // Configure HSE - let hse = match config.hse { - None => { - RCC.cr().modify(|w| w.set_hseon(false)); - None - } - Some(hse) => { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), - } - - RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); - RCC.cr().modify(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - Some(hse.freq) - } - }; - - // Enable PLL - let pll = config.pll.map(|pll| { - let (src_val, src_freq) = match pll.src { - PllSource::HSI => { - if pll.prediv != PllPreDiv::DIV2 { - panic!("if PLL source is HSI, PLL prediv must be 2."); - } - (Pllsrc::HSI_DIV2, unwrap!(hsi)) - } - PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), - }; - let in_freq = src_freq / pll.prediv; - assert!(max::PLL_IN.contains(&in_freq)); - let out_freq = in_freq * pll.mul; - assert!(max::PLL_OUT.contains(&out_freq)); - - RCC.cfgr().modify(|w| { - w.set_pllmul(pll.mul); - w.set_pllsrc(src_val); - w.set_pllxtpre(pll.prediv); - }); - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - - out_freq - }); - - #[cfg(any(rcc_f1, rcc_f1cl))] - let usb = match pll { - Some(Hertz(72_000_000)) => { - RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1_5)); - Some(Hertz(48_000_000)) - } - Some(Hertz(48_000_000)) => { - RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1)); - Some(Hertz(48_000_000)) - } - _ => None, - }; - - // Configure sysclk - let sys = match config.sys { - Sysclk::HSI => unwrap!(hsi), - Sysclk::HSE => unwrap!(hse), - Sysclk::PLL1_P => unwrap!(pll), - _ => unreachable!(), - }; - - let hclk = sys / config.ahb_pre; - let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); - let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); - - assert!(max::HCLK.contains(&hclk)); - assert!(max::PCLK1.contains(&pclk1)); - assert!(max::PCLK2.contains(&pclk2)); - - let adc = pclk2 / config.adc_pre; - assert!(max::ADC.contains(&adc)); - - // Set latency based on HCLK frquency - let latency = match hclk.0 { - ..=24_000_000 => Latency::WS0, - ..=48_000_000 => Latency::WS1, - _ => Latency::WS2, - }; - FLASH.acr().modify(|w| { - w.set_latency(latency); - // RM0316: "The prefetch buffer must be kept on when using a prescaler - // different from 1 on the AHB clock.", "Half-cycle access cannot be - // used when there is a prescaler different from 1 on the AHB clock" - if config.ahb_pre != AHBPrescaler::DIV1 { - w.set_hlfcya(false); - w.set_prftbe(true); - } - }); - - // Set prescalers - // CFGR has been written before (PLL, PLL48) don't overwrite these settings - RCC.cfgr().modify(|w| { - w.set_ppre1(config.apb1_pre); - w.set_ppre2(config.apb2_pre); - w.set_hpre(config.ahb_pre); - w.set_adcpre(config.adc_pre); - }); - - // Wait for the new prescalers to kick in - // "The clocks are divided with the new prescaler factor from - // 1 to 16 AHB cycles after write" - cortex_m::asm::delay(16); - - // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings - RCC.cfgr().modify(|w| w.set_sw(config.sys)); - while RCC.cfgr().read().sws() != config.sys {} - - let rtc = config.ls.init(); - - set_clocks!( - hsi: hsi, - hse: hse, - pll1_p: pll, - sys: Some(sys), - pclk1: Some(pclk1), - pclk2: Some(pclk2), - pclk1_tim: Some(pclk1_tim), - pclk2_tim: Some(pclk2_tim), - hclk1: Some(hclk), - adc: Some(adc), - rtc: rtc, - #[cfg(any(rcc_f1, rcc_f1cl))] - usb: usb, - lse: None, - ); -} - -mod max { - use core::ops::RangeInclusive; - - use crate::time::Hertz; - - #[cfg(not(rcc_f1cl))] - pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(16_000_000); - #[cfg(not(rcc_f1cl))] - pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(25_000_000); - - #[cfg(rcc_f1cl)] - pub(crate) const HSE_OSC: RangeInclusive = Hertz(3_000_000)..=Hertz(25_000_000); - #[cfg(rcc_f1cl)] - pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(50_000_000); - - pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(72_000_000); - pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(36_000_000); - pub(crate) const PCLK2: RangeInclusive = Hertz(0)..=Hertz(72_000_000); - - pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(25_000_000); - pub(crate) const PLL_OUT: RangeInclusive = Hertz(16_000_000)..=Hertz(72_000_000); - - pub(crate) const ADC: RangeInclusive = Hertz(0)..=Hertz(14_000_000); -} diff --git a/embassy-stm32/src/rcc/f.rs b/embassy-stm32/src/rcc/f247.rs similarity index 100% rename from embassy-stm32/src/rcc/f.rs rename to embassy-stm32/src/rcc/f247.rs diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index b7eca0615..0f3467151 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -18,10 +18,8 @@ mod hsi48; #[cfg(crs)] pub use hsi48::*; -#[cfg_attr(stm32f0, path = "f0.rs")] -#[cfg_attr(stm32f1, path = "f1.rs")] -#[cfg_attr(stm32f3, path = "f3.rs")] -#[cfg_attr(any(stm32f2, stm32f4, stm32f7), path = "f.rs")] +#[cfg_attr(any(stm32f0, stm32f1, stm32f3), path = "f013.rs")] +#[cfg_attr(any(stm32f2, stm32f4, stm32f7), path = "f247.rs")] #[cfg_attr(stm32c0, path = "c0.rs")] #[cfg_attr(stm32g0, path = "g0.rs")] #[cfg_attr(stm32g4, path = "g4.rs")] From 84258e168091f1cba226f2abd91fbfa5431c12c2 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 14 Feb 2024 15:57:06 -0600 Subject: [PATCH 459/760] wip --- embassy-executor-macros/src/macros/task.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 1efb2788b..82579cbbe 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -93,10 +93,22 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result ::embassy_executor::SpawnToken { - type Fut = impl ::core::future::Future + 'static; + trait Task { + type Fut: core::future::Future + 'static; + fn construct(#fargs) -> Self::Fut; + } + + struct ThisTask; + impl Task for ThisTask { + type Fut = impl core::future::Future + 'static; + fn construct(#fargs) -> Self::Fut { + #task_inner_ident(#(#full_args,)*) + } + } + const POOL_SIZE: usize = #pool_size; - static POOL: ::embassy_executor::raw::TaskPool = ::embassy_executor::raw::TaskPool::new(); - unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } + static POOL: ::embassy_executor::raw::TaskPool<::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); + unsafe { POOL._spawn_async_fn(move || ThisTask::construct(#(#full_args,)*)) } } }; #[cfg(not(feature = "nightly"))] From 5a6384333f9bbd61565f820097bb89f9fbcce282 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 14 Feb 2024 16:14:41 -0600 Subject: [PATCH 460/760] Fix feature flag in executor tests --- embassy-executor/tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 2c2441dd5..348cc7dc4 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] use std::boxed::Box; use std::future::poll_fn; From dd549dad1a93be4a71fd65ebb220e9cab4d1d70d Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Wed, 14 Feb 2024 16:59:43 -0600 Subject: [PATCH 461/760] Improve hygiene --- embassy-executor-macros/src/macros/task.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 82579cbbe..548fa4629 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -93,13 +93,12 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result ::embassy_executor::SpawnToken { - trait Task { - type Fut: core::future::Future + 'static; + trait _EmbassyInternalTaskTrait { + type Fut: ::core::future::Future + 'static; fn construct(#fargs) -> Self::Fut; } - struct ThisTask; - impl Task for ThisTask { + impl _EmbassyInternalTaskTrait for () { type Fut = impl core::future::Future + 'static; fn construct(#fargs) -> Self::Fut { #task_inner_ident(#(#full_args,)*) @@ -107,7 +106,7 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); + static POOL: ::embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); unsafe { POOL._spawn_async_fn(move || ThisTask::construct(#(#full_args,)*)) } } }; From 50b8100fd30fd13ac706889b0951e6ec25c77821 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 15 Feb 2024 12:34:51 +0200 Subject: [PATCH 462/760] nrf: Implement chunked DMA transfers for SPIM peripheral On some chips (notably nrf52832), the maximum DMA transfer is 255 bytes, which has caused subtle issues while interfacing with various devices over SPI bus. --- embassy-nrf/src/spim.rs | 112 ++++++++++++++++++++++++---------------- embassy-nrf/src/util.rs | 13 +++++ 2 files changed, 81 insertions(+), 44 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 8937159df..2d70732a8 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -17,7 +17,7 @@ use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::sealed::Pin as _; use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; -use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; +use crate::util::{slice_in_ram_or, slice_ptr_len, slice_ptr_parts, slice_ptr_parts_mut}; use crate::{interrupt, pac, Peripheral}; /// SPIM error @@ -25,10 +25,6 @@ use crate::{interrupt, pac, Peripheral}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { - /// Supplied TX buffer overflows EasyDMA transmit buffer - TxBufferTooLong, - /// Supplied RX buffer overflows EasyDMA receive buffer - RxBufferTooLong, /// EasyDMA can only read from data memory, read only buffers in flash will fail. BufferNotInRAM, } @@ -74,9 +70,13 @@ impl interrupt::typelevel::Handler for InterruptHandl let s = T::state(); #[cfg(feature = "_nrf52832_anomaly_109")] - if r.events_started.read().bits() != 0 { - s.waker.wake(); - r.intenclr.write(|w| w.started().clear()); + { + // Ideally we should call this only during the first chunk transfer, + // but so far calling this every time doesn't seem to be causing any issues. + if r.events_started.read().bits() != 0 { + s.waker.wake(); + r.intenclr.write(|w| w.started().clear()); + } } if r.events_end.read().bits() != 0 { @@ -209,35 +209,39 @@ impl<'d, T: Instance> Spim<'d, T> { spim } - fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { - slice_in_ram_or(tx, Error::BufferNotInRAM)?; - // NOTE: RAM slice check for rx is not necessary, as a mutable - // slice can only be built from data located in RAM. - + fn prepare_dma_transfer(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) { compiler_fence(Ordering::SeqCst); let r = T::regs(); - // Set up the DMA write. - let (ptr, tx_len) = slice_ptr_parts(tx); - if tx_len > EASY_DMA_SIZE { - return Err(Error::TxBufferTooLong); + fn xfer_params(ptr: u32, total: usize, offset: usize, length: usize) -> (u32, usize) { + if total > offset { + (ptr.wrapping_add(offset as _), core::cmp::min(total - offset, length)) + } else { + (ptr, 0) + } } - r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); - // Set up the DMA read. - let (ptr, rx_len) = slice_ptr_parts_mut(rx); - if rx_len > EASY_DMA_SIZE { - return Err(Error::RxBufferTooLong); - } - - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); + let (ptr, len) = slice_ptr_parts_mut(rx); + let (rx_ptr, rx_len) = xfer_params(ptr as _, len as _, offset, length); + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(rx_ptr) }); r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); + // Set up the DMA write. + let (ptr, len) = slice_ptr_parts(tx); + let (tx_ptr, tx_len) = xfer_params(ptr as _, len as _, offset, length); + r.txd.ptr.write(|w| unsafe { w.ptr().bits(tx_ptr) }); + r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); + + /* + trace!("XFER: offset: {}, length: {}", offset, length); + trace!("RX(len: {}, ptr: {=u32:02x})", rx_len, rx_ptr as u32); + trace!("TX(len: {}, ptr: {=u32:02x})", tx_len, tx_ptr as u32); + */ + #[cfg(feature = "_nrf52832_anomaly_109")] - { + if offset == 0 { let s = T::state(); r.events_started.reset(); @@ -260,21 +264,32 @@ impl<'d, T: Instance> Spim<'d, T> { // Start SPI transaction. r.tasks_start.write(|w| unsafe { w.bits(1) }); - - Ok(()) } - fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { - self.prepare(rx, tx)?; + fn blocking_inner_from_ram_chunk(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) { + self.prepare_dma_transfer(rx, tx, offset, length); #[cfg(feature = "_nrf52832_anomaly_109")] - while let Poll::Pending = self.nrf52832_dma_workaround_status() {} + if offset == 0 { + while self.nrf52832_dma_workaround_status().is_pending() {} + } // Wait for 'end' event. while T::regs().events_end.read().bits() == 0 {} compiler_fence(Ordering::SeqCst); + } + fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { + slice_in_ram_or(tx, Error::BufferNotInRAM)?; + // NOTE: RAM slice check for rx is not necessary, as a mutable + // slice can only be built from data located in RAM. + + let xfer_len = core::cmp::max(slice_ptr_len(rx), slice_ptr_len(tx)); + for offset in (0..xfer_len).step_by(EASY_DMA_SIZE) { + let length = core::cmp::min(xfer_len - offset, EASY_DMA_SIZE); + self.blocking_inner_from_ram_chunk(rx, tx, offset, length); + } Ok(()) } @@ -287,22 +302,23 @@ impl<'d, T: Instance> Spim<'d, T> { tx_ram_buf.copy_from_slice(tx); self.blocking_inner_from_ram(rx, tx_ram_buf) } - Err(error) => Err(error), } } - async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { - self.prepare(rx, tx)?; + async fn async_inner_from_ram_chunk(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) { + self.prepare_dma_transfer(rx, tx, offset, length); #[cfg(feature = "_nrf52832_anomaly_109")] - poll_fn(|cx| { - let s = T::state(); + if offset == 0 { + poll_fn(|cx| { + let s = T::state(); - s.waker.register(cx.waker()); + s.waker.register(cx.waker()); - self.nrf52832_dma_workaround_status() - }) - .await; + self.nrf52832_dma_workaround_status() + }) + .await; + } // Wait for 'end' event. poll_fn(|cx| { @@ -316,7 +332,18 @@ impl<'d, T: Instance> Spim<'d, T> { .await; compiler_fence(Ordering::SeqCst); + } + async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { + slice_in_ram_or(tx, Error::BufferNotInRAM)?; + // NOTE: RAM slice check for rx is not necessary, as a mutable + // slice can only be built from data located in RAM. + + let xfer_len = core::cmp::max(slice_ptr_len(rx), slice_ptr_len(tx)); + for offset in (0..xfer_len).step_by(EASY_DMA_SIZE) { + let length = core::cmp::min(xfer_len - offset, EASY_DMA_SIZE); + self.async_inner_from_ram_chunk(rx, tx, offset, length).await; + } Ok(()) } @@ -329,7 +356,6 @@ impl<'d, T: Instance> Spim<'d, T> { tx_ram_buf.copy_from_slice(tx); self.async_inner_from_ram(rx, tx_ram_buf).await } - Err(error) => Err(error), } } @@ -528,8 +554,6 @@ mod eh02 { impl embedded_hal_1::spi::Error for Error { fn kind(&self) -> embedded_hal_1::spi::ErrorKind { match *self { - Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, - Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, Self::BufferNotInRAM => embedded_hal_1::spi::ErrorKind::Other, } } diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs index b408c517b..6cdb97f08 100644 --- a/embassy-nrf/src/util.rs +++ b/embassy-nrf/src/util.rs @@ -4,6 +4,19 @@ use core::mem; const SRAM_LOWER: usize = 0x2000_0000; const SRAM_UPPER: usize = 0x3000_0000; +// #![feature(const_slice_ptr_len)] +// https://github.com/rust-lang/rust/issues/71146 +pub(crate) fn slice_ptr_len(ptr: *const [T]) -> usize { + use core::ptr::NonNull; + let ptr = ptr.cast_mut(); + if let Some(ptr) = NonNull::new(ptr) { + ptr.len() + } else { + // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null. + NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len() + } +} + // TODO: replace transmutes with core::ptr::metadata once it's stable pub(crate) fn slice_ptr_parts(slice: *const [T]) -> (*const T, usize) { unsafe { mem::transmute(slice) } From 5b7eff65417e491fa7908dfd8b62013efb55d30b Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Thu, 15 Feb 2024 23:56:26 +0100 Subject: [PATCH 463/760] [embassy-stm32]: started stm32g4 RCC refactor * Copied API from f.rs where applicable * HSE and HSI independantly configurable * Boost mode set by user rather * Added HSE, pll1_q and pll1_p frequencies to set_clocks call * Stubbed max module based on f.rs, needs cleanup --- embassy-stm32/src/rcc/g4.rs | 204 +++++++++++++++---------- examples/stm32g4/src/bin/adc.rs | 16 +- examples/stm32g4/src/bin/pll.rs | 16 +- examples/stm32g4/src/bin/usb_serial.rs | 33 ++-- 4 files changed, 160 insertions(+), 109 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 3e20bf6af..edd14ab23 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,10 +1,10 @@ use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw}; +use stm32_metapac::rcc::vals::{Adcsel, Sw}; use stm32_metapac::FLASH; pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, - Pllp as PllP, Pllq as PllQ, Pllr as PllR, Ppre as APBPrescaler, + Adcsel as AdcClockSource, Clk48sel, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, Pllm as PllPreDiv, + Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{PWR, RCC}; use crate::time::Hertz; @@ -12,28 +12,20 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(16_000_000); -/// System clock mux source -#[derive(Clone, Copy)] -pub enum ClockSrc { - HSE(Hertz), - HSI, - PLL, +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1) + Bypass, } -/// PLL clock input source -#[derive(Clone, Copy, Debug)] -pub enum PllSource { - HSI, - HSE(Hertz), -} - -impl Into for PllSource { - fn into(self) -> Pllsrc { - match self { - PllSource::HSE(..) => Pllsrc::HSE, - PllSource::HSI => Pllsrc::HSI, - } - } +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, } /// PLL Configuration @@ -43,22 +35,22 @@ impl Into for PllSource { /// frequency ranges for each of these settings. pub struct Pll { /// PLL Source clock selection. - pub source: PllSource, + pub source: Pllsrc, /// PLL pre-divider - pub prediv_m: PllM, + pub prediv: PllPreDiv, /// PLL multiplication factor for VCO - pub mul_n: PllN, + pub mul: PllMul, /// PLL division factor for P clock (ADC Clock) - pub div_p: Option, + pub divp: Option, /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI) - pub div_q: Option, + pub divq: Option, /// PLL division factor for R clock (SYSCLK) - pub div_r: Option, + pub divr: Option, } /// Sets the source for the 48MHz clock to the USB and RNG peripherals. @@ -73,39 +65,53 @@ pub enum Clock48MhzSrc { } /// Clocks configutation +#[non_exhaustive] pub struct Config { - pub mux: ClockSrc, + pub hsi: bool, + pub hse: Option, + pub sys: Sysclk, + pub hsi48: Option, + + pub pll: Option, + + /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration + /// MUST turn on the PLLR output. pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, pub low_power_run: bool, - /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration - /// MUST turn on the PLLR output. - pub pll: Option, + /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. - pub clock_48mhz_src: Option, + pub clk48_src: Option, + + pub ls: super::LsConfig, + pub adc12_clock_source: AdcClockSource, pub adc345_clock_source: AdcClockSource, pub fdcan_clock_source: FdCanClockSource, - pub ls: super::LsConfig, + pub boost: bool, } impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::HSI, + hsi: true, + hse: None, + sys: Sysclk::HSI, + hsi48: Some(Default::default()), + pll: None, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, low_power_run: false, - pll: None, - clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())), + clk48_src: Some(Clock48MhzSrc::Hsi48(Default::default())), + ls: Default::default(), adc12_clock_source: Adcsel::DISABLE, adc345_clock_source: Adcsel::DISABLE, fdcan_clock_source: FdCanClockSource::PCLK1, - ls: Default::default(), + boost: false, } } } @@ -117,34 +123,60 @@ pub struct PllFreq { } pub(crate) unsafe fn init(config: Config) { + // Configure HSI + let hsi = match config.hsi { + false => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + true => { + RCC.cr().modify(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + Some(HSI_FREQ) + } + }; + + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } + + RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } + }; + let pll_freq = config.pll.map(|pll_config| { let src_freq = match pll_config.source { - PllSource::HSI => { - RCC.cr().write(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - - HSI_FREQ - } - PllSource::HSE(freq) => { - RCC.cr().write(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - freq - } + Pllsrc::HSI => unwrap!(hsi), + Pllsrc::HSE => unwrap!(hse), + _ => unreachable!(), }; + // TODO: check PLL input, internal and output frequencies for validity + // Disable PLL before configuration RCC.cr().modify(|w| w.set_pllon(false)); while RCC.cr().read().pllrdy() {} - let internal_freq = src_freq / pll_config.prediv_m * pll_config.mul_n; + let internal_freq = src_freq / pll_config.prediv * pll_config.mul; RCC.pllcfgr().write(|w| { - w.set_plln(pll_config.mul_n); - w.set_pllm(pll_config.prediv_m); + w.set_plln(pll_config.mul); + w.set_pllm(pll_config.prediv); w.set_pllsrc(pll_config.source.into()); }); - let pll_p_freq = pll_config.div_p.map(|div_p| { + let pll_p_freq = pll_config.divp.map(|div_p| { RCC.pllcfgr().modify(|w| { w.set_pllp(div_p); w.set_pllpen(true); @@ -152,7 +184,7 @@ pub(crate) unsafe fn init(config: Config) { internal_freq / div_p }); - let pll_q_freq = pll_config.div_q.map(|div_q| { + let pll_q_freq = pll_config.divq.map(|div_q| { RCC.pllcfgr().modify(|w| { w.set_pllq(div_q); w.set_pllqen(true); @@ -160,7 +192,7 @@ pub(crate) unsafe fn init(config: Config) { internal_freq / div_q }); - let pll_r_freq = pll_config.div_r.map(|div_r| { + let pll_r_freq = pll_config.divr.map(|div_r| { RCC.pllcfgr().modify(|w| { w.set_pllr(div_r); w.set_pllren(true); @@ -179,22 +211,10 @@ pub(crate) unsafe fn init(config: Config) { } }); - let (sys_clk, sw) = match config.mux { - ClockSrc::HSI => { - // Enable HSI - RCC.cr().write(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - - (HSI_FREQ, Sw::HSI) - } - ClockSrc::HSE(freq) => { - // Enable HSE - RCC.cr().write(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - - (freq, Sw::HSE) - } - ClockSrc::PLL => { + let (sys_clk, sw) = match config.sys { + Sysclk::HSI => (HSI_FREQ, Sw::HSI), + Sysclk::HSE => (unwrap!(hse), Sw::HSE), + Sysclk::PLL1_R => { assert!(pll_freq.is_some()); assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); @@ -202,10 +222,9 @@ pub(crate) unsafe fn init(config: Config) { assert!(freq <= 170_000_000); - if freq >= 150_000_000 { - // Enable Core Boost mode on freq >= 150Mhz ([RM0440] p234) + if config.boost { + // Enable Core Boost mode ([RM0440] p234) PWR.cr5().modify(|w| w.set_r1mode(false)); - // Set flash wait state in boost mode based on frequency ([RM0440] p191) if freq <= 36_000_000 { FLASH.acr().modify(|w| w.set_latency(Latency::WS0)); } else if freq <= 68_000_000 { @@ -218,8 +237,8 @@ pub(crate) unsafe fn init(config: Config) { FLASH.acr().modify(|w| w.set_latency(Latency::WS4)); } } else { + // Enable Core Boost mode ([RM0440] p234) PWR.cr5().modify(|w| w.set_r1mode(true)); - // Set flash wait state in normal mode based on frequency ([RM0440] p191) if freq <= 30_000_000 { FLASH.acr().modify(|w| w.set_latency(Latency::WS0)); } else if freq <= 60_000_000 { @@ -235,6 +254,7 @@ pub(crate) unsafe fn init(config: Config) { (Hertz(freq), Sw::PLL1_R) } + _ => unreachable!(), }; RCC.cfgr().modify(|w| { @@ -263,7 +283,7 @@ pub(crate) unsafe fn init(config: Config) { }; // Setup the 48 MHz clock if needed - if let Some(clock_48mhz_src) = config.clock_48mhz_src { + if let Some(clock_48mhz_src) = config.clk48_src { let source = match clock_48mhz_src { Clock48MhzSrc::PllQ => { // Make sure the PLLQ is enabled and running at 48Mhz @@ -317,9 +337,33 @@ pub(crate) unsafe fn init(config: Config) { pclk2_tim: Some(apb2_tim_freq), adc: adc12_ck, adc34: adc345_ck, - pll1_p: None, - pll1_q: None, // TODO - hse: None, // TODO + pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), + pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_p), + hse: hse, rtc: rtc, ); } + +// TODO: if necessary, make more of these gated behind cfg attrs +mod max { + use core::ops::RangeInclusive; + + use crate::time::Hertz; + + /// HSE 4-48MHz (RM0440 p280) + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(48_000_000); + + /// External Clock ?-48MHz (RM0440 p280) + pub(crate) const HSE_BYP: RangeInclusive = Hertz(0)..=Hertz(48_000_000); + + /// SYSCLK ?-170MHz (RM0440 p282) + pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); + + /// PLL Output frequency ?-170MHz (RM0440 p281) + pub(crate) const PCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); + + // Left over from f.rs, remove if not necessary + pub(crate) const HCLK: RangeInclusive = Hertz(12_500_000)..=Hertz(216_000_000); + pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(2_100_000); + pub(crate) const PLL_VCO: RangeInclusive = Hertz(100_000_000)..=Hertz(432_000_000); +} diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 35324d931..99e3ef63b 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::rcc::{AdcClockSource, ClockSrc, Pll, PllM, PllN, PllR, PllSource}; +use embassy_stm32::rcc::{AdcClockSource, Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk}; use embassy_stm32::Config; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -14,17 +14,17 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.pll = Some(Pll { - source: PllSource::HSI, - prediv_m: PllM::DIV4, - mul_n: PllN::MUL85, - div_p: None, - div_q: None, + source: Pllsrc::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, // Main system clock at 170 MHz - div_r: Some(PllR::DIV2), + divr: Some(PllRDiv::DIV2), }); config.rcc.adc12_clock_source = AdcClockSource::SYS; - config.rcc.mux = ClockSrc::PLL; + config.rcc.sys = Sysclk::PLL1_R; let mut p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs index 46ebe0b0d..5274de79d 100644 --- a/examples/stm32g4/src/bin/pll.rs +++ b/examples/stm32g4/src/bin/pll.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllR, PllSource}; +use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk}; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -13,16 +13,16 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.pll = Some(Pll { - source: PllSource::HSI, - prediv_m: PllM::DIV4, - mul_n: PllN::MUL85, - div_p: None, - div_q: None, + source: Pllsrc::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, // Main system clock at 170 MHz - div_r: Some(PllR::DIV2), + divr: Some(PllRDiv::DIV2), }); - config.rcc.mux = ClockSrc::PLL; + config.rcc.sys = Sysclk::PLL1_R; let _p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index c26fa76b7..d9207e4cd 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -3,7 +3,9 @@ use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, Hsi48Config, Pll, PllM, PllN, PllQ, PllR, PllSource}; +use embassy_stm32::rcc::{ + Clock48MhzSrc, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk, +}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, Config}; @@ -24,25 +26,30 @@ async fn main(_spawner: Spawner) { // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. const USE_HSI48: bool = true; - let plldivq = if USE_HSI48 { None } else { Some(PllQ::DIV6) }; + let plldivq = if USE_HSI48 { None } else { Some(PllQDiv::DIV6) }; - config.rcc.pll = Some(Pll { - source: PllSource::HSE(Hertz(8_000_000)), - prediv_m: PllM::DIV2, - mul_n: PllN::MUL72, - div_p: None, - div_q: plldivq, - // Main system clock at 144 MHz - div_r: Some(PllR::DIV2), + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Oscillator, }); - config.rcc.mux = ClockSrc::PLL; + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV2, + mul: PllMul::MUL72, + divp: None, + divq: plldivq, + // Main system clock at 144 MHz + divr: Some(PllRDiv::DIV2), + }); + + config.rcc.sys = Sysclk::PLL1_R; if USE_HSI48 { // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. - config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true })); + config.rcc.clk48_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true })); } else { - config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ); + config.rcc.clk48_src = Some(Clock48MhzSrc::PllQ); } let p = embassy_stm32::init(config); From bd0b450ca4ff36b2b1fe0b3b422cd478f9201ad0 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 15 Feb 2024 17:43:20 -0500 Subject: [PATCH 464/760] Improve rp2040 i2c slave This commit takes the fixes and error reporting improvements from jcdickinson's work and applies them without overlaying a software state machine on top of the hardware state machine. Also allows configuration of response to 'general call' writes. --- embassy-rp/src/i2c_slave.rs | 234 +++++++++++++++++++------------ examples/rp/src/bin/i2c_slave.rs | 2 +- 2 files changed, 147 insertions(+), 89 deletions(-) diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 721b7a1f6..d3cc20f39 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -4,6 +4,7 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; +use embassy_time::{block_for, Duration}; use pac::i2c; use crate::i2c::{ @@ -21,6 +22,16 @@ pub enum Error { Abort(AbortReason), /// User passed in a response buffer that was 0 length InvalidResponseBufferLength, + /// The response buffer length was too short to contain the message + /// + /// The length parameter will always be the length of the buffer, and is + /// provided as a convenience for matching alongside `Command::Write`. + PartialWrite(usize), + /// The response buffer length was too short to contain the message + /// + /// The length parameter will always be the length of the buffer, and is + /// provided as a convenience for matching alongside `Command::GeneralCall`. + PartialGeneralCall(usize), } /// Received command @@ -56,17 +67,23 @@ pub enum ReadStatus { pub struct Config { /// Target Address pub addr: u16, + /// Control if the peripheral should ack to and report general calls. + pub general_call: bool, } impl Default for Config { fn default() -> Self { - Self { addr: 0x55 } + Self { + addr: 0x55, + general_call: true, + } } } /// I2CSlave driver. pub struct I2cSlave<'d, T: Instance> { phantom: PhantomData<&'d mut T>, + pending_byte: Option, } impl<'d, T: Instance> I2cSlave<'d, T> { @@ -96,7 +113,19 @@ impl<'d, T: Instance> I2cSlave<'d, T> { w.set_master_mode(false); w.set_ic_slave_disable(false); w.set_tx_empty_ctrl(true); + w.set_rx_fifo_full_hld_ctrl(true); + + // This typically makes no sense for a slave, but it is used to + // tune spike suppression, according to the datasheet. + w.set_speed(pac::i2c::vals::Speed::FAST); + + // Generate stop interrupts for general calls + // This also causes stop interrupts for other devices on the bus but those will not be + // propagated up to the application. + w.set_stop_det_ifaddressed(!config.general_call); }); + p.ic_ack_general_call() + .write(|w| w.set_ack_gen_call(config.general_call)); // Set FIFO watermarks to 1 to make things simpler. This is encoded // by a register value of 0. Rx watermark should never change, but Tx watermark will be @@ -119,7 +148,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { phantom: PhantomData } + Self { + phantom: PhantomData, + pending_byte: None, + } } /// Calls `f` to check if we are ready or not. @@ -133,8 +165,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { future::poll_fn(|cx| { let r = f(self); - trace!("intr p: {:013b}", T::regs().ic_raw_intr_stat().read().0); - if r.is_pending() { T::waker().register(cx.waker()); g(self); @@ -146,14 +176,36 @@ impl<'d, T: Instance> I2cSlave<'d, T> { } #[inline(always)] - fn drain_fifo(&mut self, buffer: &mut [u8], offset: usize) -> usize { + fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) { let p = T::regs(); - let len = p.ic_rxflr().read().rxflr() as usize; - let end = offset + len; - for i in offset..end { - buffer[i] = p.ic_data_cmd().read().dat(); + + for b in &mut buffer[*offset..] { + if let Some(pending) = self.pending_byte.take() { + *b = pending; + *offset += 1; + continue; + } + + let status = p.ic_status().read(); + if !status.rfne() { + break; + } + + let dat = p.ic_data_cmd().read(); + if *offset != 0 && dat.first_data_byte() { + // The RP2040 state machine will keep placing bytes into the + // FIFO, even if they are part of a subsequent write transaction. + // + // Unfortunately merely reading ic_data_cmd will consume that + // byte, the first byte of the next transaction, so we need + // to store it elsewhere + self.pending_byte = Some(dat.dat()); + break; + } + + *b = dat.dat(); + *offset += 1; } - end } #[inline(always)] @@ -165,52 +217,62 @@ impl<'d, T: Instance> I2cSlave<'d, T> { } /// Wait asynchronously for commands from an I2C master. - /// `buffer` is provided in case master does a 'write' and is unused for 'read'. + /// `buffer` is provided in case master does a 'write', 'write read', or 'general call' and is unused for 'read'. pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { let p = T::regs(); - p.ic_clr_intr().read(); // set rx fifo watermark to 1 byte p.ic_rx_tl().write(|w| w.set_rx_tl(0)); let mut len = 0; - let ret = self - .wait_on( - |me| { - let stat = p.ic_raw_intr_stat().read(); - if p.ic_rxflr().read().rxflr() > 0 { - len = me.drain_fifo(buffer, len); - // we're recieving data, set rx fifo watermark to 12 bytes to reduce interrupt noise - p.ic_rx_tl().write(|w| w.set_rx_tl(11)); - } + self.wait_on( + |me| { + let stat = p.ic_raw_intr_stat().read(); - if stat.restart_det() && stat.rd_req() { - Poll::Ready(Ok(Command::WriteRead(len))) - } else if stat.gen_call() && stat.stop_det() && len > 0 { - Poll::Ready(Ok(Command::GeneralCall(len))) - } else if stat.stop_det() { - Poll::Ready(Ok(Command::Write(len))) - } else if stat.rd_req() { - Poll::Ready(Ok(Command::Read)) + if p.ic_rxflr().read().rxflr() > 0 { + me.drain_fifo(buffer, &mut len); + // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise + p.ic_rx_tl().write(|w| w.set_rx_tl(11)); + } + + if buffer.len() == len { + if stat.gen_call() { + return Poll::Ready(Err(Error::PartialGeneralCall(buffer.len()))); } else { - Poll::Pending + return Poll::Ready(Err(Error::PartialWrite(buffer.len()))); } - }, - |_me| { - p.ic_intr_mask().modify(|w| { - w.set_m_stop_det(true); - w.set_m_restart_det(true); - w.set_m_gen_call(true); - w.set_m_rd_req(true); - w.set_m_rx_full(true); - }); - }, - ) - .await; + } - p.ic_clr_intr().read(); - - ret + if stat.restart_det() && stat.rd_req() { + p.ic_clr_restart_det().read(); + Poll::Ready(Ok(Command::WriteRead(len))) + } else if stat.gen_call() && stat.stop_det() && len > 0 { + p.ic_clr_gen_call().read(); + p.ic_clr_stop_det().read(); + Poll::Ready(Ok(Command::GeneralCall(len))) + } else if stat.stop_det() && len > 0 { + p.ic_clr_stop_det().read(); + Poll::Ready(Ok(Command::Write(len))) + } else if stat.rd_req() { + p.ic_clr_stop_det().read(); + p.ic_clr_restart_det().read(); + p.ic_clr_gen_call().read(); + Poll::Ready(Ok(Command::Read)) + } else { + Poll::Pending + } + }, + |_me| { + p.ic_intr_mask().modify(|w| { + w.set_m_stop_det(true); + w.set_m_restart_det(true); + w.set_m_gen_call(true); + w.set_m_rd_req(true); + w.set_m_rx_full(true); + }); + }, + ) + .await } /// Respond to an I2C master READ command, asynchronously. @@ -223,47 +285,47 @@ impl<'d, T: Instance> I2cSlave<'d, T> { let mut chunks = buffer.chunks(FIFO_SIZE as usize); - let ret = self - .wait_on( - |me| { - if let Err(abort_reason) = me.read_and_clear_abort_reason() { - if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { - return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); - } else { - return Poll::Ready(Err(abort_reason)); - } - } - - if let Some(chunk) = chunks.next() { - me.write_to_fifo(chunk); - - Poll::Pending + self.wait_on( + |me| { + if let Err(abort_reason) = me.read_and_clear_abort_reason() { + if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { + p.ic_clr_intr().read(); + return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); } else { - let stat = p.ic_raw_intr_stat().read(); - - if stat.rx_done() && stat.stop_det() { - Poll::Ready(Ok(ReadStatus::Done)) - } else if stat.rd_req() { - Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) - } else { - Poll::Pending - } + return Poll::Ready(Err(abort_reason)); } - }, - |_me| { - p.ic_intr_mask().modify(|w| { - w.set_m_stop_det(true); - w.set_m_rx_done(true); - w.set_m_tx_empty(true); - w.set_m_tx_abrt(true); - }) - }, - ) - .await; + } - p.ic_clr_intr().read(); + if let Some(chunk) = chunks.next() { + me.write_to_fifo(chunk); - ret + p.ic_clr_rd_req().read(); + + Poll::Pending + } else { + let stat = p.ic_raw_intr_stat().read(); + + if stat.rx_done() && stat.stop_det() { + p.ic_clr_rx_done().read(); + p.ic_clr_stop_det().read(); + Poll::Ready(Ok(ReadStatus::Done)) + } else if stat.rd_req() && stat.tx_empty() { + Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) + } else { + Poll::Pending + } + } + }, + |_me| { + p.ic_intr_mask().modify(|w| { + w.set_m_stop_det(true); + w.set_m_rx_done(true); + w.set_m_tx_empty(true); + w.set_m_tx_abrt(true); + }) + }, + ) + .await } /// Respond to reads with the fill byte until the controller stops asking @@ -294,10 +356,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { let p = T::regs(); let mut abort_reason = p.ic_tx_abrt_source().read(); - // Mask off fifo flush count - let tx_flush_cnt = abort_reason.tx_flush_cnt(); - abort_reason.set_tx_flush_cnt(0); - // Mask off master_dis abort_reason.set_abrt_master_dis(false); @@ -314,8 +372,8 @@ impl<'d, T: Instance> I2cSlave<'d, T> { AbortReason::NoAcknowledge } else if abort_reason.arb_lost() { AbortReason::ArbitrationLoss - } else if abort_reason.abrt_slvflush_txfifo() { - AbortReason::TxNotEmpty(tx_flush_cnt) + } else if abort_reason.tx_flush_cnt() > 0 { + AbortReason::TxNotEmpty(abort_reason.tx_flush_cnt()) } else { AbortReason::Other(abort_reason.0) }; diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs index ac470d2be..9fffb4646 100644 --- a/examples/rp/src/bin/i2c_slave.rs +++ b/examples/rp/src/bin/i2c_slave.rs @@ -110,7 +110,7 @@ async fn main(spawner: Spawner) { let c_sda = p.PIN_1; let c_scl = p.PIN_0; let mut config = i2c::Config::default(); - config.frequency = 5_000; + config.frequency = 1_000_000; let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); unwrap!(spawner.spawn(controller_task(controller))); From 396041ad1a954a09bb2cf45ea685ca8a1bbd8623 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 16 Feb 2024 00:04:35 +0100 Subject: [PATCH 465/760] Commented out currently unused constants --- embassy-stm32/src/rcc/g4.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index edd14ab23..c9ac2bb0b 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -357,13 +357,13 @@ mod max { pub(crate) const HSE_BYP: RangeInclusive = Hertz(0)..=Hertz(48_000_000); /// SYSCLK ?-170MHz (RM0440 p282) - pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); + //pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); /// PLL Output frequency ?-170MHz (RM0440 p281) - pub(crate) const PCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); + //pub(crate) const PCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); // Left over from f.rs, remove if not necessary - pub(crate) const HCLK: RangeInclusive = Hertz(12_500_000)..=Hertz(216_000_000); - pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(2_100_000); - pub(crate) const PLL_VCO: RangeInclusive = Hertz(100_000_000)..=Hertz(432_000_000); + //pub(crate) const HCLK: RangeInclusive = Hertz(12_500_000)..=Hertz(216_000_000); + //pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(2_100_000); + //pub(crate) const PLL_VCO: RangeInclusive = Hertz(100_000_000)..=Hertz(432_000_000); } From a75007f5ccff25e5bc3afcc806ceb197f61be0bf Mon Sep 17 00:00:00 2001 From: DafabHoid Date: Fri, 16 Feb 2024 00:30:24 +0100 Subject: [PATCH 466/760] cyw43: Reuse buf to reduce stack usage --- cyw43/src/runner.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index b2a9e3e80..c72cf0def 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -242,13 +242,12 @@ where cmd, iface, }) => { - self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await; + self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await; self.check_status(&mut buf).await; } Either3::Second(packet) => { trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); - let mut buf = [0; 512]; let buf8 = slice8_mut(&mut buf); // There MUST be 2 bytes of padding between the SDPCM and BDC headers. @@ -480,9 +479,8 @@ where self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 } - async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) { - let mut buf = [0; 512]; - let buf8 = slice8_mut(&mut buf); + async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8], buf: &mut [u32; 512]) { + let buf8 = slice8_mut(buf); let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); From 72e92647e2634958d2229f35264a3dc696c3d33e Mon Sep 17 00:00:00 2001 From: Adam Snaider Date: Thu, 15 Feb 2024 18:10:20 -0500 Subject: [PATCH 467/760] Add unsafe constructor for AnyPin --- embassy-rp/src/gpio.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 93b29bbf9..a121a8036 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -889,6 +889,17 @@ pub struct AnyPin { pin_bank: u8, } +impl AnyPin { + /// Unsafely create a new type-erased pin. + /// + /// # Safety + /// + /// You must ensure that you’re only using one instance of this type at a time. + pub unsafe fn steal(pin_bank: u8) -> Self { + Self { pin_bank } + } +} + impl_peripheral!(AnyPin); impl Pin for AnyPin {} From ae02467434a344abbbb367123044c5e407c80a14 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 16 Feb 2024 02:07:21 +0100 Subject: [PATCH 468/760] stm32: update metapac. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/build.rs | 76 ++++++++++++------------------------ embassy-stm32/src/rcc/wba.rs | 2 +- 3 files changed, 27 insertions(+), 55 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index c384f14f1..389ed0041 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,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-3cc1a1603e61881a6f0a1a47c12c16c57c245ba8" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6097928f720646c73d6483a3245f922bd5faee2f" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-3cc1a1603e61881a6f0a1a47c12c16c57c245ba8", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6097928f720646c73d6483a3245f922bd5faee2f", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 35023bf1f..ee88d4541 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -5,8 +5,7 @@ use std::{env, fs}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use stm32_metapac::metadata::ir::{BlockItemInner, Enum, FieldSet}; -use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, StopMode, METADATA}; +use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccKernelClock, StopMode, METADATA}; fn main() { let target = env::var("TARGET").unwrap(); @@ -414,38 +413,6 @@ fn main() { .find(|r| r.kind == "rcc") .unwrap(); - // ======== - // Generate rcc fieldset and enum maps - let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = { - let rcc_blocks = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap().items; - let rcc_fieldsets: HashMap<&str, &FieldSet> = rcc_registers.ir.fieldsets.iter().map(|f| (f.name, f)).collect(); - let rcc_enums: HashMap<&str, &Enum> = rcc_registers.ir.enums.iter().map(|e| (e.name, e)).collect(); - - rcc_blocks - .iter() - .filter_map(|b| match &b.inner { - BlockItemInner::Register(register) => register.fieldset.map(|f| (b.name, f)), - _ => None, - }) - .filter_map(|(b, f)| { - rcc_fieldsets.get(f).map(|f| { - ( - b, - f.fields - .iter() - .filter_map(|f| { - let enumm = f.enumm?; - let enumm = rcc_enums.get(enumm)?; - - Some((f.name, *enumm)) - }) - .collect(), - ) - }) - }) - .collect() - }; - // ======== // Generate RccPeripheral impls @@ -494,8 +461,8 @@ fn main() { let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; let pname = format_ident!("{}", p.name); - let en_reg = format_ident!("{}", en.register); - let set_en_field = format_ident!("set_{}", en.field); + let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); + let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); let refcount = force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; @@ -523,21 +490,25 @@ fn main() { (TokenStream::new(), TokenStream::new()) }; - let mux_for = |mux: Option<&'static PeripheralRccRegister>| { - let mux = mux?; - let fieldset = rcc_enum_map.get(mux.register)?; - let enumm = fieldset.get(mux.field)?; + let clock_frequency = match &rcc.kernel_clock { + PeripheralRccKernelClock::Mux(mux) => { + let ir = &rcc_registers.ir; + let fieldset_name = mux.register.to_ascii_lowercase(); + let fieldset = ir + .fieldsets + .iter() + .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name)) + .unwrap(); + let field_name = mux.field.to_ascii_lowercase(); + let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap(); + let enum_name = field.enumm.unwrap(); + let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap(); - Some((mux, *enumm)) - }; + let fieldset_name = format_ident!("{}", fieldset_name); + let field_name = format_ident!("{}", field_name); + let enum_name = format_ident!("{}", enum_name); - let clock_frequency = match mux_for(rcc.mux.as_ref()) { - Some((mux, rcc_enumm)) => { - let fieldset_name = format_ident!("{}", mux.register); - let field_name = format_ident!("{}", mux.field); - let enum_name = format_ident!("{}", rcc_enumm.name); - - let match_arms: TokenStream = rcc_enumm + let match_arms: TokenStream = enumm .variants .iter() .filter(|v| v.name != "DISABLE") @@ -561,9 +532,10 @@ fn main() { } } } - None => { - let clock_name = format_ident!("{}", rcc.clock); - clock_names.insert(rcc.clock.to_string()); + PeripheralRccKernelClock::Clock(clock) => { + let clock = clock.to_ascii_lowercase(); + let clock_name = format_ident!("{}", clock); + clock_names.insert(clock.to_string()); quote! { unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } } diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 47ce4783c..fbf2d1cf9 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -49,7 +49,7 @@ impl Default for Config { apb2_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1, ls: Default::default(), - adc_clock_source: AdcClockSource::HCLK1, + adc_clock_source: AdcClockSource::HCLK4, voltage_scale: VoltageScale::RANGE2, } } From 169f1ce928177a6ff85ce7e9ff5a995063b6aace Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Thu, 15 Feb 2024 19:50:42 -0800 Subject: [PATCH 469/760] I believe that this enables the PLL clock input to different TIMs for the STM32F3xx Series of chips. --- embassy-stm32/src/rcc/f013.rs | 241 ++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index c2933186c..0d2877755 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -74,6 +74,107 @@ pub enum HrtimClockSource { PllClk, } +#[cfg(all(stm32f3, not(rcc_f37)))] +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum TimClockSource { + PClk2, + PllClk, +} + +#[cfg(all(stm32f3, not(rcc_f37)))] +#[derive(Clone, Copy)] +pub struct TimClockSources { + pub tim1: TimClockSource, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + ))] + pub tim2: TimClockSource, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + ))] + pub tim34: TimClockSource, + #[cfg(any( + all(stm32f303, any(package_B, package_C, package_D, package_E)), + stm32f358, + ))] + pub tim8: TimClockSource, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] + pub tim15: TimClockSource, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] + pub tim16: TimClockSource, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] + pub tim17: TimClockSource, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + ))] + pub tim20: TimClockSource +} + +impl Default for TimClockSources { + fn default() -> Self { + Self { + tim1: TimClockSource::PClk2, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + ))] + tim2: TimClockSource::PClk2, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + ))] + tim34: TimClockSource::PClk2, + #[cfg(any( + all(stm32f303, any(package_B, package_C, package_D, package_E)), + stm32f358, + ))] + tim8: TimClockSource::PClk2, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] + tim15: TimClockSource::PClk2, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] + tim16: TimClockSource::PClk2, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] + tim17: TimClockSource::PClk2, + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + ))] + tim20: TimClockSource::PClk2 + } + } +} + /// Clocks configutation #[non_exhaustive] pub struct Config { @@ -99,6 +200,8 @@ pub struct Config { pub adc34: AdcClockSource, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, + #[cfg(not(stm32f37))] + pub tim: TimClockSources, pub ls: super::LsConfig, } @@ -129,6 +232,8 @@ impl Default for Config { adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(stm32f334)] hrtim: HrtimClockSource::BusClk, + #[cfg(not(stm32f37))] + tim: Default::default() } } } @@ -364,6 +469,126 @@ pub(crate) unsafe fn init(config: Config) { } }; + #[cfg(all(stm32f3, not(rcc_f37)))] + let tim1 = match config.tim.tim1 { + TimClockSource::PClk2 => None, + TimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + let pll = unwrap!(pll); + assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + + RCC.cfgr3().modify(|w| w.set_tim1(Timsw::PLL1_P)); + + Some(pll * 2u32) + } + }; + + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + let tim2 = match config.tim.tim2 { + TimClockSource::PClk2 => None, + TimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + let pll = unwrap!(pll); + assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + + RCC.cfgr3().modify(|w| w.set_tim2(Timsw::PLL1_P)); + + Some(pll * 2u32) + } + }; + + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + let tim34 = match config.tim.tim34 { + TimClockSource::PClk2 => None, + TimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + let pll = unwrap!(pll); + assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + + RCC.cfgr3().modify(|w| w.set_tim34(Timsw::PLL1_P)); + + Some(pll * 2u32) + } + }; + + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] + let tim8 = match config.tim.tim8 { + TimClockSource::PClk2 => None, + TimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + let pll = unwrap!(pll); + assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + + RCC.cfgr3().modify(|w| w.set_tim8(Timsw::PLL1_P)); + + Some(pll * 2u32) + } + }; + + #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + let tim15 = match config.tim.tim15 { + TimClockSource::PClk2 => None, + TimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + let pll = unwrap!(pll); + assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + + RCC.cfgr3().modify(|w| w.set_tim15(Timsw::PLL1_P)); + + Some(pll * 2u32) + } + }; + + #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + let tim16 = match config.tim.tim16 { + TimClockSource::PClk2 => None, + TimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + let pll = unwrap!(pll); + assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + + RCC.cfgr3().modify(|w| w.set_tim16(Timsw::PLL1_P)); + + Some(pll * 2u32) + } + }; + + #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + let tim17 = match config.tim.tim17 { + TimClockSource::PClk2 => None, + TimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + let pll = unwrap!(pll); + assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + + RCC.cfgr3().modify(|w| w.set_tim17(Timsw::PLL1_P)); + + Some(pll * 2u32) + } + }; + + #[cfg(any(all(stm32f303, any(package_D, package_E))))] + let tim20 = match config.tim.tim20 { + TimClockSource::PClk2 => None, + TimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + let pll = unwrap!(pll); + assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + + RCC.cfgr3().modify(|w| w.set_tim20(Timsw::PLL1_P)); + + Some(pll * 2u32) + } + }; + set_clocks!( hsi: hsi, hse: hse, @@ -380,6 +605,22 @@ pub(crate) unsafe fn init(config: Config) { adc34: Some(adc34), #[cfg(stm32f334)] hrtim: hrtim, + #[cfg(all(stm32f3, not(rcc_f37)))] + tim1: tim1, + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + tim2: tim2, + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + tim34: tim34, + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] + tim8: tim8, + #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + tim15: tim15, + #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + tim16: tim16, + #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + tim17: tim17, + #[cfg(any(all(stm32f303, any(package_D, package_E))))] + tim20: tim20, rtc: rtc, hsi48: hsi48, #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] From 029d6383b56c45167b99ef5c5c862946410d8f52 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Thu, 15 Feb 2024 20:02:25 -0800 Subject: [PATCH 470/760] Rust fmt and fix build. --- embassy-stm32/src/rcc/f013.rs | 97 ++++++++++++++++------------------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 0d2877755..766a4a0f5 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -85,20 +85,11 @@ pub enum TimClockSource { #[derive(Clone, Copy)] pub struct TimClockSources { pub tim1: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - ))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)),))] pub tim2: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - ))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)),))] pub tim34: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_B, package_C, package_D, package_E)), - stm32f358, - ))] + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358,))] pub tim8: TimClockSource, #[cfg(any( all(stm32f303, any(package_D, package_E)), @@ -121,30 +112,19 @@ pub struct TimClockSources { all(stm32f302, any(package_6, package_8)) ))] pub tim17: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - ))] - pub tim20: TimClockSource + #[cfg(any(all(stm32f303, any(package_D, package_E)),))] + pub tim20: TimClockSource, } impl Default for TimClockSources { fn default() -> Self { Self { tim1: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - ))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)),))] tim2: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - ))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)),))] tim34: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_B, package_C, package_D, package_E)), - stm32f358, - ))] + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358,))] tim8: TimClockSource::PClk2, #[cfg(any( all(stm32f303, any(package_D, package_E)), @@ -167,10 +147,8 @@ impl Default for TimClockSources { all(stm32f302, any(package_6, package_8)) ))] tim17: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - ))] - tim20: TimClockSource::PClk2 + #[cfg(any(all(stm32f303, any(package_D, package_E)),))] + tim20: TimClockSource::PClk2, } } } @@ -233,7 +211,7 @@ impl Default for Config { #[cfg(stm32f334)] hrtim: HrtimClockSource::BusClk, #[cfg(not(stm32f37))] - tim: Default::default() + tim: Default::default(), } } } @@ -476,9 +454,9 @@ pub(crate) unsafe fn init(config: Config) { use crate::pac::rcc::vals::Timsw; let pll = unwrap!(pll); - assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - RCC.cfgr3().modify(|w| w.set_tim1(Timsw::PLL1_P)); + RCC.cfgr3().modify(|w| w.set_tim1sw(Timsw::PLL1_P)); Some(pll * 2u32) } @@ -491,9 +469,9 @@ pub(crate) unsafe fn init(config: Config) { use crate::pac::rcc::vals::Timsw; let pll = unwrap!(pll); - assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - RCC.cfgr3().modify(|w| w.set_tim2(Timsw::PLL1_P)); + RCC.cfgr3().modify(|w| w.set_tim2sw(Timsw::PLL1_P)); Some(pll * 2u32) } @@ -506,9 +484,9 @@ pub(crate) unsafe fn init(config: Config) { use crate::pac::rcc::vals::Timsw; let pll = unwrap!(pll); - assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - RCC.cfgr3().modify(|w| w.set_tim34(Timsw::PLL1_P)); + RCC.cfgr3().modify(|w| w.set_tim34sw(Timsw::PLL1_P)); Some(pll * 2u32) } @@ -521,54 +499,69 @@ pub(crate) unsafe fn init(config: Config) { use crate::pac::rcc::vals::Timsw; let pll = unwrap!(pll); - assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - RCC.cfgr3().modify(|w| w.set_tim8(Timsw::PLL1_P)); + RCC.cfgr3().modify(|w| w.set_tim8sw(Timsw::PLL1_P)); Some(pll * 2u32) } }; - #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] let tim15 = match config.tim.tim15 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { use crate::pac::rcc::vals::Timsw; let pll = unwrap!(pll); - assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - RCC.cfgr3().modify(|w| w.set_tim15(Timsw::PLL1_P)); + RCC.cfgr3().modify(|w| w.set_tim15sw(Timsw::PLL1_P)); Some(pll * 2u32) } }; - #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] let tim16 = match config.tim.tim16 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { use crate::pac::rcc::vals::Timsw; let pll = unwrap!(pll); - assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - RCC.cfgr3().modify(|w| w.set_tim16(Timsw::PLL1_P)); + RCC.cfgr3().modify(|w| w.set_tim16sw(Timsw::PLL1_P)); Some(pll * 2u32) } }; - #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + stm32f301, + stm32f318, + all(stm32f302, any(package_6, package_8)) + ))] let tim17 = match config.tim.tim17 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { use crate::pac::rcc::vals::Timsw; let pll = unwrap!(pll); - assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - RCC.cfgr3().modify(|w| w.set_tim17(Timsw::PLL1_P)); + RCC.cfgr3().modify(|w| w.set_tim17sw(Timsw::PLL1_P)); Some(pll * 2u32) } @@ -581,9 +574,9 @@ pub(crate) unsafe fn init(config: Config) { use crate::pac::rcc::vals::Timsw; let pll = unwrap!(pll); - assert((pclk2 == pll) || (pclk2 * 2u32 == pll)); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - RCC.cfgr3().modify(|w| w.set_tim20(Timsw::PLL1_P)); + RCC.cfgr3().modify(|w| w.set_tim20sw(Timsw::PLL1_P)); Some(pll * 2u32) } From f41b0f6ba95d0323f058a1ec2a2dc9b6f3317fee Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 15 Feb 2024 23:06:57 -0500 Subject: [PATCH 471/760] Remove unused imports --- embassy-rp/src/i2c_slave.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index d3cc20f39..979686627 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -4,7 +4,6 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; -use embassy_time::{block_for, Duration}; use pac::i2c; use crate::i2c::{ From 4408c169a5c3961f1a5163ce6c09762988c1a471 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Thu, 15 Feb 2024 22:53:00 -0800 Subject: [PATCH 472/760] Fix cfg lines --- embassy-stm32/src/rcc/f013.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 766a4a0f5..b5ec8585e 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -116,6 +116,7 @@ pub struct TimClockSources { pub tim20: TimClockSource, } +#[cfg(all(stm32f3, not(rcc_f37)))] impl Default for TimClockSources { fn default() -> Self { Self { @@ -178,7 +179,7 @@ pub struct Config { pub adc34: AdcClockSource, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, - #[cfg(not(stm32f37))] + #[cfg(all(stm32f3, not(stm32f37)))] pub tim: TimClockSources, pub ls: super::LsConfig, @@ -210,7 +211,7 @@ impl Default for Config { adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(stm32f334)] hrtim: HrtimClockSource::BusClk, - #[cfg(not(stm32f37))] + #[cfg(all(stm32f3, not(stm32f37)))] tim: Default::default(), } } From 56b345c722aa22e778eb8551c4d019441bf5520e Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Thu, 15 Feb 2024 23:12:18 -0800 Subject: [PATCH 473/760] Clean up register setting --- embassy-stm32/src/rcc/f013.rs | 118 +++++++--------------------------- 1 file changed, 23 insertions(+), 95 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index b5ec8585e..2352b057d 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -179,7 +179,7 @@ pub struct Config { pub adc34: AdcClockSource, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, - #[cfg(all(stm32f3, not(stm32f37)))] + #[cfg(all(stm32f3, not(rcc_f37)))] pub tim: TimClockSources, pub ls: super::LsConfig, @@ -449,62 +449,34 @@ pub(crate) unsafe fn init(config: Config) { }; #[cfg(all(stm32f3, not(rcc_f37)))] - let tim1 = match config.tim.tim1 { - TimClockSource::PClk2 => None, + match config.tim.tim1 { + TimClockSource::PClk2 => {}, TimClockSource::PllClk => { - use crate::pac::rcc::vals::Timsw; - - let pll = unwrap!(pll); - assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - - RCC.cfgr3().modify(|w| w.set_tim1sw(Timsw::PLL1_P)); - - Some(pll * 2u32) + RCC.cfgr3().modify(|w| w.set_tim1sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] - let tim2 = match config.tim.tim2 { - TimClockSource::PClk2 => None, + match config.tim.tim2 { + TimClockSource::PClk2 => {}, TimClockSource::PllClk => { - use crate::pac::rcc::vals::Timsw; - - let pll = unwrap!(pll); - assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - - RCC.cfgr3().modify(|w| w.set_tim2sw(Timsw::PLL1_P)); - - Some(pll * 2u32) + RCC.cfgr3().modify(|w| w.set_tim2sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] - let tim34 = match config.tim.tim34 { - TimClockSource::PClk2 => None, + match config.tim.tim34 { + TimClockSource::PClk2 => {}, TimClockSource::PllClk => { - use crate::pac::rcc::vals::Timsw; - - let pll = unwrap!(pll); - assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - - RCC.cfgr3().modify(|w| w.set_tim34sw(Timsw::PLL1_P)); - - Some(pll * 2u32) + RCC.cfgr3().modify(|w| w.set_tim34sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] - let tim8 = match config.tim.tim8 { - TimClockSource::PClk2 => None, + match config.tim.tim8 { + TimClockSource::PClk2 => {}, TimClockSource::PllClk => { - use crate::pac::rcc::vals::Timsw; - - let pll = unwrap!(pll); - assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - - RCC.cfgr3().modify(|w| w.set_tim8sw(Timsw::PLL1_P)); - - Some(pll * 2u32) + RCC.cfgr3().modify(|w| w.set_tim8sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; @@ -514,17 +486,10 @@ pub(crate) unsafe fn init(config: Config) { stm32f318, all(stm32f302, any(package_6, package_8)) ))] - let tim15 = match config.tim.tim15 { + match config.tim.tim15 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { - use crate::pac::rcc::vals::Timsw; - - let pll = unwrap!(pll); - assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - - RCC.cfgr3().modify(|w| w.set_tim15sw(Timsw::PLL1_P)); - - Some(pll * 2u32) + RCC.cfgr3().modify(|w| w.set_tim15sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; @@ -534,17 +499,10 @@ pub(crate) unsafe fn init(config: Config) { stm32f318, all(stm32f302, any(package_6, package_8)) ))] - let tim16 = match config.tim.tim16 { + match config.tim.tim16 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { - use crate::pac::rcc::vals::Timsw; - - let pll = unwrap!(pll); - assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - - RCC.cfgr3().modify(|w| w.set_tim16sw(Timsw::PLL1_P)); - - Some(pll * 2u32) + RCC.cfgr3().modify(|w| w.set_tim16sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; @@ -554,34 +512,20 @@ pub(crate) unsafe fn init(config: Config) { stm32f318, all(stm32f302, any(package_6, package_8)) ))] - let tim17 = match config.tim.tim17 { + match config.tim.tim17 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { - use crate::pac::rcc::vals::Timsw; - - let pll = unwrap!(pll); - assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - - RCC.cfgr3().modify(|w| w.set_tim17sw(Timsw::PLL1_P)); - - Some(pll * 2u32) + RCC.cfgr3().modify(|w| w.set_tim17sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } - }; + } #[cfg(any(all(stm32f303, any(package_D, package_E))))] - let tim20 = match config.tim.tim20 { + match config.tim.tim20 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { - use crate::pac::rcc::vals::Timsw; - - let pll = unwrap!(pll); - assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); - - RCC.cfgr3().modify(|w| w.set_tim20sw(Timsw::PLL1_P)); - - Some(pll * 2u32) + RCC.cfgr3().modify(|w| w.set_tim20sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } - }; + } set_clocks!( hsi: hsi, @@ -599,22 +543,6 @@ pub(crate) unsafe fn init(config: Config) { adc34: Some(adc34), #[cfg(stm32f334)] hrtim: hrtim, - #[cfg(all(stm32f3, not(rcc_f37)))] - tim1: tim1, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] - tim2: tim2, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] - tim34: tim34, - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] - tim8: tim8, - #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] - tim15: tim15, - #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] - tim16: tim16, - #[cfg(any(all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, all(stm32f302, any(package_6, package_8))))] - tim17: tim17, - #[cfg(any(all(stm32f303, any(package_D, package_E))))] - tim20: tim20, rtc: rtc, hsi48: hsi48, #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] From d28ba1d60689e5a0d5623c5ea4890663d899523a Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Thu, 15 Feb 2024 23:16:17 -0800 Subject: [PATCH 474/760] rustfmt --- embassy-stm32/src/rcc/f013.rs | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 2352b057d..17c734f09 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -204,14 +204,13 @@ impl Default for Config { // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz) adc_pre: ADCPrescaler::DIV6, - #[cfg(all(stm32f3, not(rcc_f37)))] adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(stm32f334)] hrtim: HrtimClockSource::BusClk, - #[cfg(all(stm32f3, not(stm32f37)))] + #[cfg(all(stm32f3, not(rcc_f37)))] tim: Default::default(), } } @@ -450,33 +449,37 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(all(stm32f3, not(rcc_f37)))] match config.tim.tim1 { - TimClockSource::PClk2 => {}, + TimClockSource::PClk2 => {} TimClockSource::PllClk => { - RCC.cfgr3().modify(|w| w.set_tim1sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + RCC.cfgr3() + .modify(|w| w.set_tim1sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] match config.tim.tim2 { - TimClockSource::PClk2 => {}, + TimClockSource::PClk2 => {} TimClockSource::PllClk => { - RCC.cfgr3().modify(|w| w.set_tim2sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + RCC.cfgr3() + .modify(|w| w.set_tim2sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] match config.tim.tim34 { - TimClockSource::PClk2 => {}, + TimClockSource::PClk2 => {} TimClockSource::PllClk => { - RCC.cfgr3().modify(|w| w.set_tim34sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + RCC.cfgr3() + .modify(|w| w.set_tim34sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] match config.tim.tim8 { - TimClockSource::PClk2 => {}, + TimClockSource::PClk2 => {} TimClockSource::PllClk => { - RCC.cfgr3().modify(|w| w.set_tim8sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + RCC.cfgr3() + .modify(|w| w.set_tim8sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; @@ -489,7 +492,8 @@ pub(crate) unsafe fn init(config: Config) { match config.tim.tim15 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { - RCC.cfgr3().modify(|w| w.set_tim15sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + RCC.cfgr3() + .modify(|w| w.set_tim15sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; @@ -502,7 +506,8 @@ pub(crate) unsafe fn init(config: Config) { match config.tim.tim16 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { - RCC.cfgr3().modify(|w| w.set_tim16sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + RCC.cfgr3() + .modify(|w| w.set_tim16sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } }; @@ -515,7 +520,8 @@ pub(crate) unsafe fn init(config: Config) { match config.tim.tim17 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { - RCC.cfgr3().modify(|w| w.set_tim17sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + RCC.cfgr3() + .modify(|w| w.set_tim17sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } } @@ -523,7 +529,8 @@ pub(crate) unsafe fn init(config: Config) { match config.tim.tim20 { TimClockSource::PClk2 => None, TimClockSource::PllClk => { - RCC.cfgr3().modify(|w| w.set_tim20sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + RCC.cfgr3() + .modify(|w| w.set_tim20sw(crate::pac::rcc::vals::Timsw::PLL1_P)); } } From d7623c79291cfba562f9881e062180d5c92b875e Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Thu, 15 Feb 2024 23:20:35 -0800 Subject: [PATCH 475/760] Remove extraneous , in cfg --- embassy-stm32/src/rcc/f013.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 17c734f09..4d5116a56 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -85,11 +85,11 @@ pub enum TimClockSource { #[derive(Clone, Copy)] pub struct TimClockSources { pub tim1: TimClockSource, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)),))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] pub tim2: TimClockSource, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)),))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] pub tim34: TimClockSource, - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358,))] + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] pub tim8: TimClockSource, #[cfg(any( all(stm32f303, any(package_D, package_E)), @@ -112,7 +112,7 @@ pub struct TimClockSources { all(stm32f302, any(package_6, package_8)) ))] pub tim17: TimClockSource, - #[cfg(any(all(stm32f303, any(package_D, package_E)),))] + #[cfg(any(all(stm32f303, any(package_D, package_E))))] pub tim20: TimClockSource, } @@ -121,11 +121,11 @@ impl Default for TimClockSources { fn default() -> Self { Self { tim1: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)),))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] tim2: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)),))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] tim34: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358,))] + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] tim8: TimClockSource::PClk2, #[cfg(any( all(stm32f303, any(package_D, package_E)), @@ -148,7 +148,7 @@ impl Default for TimClockSources { all(stm32f302, any(package_6, package_8)) ))] tim17: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_D, package_E)),))] + #[cfg(any(all(stm32f303, any(package_D, package_E))))] tim20: TimClockSource::PClk2, } } From bcb0be21c180d4107e636083f5a1543a1f51447b Mon Sep 17 00:00:00 2001 From: Frank Plowman Date: Fri, 16 Feb 2024 17:24:58 +0000 Subject: [PATCH 476/760] embassy-nrf: Fix PDM gain register value derivation Co-authored-by: Sol Harter --- embassy-nrf/src/pdm.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 24fa29a4a..64d414d8f 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -4,6 +4,7 @@ use core::future::poll_fn; use core::marker::PhantomData; +use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; @@ -145,15 +146,14 @@ impl<'d, T: Instance> Pdm<'d, T> { } fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) { - let gain_left = gain_left - .saturating_add(I7F1::from_bits(40)) - .saturating_to_num::() - .clamp(0, 0x50); - let gain_right = gain_right - .saturating_add(I7F1::from_bits(40)) - .saturating_to_num::() - .clamp(0, 0x50); - + let gain_to_bits = |gain: I7F1| -> u8 { + let gain = gain.saturating_add(I7F1::from_bits(0x28)) + .to_bits() + .clamp(0, 0x50); + unsafe { mem::transmute(gain) } + }; + let gain_left = gain_to_bits(gain_left); + let gain_right = gain_to_bits(gain_right); r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) }); r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) }); } From 32e4c93954abb3add1c9b2c8fff627c497d47258 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 16 Feb 2024 19:58:19 +0100 Subject: [PATCH 477/760] Removed dangling doc comments --- embassy-stm32/src/rcc/g4.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index c9ac2bb0b..5ac933af4 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -356,10 +356,10 @@ mod max { /// External Clock ?-48MHz (RM0440 p280) pub(crate) const HSE_BYP: RangeInclusive = Hertz(0)..=Hertz(48_000_000); - /// SYSCLK ?-170MHz (RM0440 p282) + // SYSCLK ?-170MHz (RM0440 p282) //pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); - /// PLL Output frequency ?-170MHz (RM0440 p281) + // PLL Output frequency ?-170MHz (RM0440 p281) //pub(crate) const PCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); // Left over from f.rs, remove if not necessary From ae748339999034854a78629c2e2f160d0d8417f9 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 16 Feb 2024 20:32:35 +0100 Subject: [PATCH 478/760] Removed redundant HSI48 configuration --- embassy-stm32/src/rcc/g4.rs | 32 ++++++++------------------ examples/stm32g4/src/bin/usb_serial.rs | 7 +++--- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 5ac933af4..7ca741fc7 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -3,8 +3,9 @@ use stm32_metapac::rcc::vals::{Adcsel, Sw}; use stm32_metapac::FLASH; pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Clk48sel, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, Pllm as PllPreDiv, - Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler, Sw as Sysclk, + Adcsel as AdcClockSource, Clk48sel as Clk48Src, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, + Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler, + Sw as Sysclk, }; use crate::pac::{PWR, RCC}; use crate::time::Hertz; @@ -53,17 +54,6 @@ pub struct Pll { pub divr: Option, } -/// Sets the source for the 48MHz clock to the USB and RNG peripherals. -pub enum Clock48MhzSrc { - /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the - /// oscillator to comply with the USB specification for oscillator tolerance. - Hsi48(super::Hsi48Config), - /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the - /// PLL needs to be using the HSE source to comply with the USB specification for oscillator - /// tolerance. - PllQ, -} - /// Clocks configutation #[non_exhaustive] pub struct Config { @@ -82,7 +72,7 @@ pub struct Config { pub low_power_run: bool, /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. - pub clk48_src: Option, + pub clk48_src: Clk48Src, pub ls: super::LsConfig, @@ -106,7 +96,7 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, low_power_run: false, - clk48_src: Some(Clock48MhzSrc::Hsi48(Default::default())), + clk48_src: Clk48Src::HSI48, ls: Default::default(), adc12_clock_source: Adcsel::DISABLE, adc345_clock_source: Adcsel::DISABLE, @@ -283,19 +273,17 @@ pub(crate) unsafe fn init(config: Config) { }; // Setup the 48 MHz clock if needed - if let Some(clock_48mhz_src) = config.clk48_src { - let source = match clock_48mhz_src { - Clock48MhzSrc::PllQ => { + { + let source = match config.clk48_src { + Clk48Src::PLL1_Q => { // Make sure the PLLQ is enabled and running at 48Mhz let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q); assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000); crate::pac::rcc::vals::Clk48sel::PLL1_Q } - Clock48MhzSrc::Hsi48(config) => { - super::init_hsi48(config); - crate::pac::rcc::vals::Clk48sel::HSI48 - } + Clk48Src::HSI48 => crate::pac::rcc::vals::Clk48sel::HSI48, + _ => unreachable!(), }; RCC.ccipr().modify(|w| w.set_clk48sel(source)); diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index d9207e4cd..353ac1799 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -4,7 +4,7 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::rcc::{ - Clock48MhzSrc, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk, + Clk48Src, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk, }; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; @@ -47,9 +47,10 @@ async fn main(_spawner: Spawner) { if USE_HSI48 { // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. - config.rcc.clk48_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true })); + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); + config.rcc.clk48_src = Clk48Src::HSI48; } else { - config.rcc.clk48_src = Some(Clock48MhzSrc::PllQ); + config.rcc.clk48_src = Clk48Src::PLL1_Q; } let p = embassy_stm32::init(config); From 25a95503f661f064e57854df8f831ad681868a4c Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 16 Feb 2024 20:41:04 +0100 Subject: [PATCH 479/760] Configured HSI48 if enabled, assert is enabled if chosen as clk48 source --- embassy-stm32/src/rcc/g4.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 7ca741fc7..22dfa25c6 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -145,6 +145,11 @@ pub(crate) unsafe fn init(config: Config) { } }; + // Configure HSI48 if required + if let Some(hsi48_config) = config.hsi48 { + super::init_hsi48(hsi48_config); + } + let pll_freq = config.pll.map(|pll_config| { let src_freq = match pll_config.source { Pllsrc::HSI => unwrap!(hsi), @@ -272,7 +277,7 @@ pub(crate) unsafe fn init(config: Config) { } }; - // Setup the 48 MHz clock if needed + // Configure the 48MHz clock source for USB and RNG peripherals. { let source = match config.clk48_src { Clk48Src::PLL1_Q => { @@ -282,7 +287,11 @@ pub(crate) unsafe fn init(config: Config) { crate::pac::rcc::vals::Clk48sel::PLL1_Q } - Clk48Src::HSI48 => crate::pac::rcc::vals::Clk48sel::HSI48, + Clk48Src::HSI48 => { + // Make sure HSI48 is enabled + assert!(config.hsi48.is_some()); + crate::pac::rcc::vals::Clk48sel::HSI48 + } _ => unreachable!(), }; From e465dacf739e499f64b7943f4674edfe060f83b7 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 16 Feb 2024 21:34:12 +0100 Subject: [PATCH 480/760] Added documentation, fixed and refined boost and flash read latency config --- embassy-stm32/src/rcc/g4.rs | 69 +++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 22dfa25c6..e2afd5260 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -13,6 +13,7 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(16_000_000); +/// HSE Mode #[derive(Clone, Copy, Eq, PartialEq)] pub enum HseMode { /// crystal/ceramic oscillator (HSEBYP=0) @@ -21,6 +22,7 @@ pub enum HseMode { Bypass, } +/// HSE Configuration #[derive(Clone, Copy, Eq, PartialEq)] pub struct Hse { /// HSE frequency. @@ -57,11 +59,19 @@ pub struct Pll { /// Clocks configutation #[non_exhaustive] pub struct Config { + /// HSI Enable pub hsi: bool, + + /// HSE Configuration pub hse: Option, + + /// System Clock Configuration pub sys: Sysclk, + + /// HSI48 Configuration pub hsi48: Option, + /// PLL Configuration pub pll: Option, /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration @@ -69,17 +79,26 @@ pub struct Config { pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, + pub low_power_run: bool, /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. pub clk48_src: Clk48Src, + /// Low-Speed Clock Configuration pub ls: super::LsConfig, + /// Clock Source for ADCs 1 and 2 pub adc12_clock_source: AdcClockSource, + + /// Clock Source for ADCs 3, 4 and 5 pub adc345_clock_source: AdcClockSource, + + /// Clock Source for FDCAN pub fdcan_clock_source: FdCanClockSource, + /// Enable range1 boost mode + /// Recommended when the SYSCLK frequency is greater than 150MHz. pub boost: bool, } @@ -217,36 +236,6 @@ pub(crate) unsafe fn init(config: Config) { assert!(freq <= 170_000_000); - if config.boost { - // Enable Core Boost mode ([RM0440] p234) - PWR.cr5().modify(|w| w.set_r1mode(false)); - if freq <= 36_000_000 { - FLASH.acr().modify(|w| w.set_latency(Latency::WS0)); - } else if freq <= 68_000_000 { - FLASH.acr().modify(|w| w.set_latency(Latency::WS1)); - } else if freq <= 102_000_000 { - FLASH.acr().modify(|w| w.set_latency(Latency::WS2)); - } else if freq <= 136_000_000 { - FLASH.acr().modify(|w| w.set_latency(Latency::WS3)); - } else { - FLASH.acr().modify(|w| w.set_latency(Latency::WS4)); - } - } else { - // Enable Core Boost mode ([RM0440] p234) - PWR.cr5().modify(|w| w.set_r1mode(true)); - if freq <= 30_000_000 { - FLASH.acr().modify(|w| w.set_latency(Latency::WS0)); - } else if freq <= 60_000_000 { - FLASH.acr().modify(|w| w.set_latency(Latency::WS1)); - } else if freq <= 80_000_000 { - FLASH.acr().modify(|w| w.set_latency(Latency::WS2)); - } else if freq <= 120_000_000 { - FLASH.acr().modify(|w| w.set_latency(Latency::WS3)); - } else { - FLASH.acr().modify(|w| w.set_latency(Latency::WS4)); - } - } - (Hertz(freq), Sw::PLL1_R) } _ => unreachable!(), @@ -261,6 +250,26 @@ pub(crate) unsafe fn init(config: Config) { let ahb_freq = sys_clk / config.ahb_pre; + // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) + PWR.cr5().modify(|w| w.set_r1mode(!config.boost)); + + // Configure flash read access latency based on boost mode and frequency (RM0440 p98) + FLASH.acr().modify(|w| { + w.set_latency(match (config.boost, ahb_freq.0) { + (true, ..=34_000_000) => Latency::WS0, + (true, ..=68_000_000) => Latency::WS1, + (true, ..=102_000_000) => Latency::WS2, + (true, ..=136_000_000) => Latency::WS3, + (true, _) => Latency::WS4, + + (false, ..=36_000_000) => Latency::WS0, + (false, ..=60_000_000) => Latency::WS1, + (false, ..=90_000_000) => Latency::WS2, + (false, ..=120_000_000) => Latency::WS3, + (false, _) => Latency::WS4, + }) + }); + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { From c5f39d5c89240d17b0d7c8ee48fc48757c163bba Mon Sep 17 00:00:00 2001 From: Frank Plowman Date: Fri, 16 Feb 2024 20:42:14 +0000 Subject: [PATCH 481/760] embassy-nrf: Use fully-qualified `core::mem::transmute` --- embassy-nrf/src/pdm.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 64d414d8f..d03315fb6 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -4,7 +4,6 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; @@ -150,7 +149,7 @@ impl<'d, T: Instance> Pdm<'d, T> { let gain = gain.saturating_add(I7F1::from_bits(0x28)) .to_bits() .clamp(0, 0x50); - unsafe { mem::transmute(gain) } + unsafe { core::mem::transmute(gain) } }; let gain_left = gain_to_bits(gain_left); let gain_right = gain_to_bits(gain_right); From 07987aea4e2706d8a7fa252ba3f6e31d576537ee Mon Sep 17 00:00:00 2001 From: Frank Plowman Date: Fri, 16 Feb 2024 20:45:58 +0000 Subject: [PATCH 482/760] embassy-nrf: Fix various typos and make style more consistent --- embassy-nrf/src/pdm.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index d03315fb6..dcaeffe0f 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -1,4 +1,4 @@ -//! Pulse Density Modulation (PDM) mirophone driver. +//! Pulse Density Modulation (PDM) mirophone driver #![macro_use] @@ -26,7 +26,7 @@ pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency; pub use crate::pac::pdm::ratio::RATIO_A as Ratio; use crate::{interrupt, Peripheral}; -/// Interrupt handler. +/// Interrupt handler pub struct InterruptHandler { _phantom: PhantomData, } @@ -56,12 +56,12 @@ pub struct Pdm<'d, T: Instance> { _peri: PeripheralRef<'d, T>, } -/// PDM error. +/// PDM error #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { - /// Buffer is too long. + /// Buffer is too long BufferTooLong, /// Buffer is empty BufferZeroLength, @@ -75,13 +75,13 @@ static DUMMY_BUFFER: [i16; 1] = [0; 1]; /// The state of a continuously running sampler. While it reflects /// the progress of a sampler, it also signals what should be done -/// next. For example, if the sampler has stopped then the Pdm implementation -/// can then tear down its infrastructure. +/// next. For example, if the sampler has stopped then the PDM implementation +/// can then tear down its infrastructure #[derive(PartialEq)] pub enum SamplerState { - /// The sampler processed the samples and is ready for more. + /// The sampler processed the samples and is ready for more Sampled, - /// The sampler is done processing samples. + /// The sampler is done processing samples Stopped, } @@ -162,12 +162,12 @@ impl<'d, T: Instance> Pdm<'d, T> { Self::_set_gain(T::regs(), gain_left, gain_right) } - /// Start sampling microphon data into a dummy buffer - /// Usefull to start the microphon and keep it active between recording samples + /// Start sampling microphone data into a dummy buffer. + /// Useful to start the microphone and keep it active between recording samples. pub async fn start(&mut self) { let r = T::regs(); - // start dummy sampling because microphon needs some setup time + // start dummy sampling because microphone needs some setup time r.sample .ptr .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); @@ -178,14 +178,14 @@ impl<'d, T: Instance> Pdm<'d, T> { r.tasks_start.write(|w| unsafe { w.bits(1) }); } - /// Stop sampling microphon data inta a dummy buffer + /// Stop sampling microphone data inta a dummy buffer pub async fn stop(&mut self) { let r = T::regs(); r.tasks_stop.write(|w| unsafe { w.bits(1) }); r.events_started.reset(); } - /// Sample data into the given buffer. + /// Sample data into the given buffer pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { if buffer.len() == 0 { return Err(Error::BufferZeroLength); @@ -302,7 +302,7 @@ impl<'d, T: Instance> Pdm<'d, T> { }); // Don't reorder the start event before the previous writes. Hopefully self - // wouldn't happen anyway. + // wouldn't happen anyway compiler_fence(Ordering::SeqCst); r.tasks_start.write(|w| unsafe { w.bits(1) }); @@ -313,11 +313,11 @@ impl<'d, T: Instance> Pdm<'d, T> { let drop = OnDrop::new(|| { r.tasks_stop.write(|w| unsafe { w.bits(1) }); - // N.B. It would be better if this were async, but Drop only support sync code. + // N.B. It would be better if this were async, but Drop only support sync code while r.events_stopped.read().bits() != 0 {} }); - // Wait for events and complete when the sampler indicates it has had enough. + // Wait for events and complete when the sampler indicates it has had enough poll_fn(|cx| { let r = T::regs(); @@ -330,7 +330,7 @@ impl<'d, T: Instance> Pdm<'d, T> { r.intenset.write(|w| w.end().set()); if !done { - // Discard the last buffer after the user requested a stop. + // Discard the last buffer after the user requested a stop if sampler(&bufs[current_buffer]) == SamplerState::Sampled { let next_buffer = 1 - current_buffer; current_buffer = next_buffer; @@ -404,7 +404,7 @@ impl Default for Config { } } -/// PDM operation mode. +/// PDM operation mode #[derive(PartialEq)] pub enum OperationMode { /// Mono (1 channel) @@ -475,9 +475,9 @@ pub(crate) mod sealed { } } -/// PDM peripheral instance. +/// PDM peripheral instance pub trait Instance: Peripheral

+ sealed::Instance + 'static + Send { - /// Interrupt for this peripheral. + /// Interrupt for this peripheral type Interrupt: interrupt::typelevel::Interrupt; } From 7d111191689460ddfdce08dec7195cb9fa1b598b Mon Sep 17 00:00:00 2001 From: Frank Plowman Date: Fri, 16 Feb 2024 20:47:19 +0000 Subject: [PATCH 483/760] embassy-nrf: Don't break lines; make rustfmt happy --- embassy-nrf/src/pdm.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index dcaeffe0f..6ddc4dc0a 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -146,9 +146,7 @@ impl<'d, T: Instance> Pdm<'d, T> { fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) { let gain_to_bits = |gain: I7F1| -> u8 { - let gain = gain.saturating_add(I7F1::from_bits(0x28)) - .to_bits() - .clamp(0, 0x50); + let gain = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50); unsafe { core::mem::transmute(gain) } }; let gain_left = gain_to_bits(gain_left); From a24087c36c60e97f8b0aaefe57111c3a2edd6e8a Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 16 Feb 2024 21:52:58 +0100 Subject: [PATCH 484/760] Configured SYSCLK after boost mode, added comments --- embassy-stm32/src/rcc/g4.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index e2afd5260..0c1a1e4b1 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -241,16 +241,13 @@ pub(crate) unsafe fn init(config: Config) { _ => unreachable!(), }; - RCC.cfgr().modify(|w| { - w.set_sw(sw); - w.set_hpre(config.ahb_pre); - w.set_ppre1(config.apb1_pre); - w.set_ppre2(config.apb2_pre); - }); - + // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. let ahb_freq = sys_clk / config.ahb_pre; // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) + // TODO: according to RM0440 p235, when switching from range1-normal to range1-boost, it’s necessary to divide + // SYSCLK by 2 using the AHB prescaler, set boost and flash read latency, switch system frequency, wait 1us and + // reconfigure the AHB prescaler as desired. Unclear whether this is always necessary. PWR.cr5().modify(|w| w.set_r1mode(!config.boost)); // Configure flash read access latency based on boost mode and frequency (RM0440 p98) @@ -270,6 +267,14 @@ pub(crate) unsafe fn init(config: Config) { }) }); + // Now that boost mode and flash read access latency are configured, set up SYSCLK + RCC.cfgr().modify(|w| { + w.set_sw(sw); + w.set_hpre(config.ahb_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); + }); + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { From 6d7458dac7e768425342910e04a75c85e667cb82 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Sat, 17 Feb 2024 00:30:16 +0100 Subject: [PATCH 485/760] Refinements * Implemented boost mode dance (RM0440 p234-245, 6.5.1) * Enabled boost mode in usb_serial example, tested on hardware * Removed hard requirement of a valid 48MHz source (HSI48 is checked if requested, PLL passed through as-is and assumed to be valid) * Used calc_pclk to calculate APB frequencies * Refactored 48MHz configuration code to remove unnecessary let and block * Renamed ahb_freq to hclk for clarity and consistency --- embassy-stm32/src/rcc/g4.rs | 67 ++++++++++++-------------- examples/stm32g4/src/bin/usb_serial.rs | 1 + 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 0c1a1e4b1..382ffbead 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -242,17 +242,25 @@ pub(crate) unsafe fn init(config: Config) { }; // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. - let ahb_freq = sys_clk / config.ahb_pre; + let hclk = sys_clk / config.ahb_pre; // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) - // TODO: according to RM0440 p235, when switching from range1-normal to range1-boost, it’s necessary to divide - // SYSCLK by 2 using the AHB prescaler, set boost and flash read latency, switch system frequency, wait 1us and - // reconfigure the AHB prescaler as desired. Unclear whether this is always necessary. - PWR.cr5().modify(|w| w.set_r1mode(!config.boost)); + if config.boost { + // RM0440 p235 + // “The sequence to switch from Range1 normal mode to Range1 boost mode is: + // 1. The system clock must be divided by 2 using the AHB prescaler before switching to a higher system frequency. + RCC.cfgr().modify(|w| w.set_hpre(AHBPrescaler::DIV2)); + // 2. Clear the R1MODE bit in the PWR_CR5 register. (enables boost mode) + PWR.cr5().modify(|w| w.set_r1mode(false)); + + // Below: + // 3. Adjust wait states according to new freq target + // 4. Configure and switch to new frequency + } // Configure flash read access latency based on boost mode and frequency (RM0440 p98) FLASH.acr().modify(|w| { - w.set_latency(match (config.boost, ahb_freq.0) { + w.set_latency(match (config.boost, hclk.0) { (true, ..=34_000_000) => Latency::WS0, (true, ..=68_000_000) => Latency::WS1, (true, ..=102_000_000) => Latency::WS2, @@ -267,6 +275,11 @@ pub(crate) unsafe fn init(config: Config) { }) }); + if config.boost { + // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency. + cortex_m::asm::delay(16); + } + // Now that boost mode and flash read access latency are configured, set up SYSCLK RCC.cfgr().modify(|w| { w.set_sw(sw); @@ -275,30 +288,16 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre); }); - let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } - }; - - let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } - }; + let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre); + let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre); // Configure the 48MHz clock source for USB and RNG peripherals. - { - let source = match config.clk48_src { + RCC.ccipr().modify(|w| { + w.set_clk48sel(match config.clk48_src { Clk48Src::PLL1_Q => { - // Make sure the PLLQ is enabled and running at 48Mhz - let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q); - assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000); - + // Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock. + // Peripherals which require one (USB, RNG) should check that they‘re driven by a valid 48MHz + // clock at init. crate::pac::rcc::vals::Clk48sel::PLL1_Q } Clk48Src::HSI48 => { @@ -307,10 +306,8 @@ pub(crate) unsafe fn init(config: Config) { crate::pac::rcc::vals::Clk48sel::HSI48 } _ => unreachable!(), - }; - - RCC.ccipr().modify(|w| w.set_clk48sel(source)); - } + }) + }); RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); @@ -339,9 +336,9 @@ pub(crate) unsafe fn init(config: Config) { set_clocks!( sys: Some(sys_clk), - hclk1: Some(ahb_freq), - hclk2: Some(ahb_freq), - hclk3: Some(ahb_freq), + hclk1: Some(hclk), + hclk2: Some(hclk), + hclk3: Some(hclk), pclk1: Some(apb1_freq), pclk1_tim: Some(apb1_tim_freq), pclk2: Some(apb2_freq), @@ -355,7 +352,7 @@ pub(crate) unsafe fn init(config: Config) { ); } -// TODO: if necessary, make more of these gated behind cfg attrs +// TODO: if necessary, make more of these, gated behind cfg attrs mod max { use core::ops::RangeInclusive; diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 353ac1799..989fef5b0 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -44,6 +44,7 @@ async fn main(_spawner: Spawner) { }); config.rcc.sys = Sysclk::PLL1_R; + config.rcc.boost = true; // BOOST! if USE_HSI48 { // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. From 370db9fb06862695433c9314585a492d8c1684ae Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Fri, 16 Feb 2024 16:39:23 -0800 Subject: [PATCH 486/760] Update f013.rs Add stm32f398 --- embassy-stm32/src/rcc/f013.rs | 45 +++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 4d5116a56..3f1b88e5c 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -85,31 +85,34 @@ pub enum TimClockSource { #[derive(Clone, Copy)] pub struct TimClockSources { pub tim1: TimClockSource, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] pub tim2: TimClockSource, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] pub tim34: TimClockSource, - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358, stm32f398))] pub tim8: TimClockSource, #[cfg(any( all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] pub tim15: TimClockSource, #[cfg(any( all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] pub tim16: TimClockSource, #[cfg(any( all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] pub tim17: TimClockSource, #[cfg(any(all(stm32f303, any(package_D, package_E))))] @@ -121,31 +124,34 @@ impl Default for TimClockSources { fn default() -> Self { Self { tim1: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] tim2: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] tim34: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358, stm32f398))] tim8: TimClockSource::PClk2, #[cfg(any( all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] tim15: TimClockSource::PClk2, #[cfg(any( all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] tim16: TimClockSource::PClk2, #[cfg(any( all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] tim17: TimClockSource::PClk2, #[cfg(any(all(stm32f303, any(package_D, package_E))))] @@ -456,7 +462,7 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] match config.tim.tim2 { TimClockSource::PClk2 => {} TimClockSource::PllClk => { @@ -465,7 +471,7 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E))))] + #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] match config.tim.tim34 { TimClockSource::PClk2 => {} TimClockSource::PllClk => { @@ -474,7 +480,7 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358))] + #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358, stm32f398))] match config.tim.tim8 { TimClockSource::PClk2 => {} TimClockSource::PllClk => { @@ -487,7 +493,8 @@ pub(crate) unsafe fn init(config: Config) { all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] match config.tim.tim15 { TimClockSource::PClk2 => None, @@ -501,7 +508,8 @@ pub(crate) unsafe fn init(config: Config) { all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] match config.tim.tim16 { TimClockSource::PClk2 => None, @@ -515,7 +523,8 @@ pub(crate) unsafe fn init(config: Config) { all(stm32f303, any(package_D, package_E)), stm32f301, stm32f318, - all(stm32f302, any(package_6, package_8)) + all(stm32f302, any(package_6, package_8)), + stm32f398 ))] match config.tim.tim17 { TimClockSource::PClk2 => None, From 77739faaeb155478d3d50e7b8a3add79b5e94222 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Fri, 16 Feb 2024 16:42:19 -0800 Subject: [PATCH 487/760] Rustfmt --- embassy-stm32/src/rcc/f013.rs | 54 +++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 3f1b88e5c..1a0e34614 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -85,11 +85,23 @@ pub enum TimClockSource { #[derive(Clone, Copy)] pub struct TimClockSources { pub tim1: TimClockSource, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)) + stm32f398 + ))] pub tim2: TimClockSource, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + stm32f398 + ))] pub tim34: TimClockSource, - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358, stm32f398))] + #[cfg(any( + all(stm32f303, any(package_B, package_C, package_D, package_E)), + stm32f358, + stm32f398 + ))] pub tim8: TimClockSource, #[cfg(any( all(stm32f303, any(package_D, package_E)), @@ -124,11 +136,23 @@ impl Default for TimClockSources { fn default() -> Self { Self { tim1: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + stm32f398 + ))] tim2: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + stm32f398 + ))] tim34: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358, stm32f398))] + #[cfg(any( + all(stm32f303, any(package_B, package_C, package_D, package_E)), + stm32f358, + stm32f398 + ))] tim8: TimClockSource::PClk2, #[cfg(any( all(stm32f303, any(package_D, package_E)), @@ -462,7 +486,11 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + stm32f398 + ))] match config.tim.tim2 { TimClockSource::PClk2 => {} TimClockSource::PllClk => { @@ -471,7 +499,11 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(any(all(stm32f303, any(package_D, package_E)), all(stm32f302, any(package_D, package_E)), stm32f398))] + #[cfg(any( + all(stm32f303, any(package_D, package_E)), + all(stm32f302, any(package_D, package_E)), + stm32f398 + ))] match config.tim.tim34 { TimClockSource::PClk2 => {} TimClockSource::PllClk => { @@ -480,7 +512,11 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(any(all(stm32f303, any(package_B, package_C, package_D, package_E)), stm32f358, stm32f398))] + #[cfg(any( + all(stm32f303, any(package_B, package_C, package_D, package_E)), + stm32f358, + stm32f398 + ))] match config.tim.tim8 { TimClockSource::PClk2 => {} TimClockSource::PllClk => { From 7592e8be6e40dc6be655bcf011f3ce2aee5b9743 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Fri, 16 Feb 2024 16:45:58 -0800 Subject: [PATCH 488/760] Fix build --- embassy-stm32/src/rcc/f013.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 1a0e34614..8ceae6a8a 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -495,7 +495,7 @@ pub(crate) unsafe fn init(config: Config) { TimClockSource::PClk2 => {} TimClockSource::PllClk => { RCC.cfgr3() - .modify(|w| w.set_tim2sw(crate::pac::rcc::vals::Timsw::PLL1_P)); + .modify(|w| w.set_tim2sw(crate::pac::rcc::vals::Tim2sw::PLL1_P)); } }; @@ -533,7 +533,7 @@ pub(crate) unsafe fn init(config: Config) { stm32f398 ))] match config.tim.tim15 { - TimClockSource::PClk2 => None, + TimClockSource::PClk2 => {}, TimClockSource::PllClk => { RCC.cfgr3() .modify(|w| w.set_tim15sw(crate::pac::rcc::vals::Timsw::PLL1_P)); @@ -548,7 +548,7 @@ pub(crate) unsafe fn init(config: Config) { stm32f398 ))] match config.tim.tim16 { - TimClockSource::PClk2 => None, + TimClockSource::PClk2 => {}, TimClockSource::PllClk => { RCC.cfgr3() .modify(|w| w.set_tim16sw(crate::pac::rcc::vals::Timsw::PLL1_P)); @@ -563,7 +563,7 @@ pub(crate) unsafe fn init(config: Config) { stm32f398 ))] match config.tim.tim17 { - TimClockSource::PClk2 => None, + TimClockSource::PClk2 => {}, TimClockSource::PllClk => { RCC.cfgr3() .modify(|w| w.set_tim17sw(crate::pac::rcc::vals::Timsw::PLL1_P)); @@ -572,7 +572,7 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(all(stm32f303, any(package_D, package_E))))] match config.tim.tim20 { - TimClockSource::PClk2 => None, + TimClockSource::PClk2 => {}, TimClockSource::PllClk => { RCC.cfgr3() .modify(|w| w.set_tim20sw(crate::pac::rcc::vals::Timsw::PLL1_P)); From c99c4a01a99d953805f11bf838c9f6c0b5338fae Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Fri, 16 Feb 2024 16:47:38 -0800 Subject: [PATCH 489/760] Update f013.rs --- embassy-stm32/src/rcc/f013.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 8ceae6a8a..02c3425d1 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -87,7 +87,7 @@ pub struct TimClockSources { pub tim1: TimClockSource, #[cfg(any( all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)) + all(stm32f302, any(package_D, package_E)), stm32f398 ))] pub tim2: TimClockSource, @@ -533,7 +533,7 @@ pub(crate) unsafe fn init(config: Config) { stm32f398 ))] match config.tim.tim15 { - TimClockSource::PClk2 => {}, + TimClockSource::PClk2 => {} TimClockSource::PllClk => { RCC.cfgr3() .modify(|w| w.set_tim15sw(crate::pac::rcc::vals::Timsw::PLL1_P)); @@ -548,7 +548,7 @@ pub(crate) unsafe fn init(config: Config) { stm32f398 ))] match config.tim.tim16 { - TimClockSource::PClk2 => {}, + TimClockSource::PClk2 => {} TimClockSource::PllClk => { RCC.cfgr3() .modify(|w| w.set_tim16sw(crate::pac::rcc::vals::Timsw::PLL1_P)); @@ -563,7 +563,7 @@ pub(crate) unsafe fn init(config: Config) { stm32f398 ))] match config.tim.tim17 { - TimClockSource::PClk2 => {}, + TimClockSource::PClk2 => {} TimClockSource::PllClk => { RCC.cfgr3() .modify(|w| w.set_tim17sw(crate::pac::rcc::vals::Timsw::PLL1_P)); @@ -572,7 +572,7 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(all(stm32f303, any(package_D, package_E))))] match config.tim.tim20 { - TimClockSource::PClk2 => {}, + TimClockSource::PClk2 => {} TimClockSource::PllClk => { RCC.cfgr3() .modify(|w| w.set_tim20sw(crate::pac::rcc::vals::Timsw::PLL1_P)); From 0e80dc4cd929f201dd35b569aa0aadd891c58682 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Feb 2024 02:36:48 +0100 Subject: [PATCH 490/760] tests/stm32: add stm32f091rc, stm32h503rb. --- tests/stm32/Cargo.toml | 2 ++ tests/stm32/build.rs | 2 ++ tests/stm32/src/bin/hash.rs | 1 + tests/stm32/src/common.rs | 58 ++++++++++++++++++++++++++++++++++++- 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index d94045737..8554682a4 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -30,6 +30,8 @@ stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] +stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] +stm32h503rb = ["embassy-stm32/stm32h503rb", "rng"] hash = [] eth = ["embassy-executor/task-arena-size-16384"] diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index f32a7b2f8..bc5589164 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs @@ -16,6 +16,8 @@ fn main() -> Result<(), Box> { feature = "stm32l073rz", // wrong ram size in stm32-data feature = "stm32wl55jc", + // no VTOR, so interrupts can't work when running from RAM + feature = "stm32f091rc", )) { println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rerun-if-changed=link.x"); diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index d1cfac5ce..8cc5d593f 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -24,6 +24,7 @@ bind_interrupts!(struct Irqs { feature = "stm32wba52cg", feature = "stm32l552ze", feature = "stm32h563zi", + feature = "stm32h503rb", feature = "stm32u5a5zj", feature = "stm32u585ai" ))] diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 182ad6298..50a7f9bae 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -54,6 +54,10 @@ teleprobe_meta::target!(b"nucleo-stm32l496zg"); teleprobe_meta::target!(b"nucleo-stm32wl55jc"); #[cfg(feature = "stm32wba52cg")] teleprobe_meta::target!(b"nucleo-stm32wba52cg"); +#[cfg(feature = "stm32f091rc")] +teleprobe_meta::target!(b"nucleo-stm32f091rc"); +#[cfg(feature = "stm32h503rb")] +teleprobe_meta::target!(b"nucleo-stm32h503rb"); macro_rules! define_peris { ($($name:ident = $peri:ident,)* $(@irq $irq_name:ident = $irq_code:tt,)*) => { @@ -85,6 +89,12 @@ macro_rules! define_peris { }; } +#[cfg(feature = "stm32f091rc")] +define_peris!( + UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); #[cfg(feature = "stm32f103c8")] define_peris!( UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, @@ -157,6 +167,12 @@ define_peris!( SPI = SPI4, SPI_SCK = PE12, SPI_MOSI = PE14, SPI_MISO = PE13, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, ); +#[cfg(feature = "stm32h503rb")] +define_peris!( + UART = USART1, UART_TX = PB14, UART_RX = PB15, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); #[cfg(feature = "stm32c031c6")] define_peris!( UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, @@ -247,6 +263,22 @@ pub fn config() -> Config { config.rcc = embassy_stm32::rcc::WPAN_DEFAULT; } + #[cfg(feature = "stm32f091rc")] + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL6, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + } #[cfg(feature = "stm32f103c8")] { use embassy_stm32::rcc::*; @@ -264,7 +296,6 @@ pub fn config() -> Config { config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; } - #[cfg(feature = "stm32f207zg")] { use embassy_stm32::rcc::*; @@ -400,6 +431,31 @@ pub fn config() -> Config { config.rcc.voltage_scale = VoltageScale::Scale0; } + #[cfg(feature = "stm32h503rb")] + { + use embassy_stm32::rcc::*; + config.rcc.hsi = None; + config.rcc.hsi48 = Some(Default::default()); // needed for RNG + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL125, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV2), + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.apb3_pre = APBPrescaler::DIV1; + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.voltage_scale = VoltageScale::Scale0; + } + #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] { use embassy_stm32::rcc::*; From cb7863aea548b8cda65ca3eb14e543c226dbedb8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Feb 2024 03:37:51 +0100 Subject: [PATCH 491/760] tests/stm32: actually add stm32f091rc, stm32h503rb. --- ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci.sh b/ci.sh index 7ecca92af..ef706bdc5 100755 --- a/ci.sh +++ b/ci.sh @@ -230,6 +230,8 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f091rc --out-dir out/tests/stm32f091rc \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb --out-dir out/tests/stm32h503rb \ --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ --- build --release --manifest-path tests/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ --- build --release --manifest-path tests/nrf51422/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/nrf51-dk \ From f9aea0fb54cf2f74dc4cd5ce205c7f1bfaf5dc39 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Feb 2024 03:37:51 +0100 Subject: [PATCH 492/760] tests/rp: reenable i2c test. --- ci.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/ci.sh b/ci.sh index ef706bdc5..b2170a225 100755 --- a/ci.sh +++ b/ci.sh @@ -239,9 +239,6 @@ cargo batch \ $BUILD_EXTRA -# failed, a wire must've come loose, will check asap. -rm out/tests/rpi-pico/i2c - rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble From e99ef496116b4cdfa0dd0706ac1bfc600f45c97b Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Fri, 16 Feb 2024 19:56:07 -0800 Subject: [PATCH 493/760] Move to auto-generated based system. --- embassy-stm32/build.rs | 69 ++++++++ embassy-stm32/src/rcc/f013.rs | 221 +------------------------- examples/stm32f3/src/bin/usart_dma.rs | 4 +- 3 files changed, 78 insertions(+), 216 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ee88d4541..f45a571f2 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -430,6 +430,8 @@ fn main() { let mut clock_names = BTreeSet::new(); + let mut rcc_cfgr_regs = BTreeMap::new(); + for p in METADATA.peripherals { if !singletons.contains(&p.name.to_string()) { continue; @@ -508,6 +510,16 @@ fn main() { let field_name = format_ident!("{}", field_name); let enum_name = format_ident!("{}", enum_name); + if !rcc_cfgr_regs.contains_key(mux.register) { + rcc_cfgr_regs.insert(mux.register, Vec::new()); + } + + rcc_cfgr_regs.get_mut(mux.register).unwrap().push(( + fieldset_name.clone(), + field_name.clone(), + enum_name.clone(), + )); + let match_arms: TokenStream = enumm .variants .iter() @@ -590,6 +602,63 @@ fn main() { } } + for (rcc_cfgr_reg, fields) in rcc_cfgr_regs { + println!("cargo:rustc-cfg={}", rcc_cfgr_reg.to_ascii_lowercase()); + + let struct_fields: Vec<_> = fields + .iter() + .map(|(_fieldset, fieldname, enum_name)| { + quote! { + pub #fieldname: Option + } + }) + .collect(); + + let field_names: Vec<_> = fields + .iter() + .map(|(_fieldset, fieldname, _enum_name)| fieldname) + .collect(); + + let inits: Vec<_> = fields + .iter() + .map(|(fieldset, fieldname, _enum_name)| { + let setter = format_ident!("set_{}", fieldname); + quote! { + match self.#fieldname { + None => {} + Some(val) => { + crate::pac::RCC.#fieldset() + .modify(|w| w.#setter(val)); + } + }; + } + }) + .collect(); + + let cfgr_reg = format_ident!("{}", rcc_cfgr_reg); + + g.extend(quote! { + #[derive(Clone, Copy)] + pub struct #cfgr_reg { + #( #struct_fields, )* + } + + impl Default for #cfgr_reg { + fn default() -> Self { + Self { + #( #field_names: None, )* + } + } + } + + impl #cfgr_reg { + pub fn init(self) { + #( #inits )* + } + } + }); + } + // Generate RCC clock_names.insert("sys".to_string()); clock_names.insert("rtc".to_string()); diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 02c3425d1..a61aae0e8 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -74,116 +74,6 @@ pub enum HrtimClockSource { PllClk, } -#[cfg(all(stm32f3, not(rcc_f37)))] -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum TimClockSource { - PClk2, - PllClk, -} - -#[cfg(all(stm32f3, not(rcc_f37)))] -#[derive(Clone, Copy)] -pub struct TimClockSources { - pub tim1: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - stm32f398 - ))] - pub tim2: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - stm32f398 - ))] - pub tim34: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_B, package_C, package_D, package_E)), - stm32f358, - stm32f398 - ))] - pub tim8: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - pub tim15: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - pub tim16: TimClockSource, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - pub tim17: TimClockSource, - #[cfg(any(all(stm32f303, any(package_D, package_E))))] - pub tim20: TimClockSource, -} - -#[cfg(all(stm32f3, not(rcc_f37)))] -impl Default for TimClockSources { - fn default() -> Self { - Self { - tim1: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - stm32f398 - ))] - tim2: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - stm32f398 - ))] - tim34: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_B, package_C, package_D, package_E)), - stm32f358, - stm32f398 - ))] - tim8: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - tim15: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - tim16: TimClockSource::PClk2, - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - tim17: TimClockSource::PClk2, - #[cfg(any(all(stm32f303, any(package_D, package_E))))] - tim20: TimClockSource::PClk2, - } - } -} - /// Clocks configutation #[non_exhaustive] pub struct Config { @@ -209,8 +99,8 @@ pub struct Config { pub adc34: AdcClockSource, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, - #[cfg(all(stm32f3, not(rcc_f37)))] - pub tim: TimClockSources, + #[cfg(cfgr3)] + pub cfgr3: crate::_generated::CFGR3, pub ls: super::LsConfig, } @@ -240,8 +130,8 @@ impl Default for Config { adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(stm32f334)] hrtim: HrtimClockSource::BusClk, - #[cfg(all(stm32f3, not(rcc_f37)))] - tim: Default::default(), + #[cfg(cfgr3)] + cfgr3: Default::default(), } } } @@ -477,107 +367,8 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(all(stm32f3, not(rcc_f37)))] - match config.tim.tim1 { - TimClockSource::PClk2 => {} - TimClockSource::PllClk => { - RCC.cfgr3() - .modify(|w| w.set_tim1sw(crate::pac::rcc::vals::Timsw::PLL1_P)); - } - }; - - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - stm32f398 - ))] - match config.tim.tim2 { - TimClockSource::PClk2 => {} - TimClockSource::PllClk => { - RCC.cfgr3() - .modify(|w| w.set_tim2sw(crate::pac::rcc::vals::Tim2sw::PLL1_P)); - } - }; - - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - all(stm32f302, any(package_D, package_E)), - stm32f398 - ))] - match config.tim.tim34 { - TimClockSource::PClk2 => {} - TimClockSource::PllClk => { - RCC.cfgr3() - .modify(|w| w.set_tim34sw(crate::pac::rcc::vals::Timsw::PLL1_P)); - } - }; - - #[cfg(any( - all(stm32f303, any(package_B, package_C, package_D, package_E)), - stm32f358, - stm32f398 - ))] - match config.tim.tim8 { - TimClockSource::PClk2 => {} - TimClockSource::PllClk => { - RCC.cfgr3() - .modify(|w| w.set_tim8sw(crate::pac::rcc::vals::Timsw::PLL1_P)); - } - }; - - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - match config.tim.tim15 { - TimClockSource::PClk2 => {} - TimClockSource::PllClk => { - RCC.cfgr3() - .modify(|w| w.set_tim15sw(crate::pac::rcc::vals::Timsw::PLL1_P)); - } - }; - - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - match config.tim.tim16 { - TimClockSource::PClk2 => {} - TimClockSource::PllClk => { - RCC.cfgr3() - .modify(|w| w.set_tim16sw(crate::pac::rcc::vals::Timsw::PLL1_P)); - } - }; - - #[cfg(any( - all(stm32f303, any(package_D, package_E)), - stm32f301, - stm32f318, - all(stm32f302, any(package_6, package_8)), - stm32f398 - ))] - match config.tim.tim17 { - TimClockSource::PClk2 => {} - TimClockSource::PllClk => { - RCC.cfgr3() - .modify(|w| w.set_tim17sw(crate::pac::rcc::vals::Timsw::PLL1_P)); - } - } - - #[cfg(any(all(stm32f303, any(package_D, package_E))))] - match config.tim.tim20 { - TimClockSource::PClk2 => {} - TimClockSource::PllClk => { - RCC.cfgr3() - .modify(|w| w.set_tim20sw(crate::pac::rcc::vals::Timsw::PLL1_P)); - } - } + #[cfg(cfgr3)] + config.cfgr3.init(); set_clocks!( hsi: hsi, diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 5234e53b9..7dc905adc 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs @@ -17,7 +17,9 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let mut init_config = embassy_stm32::Config::default(); + init_config.rcc.cfgr3.usart1sw = Some(embassy_stm32::pac::rcc::vals::Usart1sw::HSI); + let p = embassy_stm32::init(init_config); info!("Hello World!"); let config = Config::default(); From 0097cbcfe3311ca89f52284a4a1187e19666a330 Mon Sep 17 00:00:00 2001 From: Mick Chanthaseth Date: Fri, 16 Feb 2024 22:22:13 -0800 Subject: [PATCH 494/760] Update imports in usb_hid_mouse.rs --- examples/rp/src/bin/usb_hid_mouse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index ec125a47e..a812b22c3 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -15,7 +15,7 @@ use embassy_rp::usb::{Driver, InterruptHandler}; use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; -use rand::{Rng, RngCore}; +use rand::Rng; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; From 70b3c4374d57ab638e0cb76013b725e1ea229546 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 3 Feb 2024 09:44:00 +1000 Subject: [PATCH 495/760] Port FDCAN HAL to use PAC directly instead of fdcan crate. - Provide separate FDCAN capable and Classic CAN API's - Don't use fdcan crate dep anymore - Provide embedded-can traits. --- embassy-stm32/Cargo.toml | 901 +++++++++--------- embassy-stm32/src/can/enums.rs | 17 + embassy-stm32/src/can/fd/config.rs | 438 +++++++++ embassy-stm32/src/can/fd/filter.rs | 379 ++++++++ .../src/can/fd/message_ram/common.rs | 134 +++ embassy-stm32/src/can/fd/message_ram/enums.rs | 233 +++++ .../src/can/fd/message_ram/extended_filter.rs | 136 +++ .../src/can/fd/message_ram/generic.rs | 168 ++++ embassy-stm32/src/can/fd/message_ram/mod.rs | 170 ++++ .../src/can/fd/message_ram/rxfifo_element.rs | 122 +++ .../src/can/fd/message_ram/standard_filter.rs | 136 +++ .../can/fd/message_ram/txbuffer_element.rs | 433 +++++++++ .../src/can/fd/message_ram/txevent_element.rs | 138 +++ embassy-stm32/src/can/fd/mod.rs | 6 + embassy-stm32/src/can/fd/peripheral.rs | 776 +++++++++++++++ embassy-stm32/src/can/fdcan.rs | 633 ++++++------ embassy-stm32/src/can/frame.rs | 370 +++++++ examples/stm32g4/Cargo.toml | 1 + examples/stm32g4/src/bin/can.rs | 96 +- examples/stm32h5/src/bin/can.rs | 89 +- examples/stm32h7/src/bin/can.rs | 89 +- tests/stm32/Cargo.toml | 1 + tests/stm32/src/bin/fdcan.rs | 109 +-- 23 files changed, 4659 insertions(+), 916 deletions(-) create mode 100644 embassy-stm32/src/can/fd/config.rs create mode 100644 embassy-stm32/src/can/fd/filter.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/common.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/enums.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/extended_filter.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/generic.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/mod.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/standard_filter.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs create mode 100644 embassy-stm32/src/can/fd/message_ram/txevent_element.rs create mode 100644 embassy-stm32/src/can/fd/mod.rs create mode 100644 embassy-stm32/src/can/fd/peripheral.rs create mode 100644 embassy-stm32/src/can/frame.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 389ed0041..d585d2cd6 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -55,10 +55,12 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["un embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-nb = { version = "1.0" } +embedded-can = "0.4" embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } + defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" @@ -80,7 +82,10 @@ chrono = { version = "^0.4", default-features = false, optional = true} bit_field = "0.10.2" document-features = "0.2.7" -fdcan = { version = "0.2.0", optional = true } +static_assertions = { version = "1.1" } +volatile-register = { version = "0.2.1" } + + [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } @@ -695,373 +700,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ] stm32f779bi = [ "stm32-metapac/stm32f779bi" ] stm32f779ii = [ "stm32-metapac/stm32f779ii" ] stm32f779ni = [ "stm32-metapac/stm32f779ni" ] -stm32g030c6 = [ "stm32-metapac/stm32g030c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g030c8 = [ "stm32-metapac/stm32g030c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g030f6 = [ "stm32-metapac/stm32g030f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g030j6 = [ "stm32-metapac/stm32g030j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g030k6 = [ "stm32-metapac/stm32g030k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g030k8 = [ "stm32-metapac/stm32g030k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031c4 = [ "stm32-metapac/stm32g031c4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031c6 = [ "stm32-metapac/stm32g031c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031c8 = [ "stm32-metapac/stm32g031c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031f4 = [ "stm32-metapac/stm32g031f4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031f6 = [ "stm32-metapac/stm32g031f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031f8 = [ "stm32-metapac/stm32g031f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031g4 = [ "stm32-metapac/stm32g031g4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031g6 = [ "stm32-metapac/stm32g031g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031g8 = [ "stm32-metapac/stm32g031g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031j4 = [ "stm32-metapac/stm32g031j4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031j6 = [ "stm32-metapac/stm32g031j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031k4 = [ "stm32-metapac/stm32g031k4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031k6 = [ "stm32-metapac/stm32g031k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031k8 = [ "stm32-metapac/stm32g031k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g031y8 = [ "stm32-metapac/stm32g031y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041c6 = [ "stm32-metapac/stm32g041c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041c8 = [ "stm32-metapac/stm32g041c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041f6 = [ "stm32-metapac/stm32g041f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041f8 = [ "stm32-metapac/stm32g041f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041g6 = [ "stm32-metapac/stm32g041g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041g8 = [ "stm32-metapac/stm32g041g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041j6 = [ "stm32-metapac/stm32g041j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041k6 = [ "stm32-metapac/stm32g041k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041k8 = [ "stm32-metapac/stm32g041k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g041y8 = [ "stm32-metapac/stm32g041y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g050c6 = [ "stm32-metapac/stm32g050c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g050c8 = [ "stm32-metapac/stm32g050c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g050f6 = [ "stm32-metapac/stm32g050f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g050k6 = [ "stm32-metapac/stm32g050k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g050k8 = [ "stm32-metapac/stm32g050k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g051c6 = [ "stm32-metapac/stm32g051c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g051c8 = [ "stm32-metapac/stm32g051c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g051f6 = [ "stm32-metapac/stm32g051f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g051f8 = [ "stm32-metapac/stm32g051f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g051g6 = [ "stm32-metapac/stm32g051g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g051g8 = [ "stm32-metapac/stm32g051g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g051k6 = [ "stm32-metapac/stm32g051k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g051k8 = [ "stm32-metapac/stm32g051k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g061c6 = [ "stm32-metapac/stm32g061c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g061c8 = [ "stm32-metapac/stm32g061c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g061f6 = [ "stm32-metapac/stm32g061f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g061f8 = [ "stm32-metapac/stm32g061f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g061g6 = [ "stm32-metapac/stm32g061g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g061g8 = [ "stm32-metapac/stm32g061g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g061k6 = [ "stm32-metapac/stm32g061k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g061k8 = [ "stm32-metapac/stm32g061k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g070cb = [ "stm32-metapac/stm32g070cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g070kb = [ "stm32-metapac/stm32g070kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g070rb = [ "stm32-metapac/stm32g070rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071c6 = [ "stm32-metapac/stm32g071c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071c8 = [ "stm32-metapac/stm32g071c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071cb = [ "stm32-metapac/stm32g071cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071eb = [ "stm32-metapac/stm32g071eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071g6 = [ "stm32-metapac/stm32g071g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071g8 = [ "stm32-metapac/stm32g071g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071gb = [ "stm32-metapac/stm32g071gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071k6 = [ "stm32-metapac/stm32g071k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071k8 = [ "stm32-metapac/stm32g071k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071kb = [ "stm32-metapac/stm32g071kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071r6 = [ "stm32-metapac/stm32g071r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071r8 = [ "stm32-metapac/stm32g071r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g071rb = [ "stm32-metapac/stm32g071rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g081cb = [ "stm32-metapac/stm32g081cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g081eb = [ "stm32-metapac/stm32g081eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g081gb = [ "stm32-metapac/stm32g081gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g081kb = [ "stm32-metapac/stm32g081kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g081rb = [ "stm32-metapac/stm32g081rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b0re = [ "stm32-metapac/stm32g0b0re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1me = [ "stm32-metapac/stm32g0b1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1re = [ "stm32-metapac/stm32g0b1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1me = [ "stm32-metapac/stm32g0c1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1re = [ "stm32-metapac/stm32g0c1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431c6 = [ "stm32-metapac/stm32g431c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431c8 = [ "stm32-metapac/stm32g431c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431cb = [ "stm32-metapac/stm32g431cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431k6 = [ "stm32-metapac/stm32g431k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431k8 = [ "stm32-metapac/stm32g431k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431kb = [ "stm32-metapac/stm32g431kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431m6 = [ "stm32-metapac/stm32g431m6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431m8 = [ "stm32-metapac/stm32g431m8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431mb = [ "stm32-metapac/stm32g431mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431r6 = [ "stm32-metapac/stm32g431r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431r8 = [ "stm32-metapac/stm32g431r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431rb = [ "stm32-metapac/stm32g431rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431v6 = [ "stm32-metapac/stm32g431v6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431v8 = [ "stm32-metapac/stm32g431v8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g431vb = [ "stm32-metapac/stm32g431vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g441cb = [ "stm32-metapac/stm32g441cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g441kb = [ "stm32-metapac/stm32g441kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g441mb = [ "stm32-metapac/stm32g441mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g441rb = [ "stm32-metapac/stm32g441rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g441vb = [ "stm32-metapac/stm32g441vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471cc = [ "stm32-metapac/stm32g471cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471ce = [ "stm32-metapac/stm32g471ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471mc = [ "stm32-metapac/stm32g471mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471me = [ "stm32-metapac/stm32g471me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471qc = [ "stm32-metapac/stm32g471qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471qe = [ "stm32-metapac/stm32g471qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471rc = [ "stm32-metapac/stm32g471rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471re = [ "stm32-metapac/stm32g471re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471vc = [ "stm32-metapac/stm32g471vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g471ve = [ "stm32-metapac/stm32g471ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473cb = [ "stm32-metapac/stm32g473cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473cc = [ "stm32-metapac/stm32g473cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473ce = [ "stm32-metapac/stm32g473ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473mb = [ "stm32-metapac/stm32g473mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473mc = [ "stm32-metapac/stm32g473mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473me = [ "stm32-metapac/stm32g473me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473pb = [ "stm32-metapac/stm32g473pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473pc = [ "stm32-metapac/stm32g473pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473pe = [ "stm32-metapac/stm32g473pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473qb = [ "stm32-metapac/stm32g473qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473qc = [ "stm32-metapac/stm32g473qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473qe = [ "stm32-metapac/stm32g473qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473rb = [ "stm32-metapac/stm32g473rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473rc = [ "stm32-metapac/stm32g473rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473re = [ "stm32-metapac/stm32g473re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473vb = [ "stm32-metapac/stm32g473vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473vc = [ "stm32-metapac/stm32g473vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g473ve = [ "stm32-metapac/stm32g473ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474cb = [ "stm32-metapac/stm32g474cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474cc = [ "stm32-metapac/stm32g474cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474ce = [ "stm32-metapac/stm32g474ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474mb = [ "stm32-metapac/stm32g474mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474mc = [ "stm32-metapac/stm32g474mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474me = [ "stm32-metapac/stm32g474me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474pb = [ "stm32-metapac/stm32g474pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474pc = [ "stm32-metapac/stm32g474pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474pe = [ "stm32-metapac/stm32g474pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474qb = [ "stm32-metapac/stm32g474qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474qc = [ "stm32-metapac/stm32g474qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474qe = [ "stm32-metapac/stm32g474qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474rb = [ "stm32-metapac/stm32g474rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474rc = [ "stm32-metapac/stm32g474rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474re = [ "stm32-metapac/stm32g474re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474vb = [ "stm32-metapac/stm32g474vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474vc = [ "stm32-metapac/stm32g474vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g474ve = [ "stm32-metapac/stm32g474ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g483ce = [ "stm32-metapac/stm32g483ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g483me = [ "stm32-metapac/stm32g483me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g483pe = [ "stm32-metapac/stm32g483pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g483qe = [ "stm32-metapac/stm32g483qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g483re = [ "stm32-metapac/stm32g483re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g483ve = [ "stm32-metapac/stm32g483ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g484ce = [ "stm32-metapac/stm32g484ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g484me = [ "stm32-metapac/stm32g484me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g484pe = [ "stm32-metapac/stm32g484pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g484qe = [ "stm32-metapac/stm32g484qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g484re = [ "stm32-metapac/stm32g484re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g484ve = [ "stm32-metapac/stm32g484ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491cc = [ "stm32-metapac/stm32g491cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491ce = [ "stm32-metapac/stm32g491ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491kc = [ "stm32-metapac/stm32g491kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491ke = [ "stm32-metapac/stm32g491ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491mc = [ "stm32-metapac/stm32g491mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491me = [ "stm32-metapac/stm32g491me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491rc = [ "stm32-metapac/stm32g491rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491re = [ "stm32-metapac/stm32g491re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491vc = [ "stm32-metapac/stm32g491vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g491ve = [ "stm32-metapac/stm32g491ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g4a1me = [ "stm32-metapac/stm32g4a1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g4a1re = [ "stm32-metapac/stm32g4a1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h503cb = [ "stm32-metapac/stm32h503cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h503eb = [ "stm32-metapac/stm32h503eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h503kb = [ "stm32-metapac/stm32h503kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h503rb = [ "stm32-metapac/stm32h503rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562ag = [ "stm32-metapac/stm32h562ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562ai = [ "stm32-metapac/stm32h562ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562ig = [ "stm32-metapac/stm32h562ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562ii = [ "stm32-metapac/stm32h562ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562rg = [ "stm32-metapac/stm32h562rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562ri = [ "stm32-metapac/stm32h562ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562vg = [ "stm32-metapac/stm32h562vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562vi = [ "stm32-metapac/stm32h562vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562zg = [ "stm32-metapac/stm32h562zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h562zi = [ "stm32-metapac/stm32h562zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563ag = [ "stm32-metapac/stm32h563ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563ai = [ "stm32-metapac/stm32h563ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563ig = [ "stm32-metapac/stm32h563ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563ii = [ "stm32-metapac/stm32h563ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563mi = [ "stm32-metapac/stm32h563mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563rg = [ "stm32-metapac/stm32h563rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563ri = [ "stm32-metapac/stm32h563ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563vg = [ "stm32-metapac/stm32h563vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563vi = [ "stm32-metapac/stm32h563vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563zg = [ "stm32-metapac/stm32h563zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h563zi = [ "stm32-metapac/stm32h563zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h573ai = [ "stm32-metapac/stm32h573ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h573ii = [ "stm32-metapac/stm32h573ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h573mi = [ "stm32-metapac/stm32h573mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h573ri = [ "stm32-metapac/stm32h573ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h573vi = [ "stm32-metapac/stm32h573vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h573zi = [ "stm32-metapac/stm32h573zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32h723ve = [ "stm32-metapac/stm32h723ve", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h723vg = [ "stm32-metapac/stm32h723vg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h723ze = [ "stm32-metapac/stm32h723ze", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h723zg = [ "stm32-metapac/stm32h723zg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725ae = [ "stm32-metapac/stm32h725ae", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725ag = [ "stm32-metapac/stm32h725ag", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725ie = [ "stm32-metapac/stm32h725ie", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725ig = [ "stm32-metapac/stm32h725ig", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725re = [ "stm32-metapac/stm32h725re", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725rg = [ "stm32-metapac/stm32h725rg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725ve = [ "stm32-metapac/stm32h725ve", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725vg = [ "stm32-metapac/stm32h725vg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725ze = [ "stm32-metapac/stm32h725ze", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h725zg = [ "stm32-metapac/stm32h725zg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h730ab = [ "stm32-metapac/stm32h730ab", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h730ib = [ "stm32-metapac/stm32h730ib", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h730vb = [ "stm32-metapac/stm32h730vb", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h730zb = [ "stm32-metapac/stm32h730zb", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h733vg = [ "stm32-metapac/stm32h733vg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h733zg = [ "stm32-metapac/stm32h733zg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h735ag = [ "stm32-metapac/stm32h735ag", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h735ig = [ "stm32-metapac/stm32h735ig", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h735rg = [ "stm32-metapac/stm32h735rg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h735vg = [ "stm32-metapac/stm32h735vg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h735zg = [ "stm32-metapac/stm32h735zg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742ag = [ "stm32-metapac/stm32h742ag", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742ai = [ "stm32-metapac/stm32h742ai", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742bg = [ "stm32-metapac/stm32h742bg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742bi = [ "stm32-metapac/stm32h742bi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742ig = [ "stm32-metapac/stm32h742ig", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742ii = [ "stm32-metapac/stm32h742ii", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742vg = [ "stm32-metapac/stm32h742vg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742vi = [ "stm32-metapac/stm32h742vi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742xg = [ "stm32-metapac/stm32h742xg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742xi = [ "stm32-metapac/stm32h742xi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742zg = [ "stm32-metapac/stm32h742zg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h742zi = [ "stm32-metapac/stm32h742zi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743ag = [ "stm32-metapac/stm32h743ag", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743ai = [ "stm32-metapac/stm32h743ai", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743bg = [ "stm32-metapac/stm32h743bg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743bi = [ "stm32-metapac/stm32h743bi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743ig = [ "stm32-metapac/stm32h743ig", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743ii = [ "stm32-metapac/stm32h743ii", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743vg = [ "stm32-metapac/stm32h743vg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743vi = [ "stm32-metapac/stm32h743vi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743xg = [ "stm32-metapac/stm32h743xg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743xi = [ "stm32-metapac/stm32h743xi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743zg = [ "stm32-metapac/stm32h743zg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h743zi = [ "stm32-metapac/stm32h743zi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h750ib = [ "stm32-metapac/stm32h750ib", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h750vb = [ "stm32-metapac/stm32h750vb", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h750xb = [ "stm32-metapac/stm32h750xb", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h750zb = [ "stm32-metapac/stm32h750zb", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h753ai = [ "stm32-metapac/stm32h753ai", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h753bi = [ "stm32-metapac/stm32h753bi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h753ii = [ "stm32-metapac/stm32h753ii", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h753vi = [ "stm32-metapac/stm32h753vi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h753xi = [ "stm32-metapac/stm32h753xi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h753zi = [ "stm32-metapac/stm32h753zi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3li = [ "stm32-metapac/stm32h7a3li", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b3li = [ "stm32-metapac/stm32h7b3li", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi", "dep:fdcan", "fdcan/fdcan_h7" ] -stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi", "dep:fdcan", "fdcan/fdcan_h7" ] +stm32g030c6 = [ "stm32-metapac/stm32g030c6" ] +stm32g030c8 = [ "stm32-metapac/stm32g030c8" ] +stm32g030f6 = [ "stm32-metapac/stm32g030f6" ] +stm32g030j6 = [ "stm32-metapac/stm32g030j6" ] +stm32g030k6 = [ "stm32-metapac/stm32g030k6" ] +stm32g030k8 = [ "stm32-metapac/stm32g030k8" ] +stm32g031c4 = [ "stm32-metapac/stm32g031c4" ] +stm32g031c6 = [ "stm32-metapac/stm32g031c6" ] +stm32g031c8 = [ "stm32-metapac/stm32g031c8" ] +stm32g031f4 = [ "stm32-metapac/stm32g031f4" ] +stm32g031f6 = [ "stm32-metapac/stm32g031f6" ] +stm32g031f8 = [ "stm32-metapac/stm32g031f8" ] +stm32g031g4 = [ "stm32-metapac/stm32g031g4" ] +stm32g031g6 = [ "stm32-metapac/stm32g031g6" ] +stm32g031g8 = [ "stm32-metapac/stm32g031g8" ] +stm32g031j4 = [ "stm32-metapac/stm32g031j4" ] +stm32g031j6 = [ "stm32-metapac/stm32g031j6" ] +stm32g031k4 = [ "stm32-metapac/stm32g031k4" ] +stm32g031k6 = [ "stm32-metapac/stm32g031k6" ] +stm32g031k8 = [ "stm32-metapac/stm32g031k8" ] +stm32g031y8 = [ "stm32-metapac/stm32g031y8" ] +stm32g041c6 = [ "stm32-metapac/stm32g041c6" ] +stm32g041c8 = [ "stm32-metapac/stm32g041c8" ] +stm32g041f6 = [ "stm32-metapac/stm32g041f6" ] +stm32g041f8 = [ "stm32-metapac/stm32g041f8" ] +stm32g041g6 = [ "stm32-metapac/stm32g041g6" ] +stm32g041g8 = [ "stm32-metapac/stm32g041g8" ] +stm32g041j6 = [ "stm32-metapac/stm32g041j6" ] +stm32g041k6 = [ "stm32-metapac/stm32g041k6" ] +stm32g041k8 = [ "stm32-metapac/stm32g041k8" ] +stm32g041y8 = [ "stm32-metapac/stm32g041y8" ] +stm32g050c6 = [ "stm32-metapac/stm32g050c6" ] +stm32g050c8 = [ "stm32-metapac/stm32g050c8" ] +stm32g050f6 = [ "stm32-metapac/stm32g050f6" ] +stm32g050k6 = [ "stm32-metapac/stm32g050k6" ] +stm32g050k8 = [ "stm32-metapac/stm32g050k8" ] +stm32g051c6 = [ "stm32-metapac/stm32g051c6" ] +stm32g051c8 = [ "stm32-metapac/stm32g051c8" ] +stm32g051f6 = [ "stm32-metapac/stm32g051f6" ] +stm32g051f8 = [ "stm32-metapac/stm32g051f8" ] +stm32g051g6 = [ "stm32-metapac/stm32g051g6" ] +stm32g051g8 = [ "stm32-metapac/stm32g051g8" ] +stm32g051k6 = [ "stm32-metapac/stm32g051k6" ] +stm32g051k8 = [ "stm32-metapac/stm32g051k8" ] +stm32g061c6 = [ "stm32-metapac/stm32g061c6" ] +stm32g061c8 = [ "stm32-metapac/stm32g061c8" ] +stm32g061f6 = [ "stm32-metapac/stm32g061f6" ] +stm32g061f8 = [ "stm32-metapac/stm32g061f8" ] +stm32g061g6 = [ "stm32-metapac/stm32g061g6" ] +stm32g061g8 = [ "stm32-metapac/stm32g061g8" ] +stm32g061k6 = [ "stm32-metapac/stm32g061k6" ] +stm32g061k8 = [ "stm32-metapac/stm32g061k8" ] +stm32g070cb = [ "stm32-metapac/stm32g070cb" ] +stm32g070kb = [ "stm32-metapac/stm32g070kb" ] +stm32g070rb = [ "stm32-metapac/stm32g070rb" ] +stm32g071c6 = [ "stm32-metapac/stm32g071c6" ] +stm32g071c8 = [ "stm32-metapac/stm32g071c8" ] +stm32g071cb = [ "stm32-metapac/stm32g071cb" ] +stm32g071eb = [ "stm32-metapac/stm32g071eb" ] +stm32g071g6 = [ "stm32-metapac/stm32g071g6" ] +stm32g071g8 = [ "stm32-metapac/stm32g071g8" ] +stm32g071gb = [ "stm32-metapac/stm32g071gb" ] +stm32g071k6 = [ "stm32-metapac/stm32g071k6" ] +stm32g071k8 = [ "stm32-metapac/stm32g071k8" ] +stm32g071kb = [ "stm32-metapac/stm32g071kb" ] +stm32g071r6 = [ "stm32-metapac/stm32g071r6" ] +stm32g071r8 = [ "stm32-metapac/stm32g071r8" ] +stm32g071rb = [ "stm32-metapac/stm32g071rb" ] +stm32g081cb = [ "stm32-metapac/stm32g081cb" ] +stm32g081eb = [ "stm32-metapac/stm32g081eb" ] +stm32g081gb = [ "stm32-metapac/stm32g081gb" ] +stm32g081kb = [ "stm32-metapac/stm32g081kb" ] +stm32g081rb = [ "stm32-metapac/stm32g081rb" ] +stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce" ] +stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke" ] +stm32g0b0re = [ "stm32-metapac/stm32g0b0re" ] +stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve" ] +stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb" ] +stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc" ] +stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce" ] +stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb" ] +stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc" ] +stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke" ] +stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb" ] +stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc" ] +stm32g0b1me = [ "stm32-metapac/stm32g0b1me" ] +stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne" ] +stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb" ] +stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc" ] +stm32g0b1re = [ "stm32-metapac/stm32g0b1re" ] +stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb" ] +stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc" ] +stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve" ] +stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc" ] +stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce" ] +stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc" ] +stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke" ] +stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc" ] +stm32g0c1me = [ "stm32-metapac/stm32g0c1me" ] +stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne" ] +stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc" ] +stm32g0c1re = [ "stm32-metapac/stm32g0c1re" ] +stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc" ] +stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve" ] +stm32g431c6 = [ "stm32-metapac/stm32g431c6" ] +stm32g431c8 = [ "stm32-metapac/stm32g431c8" ] +stm32g431cb = [ "stm32-metapac/stm32g431cb" ] +stm32g431k6 = [ "stm32-metapac/stm32g431k6" ] +stm32g431k8 = [ "stm32-metapac/stm32g431k8" ] +stm32g431kb = [ "stm32-metapac/stm32g431kb" ] +stm32g431m6 = [ "stm32-metapac/stm32g431m6" ] +stm32g431m8 = [ "stm32-metapac/stm32g431m8" ] +stm32g431mb = [ "stm32-metapac/stm32g431mb" ] +stm32g431r6 = [ "stm32-metapac/stm32g431r6" ] +stm32g431r8 = [ "stm32-metapac/stm32g431r8" ] +stm32g431rb = [ "stm32-metapac/stm32g431rb" ] +stm32g431v6 = [ "stm32-metapac/stm32g431v6" ] +stm32g431v8 = [ "stm32-metapac/stm32g431v8" ] +stm32g431vb = [ "stm32-metapac/stm32g431vb" ] +stm32g441cb = [ "stm32-metapac/stm32g441cb" ] +stm32g441kb = [ "stm32-metapac/stm32g441kb" ] +stm32g441mb = [ "stm32-metapac/stm32g441mb" ] +stm32g441rb = [ "stm32-metapac/stm32g441rb" ] +stm32g441vb = [ "stm32-metapac/stm32g441vb" ] +stm32g471cc = [ "stm32-metapac/stm32g471cc" ] +stm32g471ce = [ "stm32-metapac/stm32g471ce" ] +stm32g471mc = [ "stm32-metapac/stm32g471mc" ] +stm32g471me = [ "stm32-metapac/stm32g471me" ] +stm32g471qc = [ "stm32-metapac/stm32g471qc" ] +stm32g471qe = [ "stm32-metapac/stm32g471qe" ] +stm32g471rc = [ "stm32-metapac/stm32g471rc" ] +stm32g471re = [ "stm32-metapac/stm32g471re" ] +stm32g471vc = [ "stm32-metapac/stm32g471vc" ] +stm32g471ve = [ "stm32-metapac/stm32g471ve" ] +stm32g473cb = [ "stm32-metapac/stm32g473cb" ] +stm32g473cc = [ "stm32-metapac/stm32g473cc" ] +stm32g473ce = [ "stm32-metapac/stm32g473ce" ] +stm32g473mb = [ "stm32-metapac/stm32g473mb" ] +stm32g473mc = [ "stm32-metapac/stm32g473mc" ] +stm32g473me = [ "stm32-metapac/stm32g473me" ] +stm32g473pb = [ "stm32-metapac/stm32g473pb" ] +stm32g473pc = [ "stm32-metapac/stm32g473pc" ] +stm32g473pe = [ "stm32-metapac/stm32g473pe" ] +stm32g473qb = [ "stm32-metapac/stm32g473qb" ] +stm32g473qc = [ "stm32-metapac/stm32g473qc" ] +stm32g473qe = [ "stm32-metapac/stm32g473qe" ] +stm32g473rb = [ "stm32-metapac/stm32g473rb" ] +stm32g473rc = [ "stm32-metapac/stm32g473rc" ] +stm32g473re = [ "stm32-metapac/stm32g473re" ] +stm32g473vb = [ "stm32-metapac/stm32g473vb" ] +stm32g473vc = [ "stm32-metapac/stm32g473vc" ] +stm32g473ve = [ "stm32-metapac/stm32g473ve" ] +stm32g474cb = [ "stm32-metapac/stm32g474cb" ] +stm32g474cc = [ "stm32-metapac/stm32g474cc" ] +stm32g474ce = [ "stm32-metapac/stm32g474ce" ] +stm32g474mb = [ "stm32-metapac/stm32g474mb" ] +stm32g474mc = [ "stm32-metapac/stm32g474mc" ] +stm32g474me = [ "stm32-metapac/stm32g474me" ] +stm32g474pb = [ "stm32-metapac/stm32g474pb" ] +stm32g474pc = [ "stm32-metapac/stm32g474pc" ] +stm32g474pe = [ "stm32-metapac/stm32g474pe" ] +stm32g474qb = [ "stm32-metapac/stm32g474qb" ] +stm32g474qc = [ "stm32-metapac/stm32g474qc" ] +stm32g474qe = [ "stm32-metapac/stm32g474qe" ] +stm32g474rb = [ "stm32-metapac/stm32g474rb" ] +stm32g474rc = [ "stm32-metapac/stm32g474rc" ] +stm32g474re = [ "stm32-metapac/stm32g474re" ] +stm32g474vb = [ "stm32-metapac/stm32g474vb" ] +stm32g474vc = [ "stm32-metapac/stm32g474vc" ] +stm32g474ve = [ "stm32-metapac/stm32g474ve" ] +stm32g483ce = [ "stm32-metapac/stm32g483ce" ] +stm32g483me = [ "stm32-metapac/stm32g483me" ] +stm32g483pe = [ "stm32-metapac/stm32g483pe" ] +stm32g483qe = [ "stm32-metapac/stm32g483qe" ] +stm32g483re = [ "stm32-metapac/stm32g483re" ] +stm32g483ve = [ "stm32-metapac/stm32g483ve" ] +stm32g484ce = [ "stm32-metapac/stm32g484ce" ] +stm32g484me = [ "stm32-metapac/stm32g484me" ] +stm32g484pe = [ "stm32-metapac/stm32g484pe" ] +stm32g484qe = [ "stm32-metapac/stm32g484qe" ] +stm32g484re = [ "stm32-metapac/stm32g484re" ] +stm32g484ve = [ "stm32-metapac/stm32g484ve" ] +stm32g491cc = [ "stm32-metapac/stm32g491cc" ] +stm32g491ce = [ "stm32-metapac/stm32g491ce" ] +stm32g491kc = [ "stm32-metapac/stm32g491kc" ] +stm32g491ke = [ "stm32-metapac/stm32g491ke" ] +stm32g491mc = [ "stm32-metapac/stm32g491mc" ] +stm32g491me = [ "stm32-metapac/stm32g491me" ] +stm32g491rc = [ "stm32-metapac/stm32g491rc" ] +stm32g491re = [ "stm32-metapac/stm32g491re" ] +stm32g491vc = [ "stm32-metapac/stm32g491vc" ] +stm32g491ve = [ "stm32-metapac/stm32g491ve" ] +stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce" ] +stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ] +stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] +stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] +stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] +stm32h503cb = [ "stm32-metapac/stm32h503cb" ] +stm32h503eb = [ "stm32-metapac/stm32h503eb" ] +stm32h503kb = [ "stm32-metapac/stm32h503kb" ] +stm32h503rb = [ "stm32-metapac/stm32h503rb" ] +stm32h562ag = [ "stm32-metapac/stm32h562ag" ] +stm32h562ai = [ "stm32-metapac/stm32h562ai" ] +stm32h562ig = [ "stm32-metapac/stm32h562ig" ] +stm32h562ii = [ "stm32-metapac/stm32h562ii" ] +stm32h562rg = [ "stm32-metapac/stm32h562rg" ] +stm32h562ri = [ "stm32-metapac/stm32h562ri" ] +stm32h562vg = [ "stm32-metapac/stm32h562vg" ] +stm32h562vi = [ "stm32-metapac/stm32h562vi" ] +stm32h562zg = [ "stm32-metapac/stm32h562zg" ] +stm32h562zi = [ "stm32-metapac/stm32h562zi" ] +stm32h563ag = [ "stm32-metapac/stm32h563ag" ] +stm32h563ai = [ "stm32-metapac/stm32h563ai" ] +stm32h563ig = [ "stm32-metapac/stm32h563ig" ] +stm32h563ii = [ "stm32-metapac/stm32h563ii" ] +stm32h563mi = [ "stm32-metapac/stm32h563mi" ] +stm32h563rg = [ "stm32-metapac/stm32h563rg" ] +stm32h563ri = [ "stm32-metapac/stm32h563ri" ] +stm32h563vg = [ "stm32-metapac/stm32h563vg" ] +stm32h563vi = [ "stm32-metapac/stm32h563vi" ] +stm32h563zg = [ "stm32-metapac/stm32h563zg" ] +stm32h563zi = [ "stm32-metapac/stm32h563zi" ] +stm32h573ai = [ "stm32-metapac/stm32h573ai" ] +stm32h573ii = [ "stm32-metapac/stm32h573ii" ] +stm32h573mi = [ "stm32-metapac/stm32h573mi" ] +stm32h573ri = [ "stm32-metapac/stm32h573ri" ] +stm32h573vi = [ "stm32-metapac/stm32h573vi" ] +stm32h573zi = [ "stm32-metapac/stm32h573zi" ] +stm32h723ve = [ "stm32-metapac/stm32h723ve" ] +stm32h723vg = [ "stm32-metapac/stm32h723vg" ] +stm32h723ze = [ "stm32-metapac/stm32h723ze" ] +stm32h723zg = [ "stm32-metapac/stm32h723zg" ] +stm32h725ae = [ "stm32-metapac/stm32h725ae" ] +stm32h725ag = [ "stm32-metapac/stm32h725ag" ] +stm32h725ie = [ "stm32-metapac/stm32h725ie" ] +stm32h725ig = [ "stm32-metapac/stm32h725ig" ] +stm32h725re = [ "stm32-metapac/stm32h725re" ] +stm32h725rg = [ "stm32-metapac/stm32h725rg" ] +stm32h725ve = [ "stm32-metapac/stm32h725ve" ] +stm32h725vg = [ "stm32-metapac/stm32h725vg" ] +stm32h725ze = [ "stm32-metapac/stm32h725ze" ] +stm32h725zg = [ "stm32-metapac/stm32h725zg" ] +stm32h730ab = [ "stm32-metapac/stm32h730ab" ] +stm32h730ib = [ "stm32-metapac/stm32h730ib" ] +stm32h730vb = [ "stm32-metapac/stm32h730vb" ] +stm32h730zb = [ "stm32-metapac/stm32h730zb" ] +stm32h733vg = [ "stm32-metapac/stm32h733vg" ] +stm32h733zg = [ "stm32-metapac/stm32h733zg" ] +stm32h735ag = [ "stm32-metapac/stm32h735ag" ] +stm32h735ig = [ "stm32-metapac/stm32h735ig" ] +stm32h735rg = [ "stm32-metapac/stm32h735rg" ] +stm32h735vg = [ "stm32-metapac/stm32h735vg" ] +stm32h735zg = [ "stm32-metapac/stm32h735zg" ] +stm32h742ag = [ "stm32-metapac/stm32h742ag" ] +stm32h742ai = [ "stm32-metapac/stm32h742ai" ] +stm32h742bg = [ "stm32-metapac/stm32h742bg" ] +stm32h742bi = [ "stm32-metapac/stm32h742bi" ] +stm32h742ig = [ "stm32-metapac/stm32h742ig" ] +stm32h742ii = [ "stm32-metapac/stm32h742ii" ] +stm32h742vg = [ "stm32-metapac/stm32h742vg" ] +stm32h742vi = [ "stm32-metapac/stm32h742vi" ] +stm32h742xg = [ "stm32-metapac/stm32h742xg" ] +stm32h742xi = [ "stm32-metapac/stm32h742xi" ] +stm32h742zg = [ "stm32-metapac/stm32h742zg" ] +stm32h742zi = [ "stm32-metapac/stm32h742zi" ] +stm32h743ag = [ "stm32-metapac/stm32h743ag" ] +stm32h743ai = [ "stm32-metapac/stm32h743ai" ] +stm32h743bg = [ "stm32-metapac/stm32h743bg" ] +stm32h743bi = [ "stm32-metapac/stm32h743bi" ] +stm32h743ig = [ "stm32-metapac/stm32h743ig" ] +stm32h743ii = [ "stm32-metapac/stm32h743ii" ] +stm32h743vg = [ "stm32-metapac/stm32h743vg" ] +stm32h743vi = [ "stm32-metapac/stm32h743vi" ] +stm32h743xg = [ "stm32-metapac/stm32h743xg" ] +stm32h743xi = [ "stm32-metapac/stm32h743xi" ] +stm32h743zg = [ "stm32-metapac/stm32h743zg" ] +stm32h743zi = [ "stm32-metapac/stm32h743zi" ] +stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ] +stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ] +stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ] +stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ] +stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ] +stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ] +stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ] +stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ] +stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ] +stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ] +stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ] +stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ] +stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ] +stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ] +stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ] +stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ] +stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ] +stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ] +stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ] +stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ] +stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ] +stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ] +stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ] +stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ] +stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ] +stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ] +stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ] +stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ] +stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ] +stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ] +stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ] +stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ] +stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ] +stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ] +stm32h750ib = [ "stm32-metapac/stm32h750ib" ] +stm32h750vb = [ "stm32-metapac/stm32h750vb" ] +stm32h750xb = [ "stm32-metapac/stm32h750xb" ] +stm32h750zb = [ "stm32-metapac/stm32h750zb" ] +stm32h753ai = [ "stm32-metapac/stm32h753ai" ] +stm32h753bi = [ "stm32-metapac/stm32h753bi" ] +stm32h753ii = [ "stm32-metapac/stm32h753ii" ] +stm32h753vi = [ "stm32-metapac/stm32h753vi" ] +stm32h753xi = [ "stm32-metapac/stm32h753xi" ] +stm32h753zi = [ "stm32-metapac/stm32h753zi" ] +stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ] +stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ] +stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ] +stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ] +stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ] +stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ] +stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ] +stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ] +stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ] +stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ] +stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ] +stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ] +stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ] +stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ] +stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ] +stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ] +stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ] +stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ] +stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] +stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] +stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] +stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii" ] +stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg" ] +stm32h7a3li = [ "stm32-metapac/stm32h7a3li" ] +stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng" ] +stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni" ] +stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi" ] +stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg" ] +stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri" ] +stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg" ] +stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi" ] +stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg" ] +stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi" ] +stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab" ] +stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib" ] +stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb" ] +stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb" ] +stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb" ] +stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai" ] +stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii" ] +stm32h7b3li = [ "stm32-metapac/stm32h7b3li" ] +stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni" ] +stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ] +stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ] +stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ] +stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ] stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] @@ -1388,86 +1393,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ] stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] -stm32l552cc = [ "stm32-metapac/stm32l552cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552ce = [ "stm32-metapac/stm32l552ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552me = [ "stm32-metapac/stm32l552me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552qc = [ "stm32-metapac/stm32l552qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552qe = [ "stm32-metapac/stm32l552qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552rc = [ "stm32-metapac/stm32l552rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552re = [ "stm32-metapac/stm32l552re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552vc = [ "stm32-metapac/stm32l552vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552ve = [ "stm32-metapac/stm32l552ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552zc = [ "stm32-metapac/stm32l552zc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l552ze = [ "stm32-metapac/stm32l552ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l562ce = [ "stm32-metapac/stm32l562ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l562me = [ "stm32-metapac/stm32l562me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l562qe = [ "stm32-metapac/stm32l562qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l562re = [ "stm32-metapac/stm32l562re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l562ve = [ "stm32-metapac/stm32l562ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32l562ze = [ "stm32-metapac/stm32l562ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535cb = [ "stm32-metapac/stm32u535cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535cc = [ "stm32-metapac/stm32u535cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535ce = [ "stm32-metapac/stm32u535ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535je = [ "stm32-metapac/stm32u535je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535nc = [ "stm32-metapac/stm32u535nc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535ne = [ "stm32-metapac/stm32u535ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535rb = [ "stm32-metapac/stm32u535rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535rc = [ "stm32-metapac/stm32u535rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535re = [ "stm32-metapac/stm32u535re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535vc = [ "stm32-metapac/stm32u535vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u535ve = [ "stm32-metapac/stm32u535ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u545ce = [ "stm32-metapac/stm32u545ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u545je = [ "stm32-metapac/stm32u545je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u545ne = [ "stm32-metapac/stm32u545ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u545re = [ "stm32-metapac/stm32u545re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u545ve = [ "stm32-metapac/stm32u545ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575ag = [ "stm32-metapac/stm32u575ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575ai = [ "stm32-metapac/stm32u575ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575cg = [ "stm32-metapac/stm32u575cg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575ci = [ "stm32-metapac/stm32u575ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575og = [ "stm32-metapac/stm32u575og", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575oi = [ "stm32-metapac/stm32u575oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575qg = [ "stm32-metapac/stm32u575qg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575qi = [ "stm32-metapac/stm32u575qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575rg = [ "stm32-metapac/stm32u575rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575ri = [ "stm32-metapac/stm32u575ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575vg = [ "stm32-metapac/stm32u575vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575vi = [ "stm32-metapac/stm32u575vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575zg = [ "stm32-metapac/stm32u575zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u575zi = [ "stm32-metapac/stm32u575zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u585ai = [ "stm32-metapac/stm32u585ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u585ci = [ "stm32-metapac/stm32u585ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u585oi = [ "stm32-metapac/stm32u585oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u585qi = [ "stm32-metapac/stm32u585qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u585ri = [ "stm32-metapac/stm32u585ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u585vi = [ "stm32-metapac/stm32u585vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u585zi = [ "stm32-metapac/stm32u585zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595ai = [ "stm32-metapac/stm32u595ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595aj = [ "stm32-metapac/stm32u595aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595qi = [ "stm32-metapac/stm32u595qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595qj = [ "stm32-metapac/stm32u595qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595ri = [ "stm32-metapac/stm32u595ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595rj = [ "stm32-metapac/stm32u595rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595vi = [ "stm32-metapac/stm32u595vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595vj = [ "stm32-metapac/stm32u595vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595zi = [ "stm32-metapac/stm32u595zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u595zj = [ "stm32-metapac/stm32u595zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u599bj = [ "stm32-metapac/stm32u599bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u599ni = [ "stm32-metapac/stm32u599ni", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u599nj = [ "stm32-metapac/stm32u599nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u599vi = [ "stm32-metapac/stm32u599vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u599vj = [ "stm32-metapac/stm32u599vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u599zi = [ "stm32-metapac/stm32u599zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u599zj = [ "stm32-metapac/stm32u599zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] -stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] +stm32l552cc = [ "stm32-metapac/stm32l552cc" ] +stm32l552ce = [ "stm32-metapac/stm32l552ce" ] +stm32l552me = [ "stm32-metapac/stm32l552me" ] +stm32l552qc = [ "stm32-metapac/stm32l552qc" ] +stm32l552qe = [ "stm32-metapac/stm32l552qe" ] +stm32l552rc = [ "stm32-metapac/stm32l552rc" ] +stm32l552re = [ "stm32-metapac/stm32l552re" ] +stm32l552vc = [ "stm32-metapac/stm32l552vc" ] +stm32l552ve = [ "stm32-metapac/stm32l552ve" ] +stm32l552zc = [ "stm32-metapac/stm32l552zc" ] +stm32l552ze = [ "stm32-metapac/stm32l552ze" ] +stm32l562ce = [ "stm32-metapac/stm32l562ce" ] +stm32l562me = [ "stm32-metapac/stm32l562me" ] +stm32l562qe = [ "stm32-metapac/stm32l562qe" ] +stm32l562re = [ "stm32-metapac/stm32l562re" ] +stm32l562ve = [ "stm32-metapac/stm32l562ve" ] +stm32l562ze = [ "stm32-metapac/stm32l562ze" ] +stm32u535cb = [ "stm32-metapac/stm32u535cb" ] +stm32u535cc = [ "stm32-metapac/stm32u535cc" ] +stm32u535ce = [ "stm32-metapac/stm32u535ce" ] +stm32u535je = [ "stm32-metapac/stm32u535je" ] +stm32u535nc = [ "stm32-metapac/stm32u535nc" ] +stm32u535ne = [ "stm32-metapac/stm32u535ne" ] +stm32u535rb = [ "stm32-metapac/stm32u535rb" ] +stm32u535rc = [ "stm32-metapac/stm32u535rc" ] +stm32u535re = [ "stm32-metapac/stm32u535re" ] +stm32u535vc = [ "stm32-metapac/stm32u535vc" ] +stm32u535ve = [ "stm32-metapac/stm32u535ve" ] +stm32u545ce = [ "stm32-metapac/stm32u545ce" ] +stm32u545je = [ "stm32-metapac/stm32u545je" ] +stm32u545ne = [ "stm32-metapac/stm32u545ne" ] +stm32u545re = [ "stm32-metapac/stm32u545re" ] +stm32u545ve = [ "stm32-metapac/stm32u545ve" ] +stm32u575ag = [ "stm32-metapac/stm32u575ag" ] +stm32u575ai = [ "stm32-metapac/stm32u575ai" ] +stm32u575cg = [ "stm32-metapac/stm32u575cg" ] +stm32u575ci = [ "stm32-metapac/stm32u575ci" ] +stm32u575og = [ "stm32-metapac/stm32u575og" ] +stm32u575oi = [ "stm32-metapac/stm32u575oi" ] +stm32u575qg = [ "stm32-metapac/stm32u575qg" ] +stm32u575qi = [ "stm32-metapac/stm32u575qi" ] +stm32u575rg = [ "stm32-metapac/stm32u575rg" ] +stm32u575ri = [ "stm32-metapac/stm32u575ri" ] +stm32u575vg = [ "stm32-metapac/stm32u575vg" ] +stm32u575vi = [ "stm32-metapac/stm32u575vi" ] +stm32u575zg = [ "stm32-metapac/stm32u575zg" ] +stm32u575zi = [ "stm32-metapac/stm32u575zi" ] +stm32u585ai = [ "stm32-metapac/stm32u585ai" ] +stm32u585ci = [ "stm32-metapac/stm32u585ci" ] +stm32u585oi = [ "stm32-metapac/stm32u585oi" ] +stm32u585qi = [ "stm32-metapac/stm32u585qi" ] +stm32u585ri = [ "stm32-metapac/stm32u585ri" ] +stm32u585vi = [ "stm32-metapac/stm32u585vi" ] +stm32u585zi = [ "stm32-metapac/stm32u585zi" ] +stm32u595ai = [ "stm32-metapac/stm32u595ai" ] +stm32u595aj = [ "stm32-metapac/stm32u595aj" ] +stm32u595qi = [ "stm32-metapac/stm32u595qi" ] +stm32u595qj = [ "stm32-metapac/stm32u595qj" ] +stm32u595ri = [ "stm32-metapac/stm32u595ri" ] +stm32u595rj = [ "stm32-metapac/stm32u595rj" ] +stm32u595vi = [ "stm32-metapac/stm32u595vi" ] +stm32u595vj = [ "stm32-metapac/stm32u595vj" ] +stm32u595zi = [ "stm32-metapac/stm32u595zi" ] +stm32u595zj = [ "stm32-metapac/stm32u595zj" ] +stm32u599bj = [ "stm32-metapac/stm32u599bj" ] +stm32u599ni = [ "stm32-metapac/stm32u599ni" ] +stm32u599nj = [ "stm32-metapac/stm32u599nj" ] +stm32u599vi = [ "stm32-metapac/stm32u599vi" ] +stm32u599vj = [ "stm32-metapac/stm32u599vj" ] +stm32u599zi = [ "stm32-metapac/stm32u599zi" ] +stm32u599zj = [ "stm32-metapac/stm32u599zj" ] +stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] +stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] +stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] +stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] +stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ] +stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ] +stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ] +stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ] +stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ] stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 36139a45c..135010011 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs @@ -1,4 +1,5 @@ //! Enums shared between CAN controller types. +use core::convert::TryFrom; /// Bus error #[derive(Debug)] @@ -28,3 +29,19 @@ pub enum BusError { /// At least one of error counter has reached the Error_Warning limit of 96. BusWarning, } +impl TryFrom for BusError { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + //0b000 => None, + 0b001 => Ok(Self::Stuff), + 0b010 => Ok(Self::Form), + 0b011 => Ok(Self::Acknowledge), + 0b100 => Ok(Self::BitRecessive), + 0b101 => Ok(Self::BitDominant), + 0b110 => Ok(Self::Crc), + //0b111 => Ok(Self::NoError), + _ => Err(()), + } + } +} diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs new file mode 100644 index 000000000..38b409121 --- /dev/null +++ b/embassy-stm32/src/can/fd/config.rs @@ -0,0 +1,438 @@ +//! Configuration for FDCAN Module +//! Note: This file is copied and modified from fdcan crate by Richard Meadows + +use core::num::{NonZeroU16, NonZeroU8}; + +/// Configures the bit timings. +/// +/// You can use to calculate the `btr` parameter. Enter +/// parameters as follows: +/// +/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). +/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). +/// - *Sample Point*: Should normally be left at the default value of 87.5%. +/// - *SJW*: Should normally be left at the default value of 1. +/// +/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` +/// parameter to this method. +#[derive(Clone, Copy, Debug)] +pub struct NominalBitTiming { + /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit + /// time is built up from a multiple of this quanta. Valid values are 1 to 512. + pub prescaler: NonZeroU16, + /// Valid values are 1 to 128. + pub seg1: NonZeroU8, + /// Valid values are 1 to 255. + pub seg2: NonZeroU8, + /// Valid values are 1 to 128. + pub sync_jump_width: NonZeroU8, +} +impl NominalBitTiming { + #[inline] + pub(crate) fn nbrp(&self) -> u16 { + u16::from(self.prescaler) & 0x1FF + } + #[inline] + pub(crate) fn ntseg1(&self) -> u8 { + u8::from(self.seg1) + } + #[inline] + pub(crate) fn ntseg2(&self) -> u8 { + u8::from(self.seg2) & 0x7F + } + #[inline] + pub(crate) fn nsjw(&self) -> u8 { + u8::from(self.sync_jump_width) & 0x7F + } +} + +impl Default for NominalBitTiming { + #[inline] + fn default() -> Self { + // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a NBTP + // register value of 0x0600_0A03 + Self { + prescaler: NonZeroU16::new(1).unwrap(), + seg1: NonZeroU8::new(11).unwrap(), + seg2: NonZeroU8::new(4).unwrap(), + sync_jump_width: NonZeroU8::new(4).unwrap(), + } + } +} + +/// Configures the data bit timings for the FdCan Variable Bitrates. +/// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. +#[derive(Clone, Copy, Debug)] +pub struct DataBitTiming { + /// Tranceiver Delay Compensation + pub transceiver_delay_compensation: bool, + /// The value by which the oscillator frequency is divided to generate the bit time quanta. The bit + /// time is built up from a multiple of this quanta. Valid values for the Baud Rate Prescaler are 1 + /// to 31. + pub prescaler: NonZeroU16, + /// Valid values are 1 to 31. + pub seg1: NonZeroU8, + /// Valid values are 1 to 15. + pub seg2: NonZeroU8, + /// Must always be smaller than DTSEG2, valid values are 1 to 15. + pub sync_jump_width: NonZeroU8, +} +impl DataBitTiming { + // #[inline] + // fn tdc(&self) -> u8 { + // let tsd = self.transceiver_delay_compensation as u8; + // //TODO: stm32g4 does not export the TDC field + // todo!() + // } + #[inline] + pub(crate) fn dbrp(&self) -> u8 { + (u16::from(self.prescaler) & 0x001F) as u8 + } + #[inline] + pub(crate) fn dtseg1(&self) -> u8 { + u8::from(self.seg1) & 0x1F + } + #[inline] + pub(crate) fn dtseg2(&self) -> u8 { + u8::from(self.seg2) & 0x0F + } + #[inline] + pub(crate) fn dsjw(&self) -> u8 { + u8::from(self.sync_jump_width) & 0x0F + } +} + +impl Default for DataBitTiming { + #[inline] + fn default() -> Self { + // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a DBTP + // register value of 0x0000_0A33 + Self { + transceiver_delay_compensation: false, + prescaler: NonZeroU16::new(1).unwrap(), + seg1: NonZeroU8::new(11).unwrap(), + seg2: NonZeroU8::new(4).unwrap(), + sync_jump_width: NonZeroU8::new(4).unwrap(), + } + } +} + +/// Configures which modes to use +/// Individual headers can contain a desire to be send via FdCan +/// or use Bit rate switching. But if this general setting does not allow +/// that, only classic CAN is used instead. +#[derive(Clone, Copy, Debug)] +pub enum FrameTransmissionConfig { + /// Only allow Classic CAN message Frames + ClassicCanOnly, + /// Allow (non-brs) FdCAN Message Frames + AllowFdCan, + /// Allow FdCAN Message Frames and allow Bit Rate Switching + AllowFdCanAndBRS, +} + +/// +#[derive(Clone, Copy, Debug)] +pub enum ClockDivider { + /// Divide by 1 + _1 = 0b0000, + /// Divide by 2 + _2 = 0b0001, + /// Divide by 4 + _4 = 0b0010, + /// Divide by 6 + _6 = 0b0011, + /// Divide by 8 + _8 = 0b0100, + /// Divide by 10 + _10 = 0b0101, + /// Divide by 12 + _12 = 0b0110, + /// Divide by 14 + _14 = 0b0111, + /// Divide by 16 + _16 = 0b1000, + /// Divide by 18 + _18 = 0b1001, + /// Divide by 20 + _20 = 0b1010, + /// Divide by 22 + _22 = 0b1011, + /// Divide by 24 + _24 = 0b1100, + /// Divide by 26 + _26 = 0b1101, + /// Divide by 28 + _28 = 0b1110, + /// Divide by 30 + _30 = 0b1111, +} + +/// Prescaler of the Timestamp counter +#[derive(Clone, Copy, Debug)] +pub enum TimestampPrescaler { + /// 1 + _1 = 1, + /// 2 + _2 = 2, + /// 3 + _3 = 3, + /// 4 + _4 = 4, + /// 5 + _5 = 5, + /// 6 + _6 = 6, + /// 7 + _7 = 7, + /// 8 + _8 = 8, + /// 9 + _9 = 9, + /// 10 + _10 = 10, + /// 11 + _11 = 11, + /// 12 + _12 = 12, + /// 13 + _13 = 13, + /// 14 + _14 = 14, + /// 15 + _15 = 15, + /// 16 + _16 = 16, +} + +/// Selects the source of the Timestamp counter +#[derive(Clone, Copy, Debug)] +pub enum TimestampSource { + /// The Timestamp counter is disabled + None, + /// Using the FdCan input clock as the Timstamp counter's source, + /// and using a specific prescaler + Prescaler(TimestampPrescaler), + /// Using TIM3 as a source + FromTIM3, +} + +/// How to handle frames in the global filter +#[derive(Clone, Copy, Debug)] +pub enum NonMatchingFilter { + /// Frames will go to Fifo0 when they do no match any specific filter + IntoRxFifo0 = 0b00, + /// Frames will go to Fifo1 when they do no match any specific filter + IntoRxFifo1 = 0b01, + /// Frames will be rejected when they do not match any specific filter + Reject = 0b11, +} + +/// How to handle frames which do not match a specific filter +#[derive(Clone, Copy, Debug)] +pub struct GlobalFilter { + /// How to handle non-matching standard frames + pub handle_standard_frames: NonMatchingFilter, + + /// How to handle non-matching extended frames + pub handle_extended_frames: NonMatchingFilter, + + /// How to handle remote standard frames + pub reject_remote_standard_frames: bool, + + /// How to handle remote extended frames + pub reject_remote_extended_frames: bool, +} +impl GlobalFilter { + /// Reject all non-matching and remote frames + pub const fn reject_all() -> Self { + Self { + handle_standard_frames: NonMatchingFilter::Reject, + handle_extended_frames: NonMatchingFilter::Reject, + reject_remote_standard_frames: true, + reject_remote_extended_frames: true, + } + } + + /// How to handle non-matching standard frames + pub const fn set_handle_standard_frames(mut self, filter: NonMatchingFilter) -> Self { + self.handle_standard_frames = filter; + self + } + /// How to handle non-matching exteded frames + pub const fn set_handle_extended_frames(mut self, filter: NonMatchingFilter) -> Self { + self.handle_extended_frames = filter; + self + } + /// How to handle remote standard frames + pub const fn set_reject_remote_standard_frames(mut self, filter: bool) -> Self { + self.reject_remote_standard_frames = filter; + self + } + /// How to handle remote extended frames + pub const fn set_reject_remote_extended_frames(mut self, filter: bool) -> Self { + self.reject_remote_extended_frames = filter; + self + } +} +impl Default for GlobalFilter { + #[inline] + fn default() -> Self { + Self { + handle_standard_frames: NonMatchingFilter::IntoRxFifo0, + handle_extended_frames: NonMatchingFilter::IntoRxFifo0, + reject_remote_standard_frames: false, + reject_remote_extended_frames: false, + } + } +} + +/// FdCan Config Struct +#[derive(Clone, Copy, Debug)] +pub struct FdCanConfig { + /// Nominal Bit Timings + pub nbtr: NominalBitTiming, + /// (Variable) Data Bit Timings + pub dbtr: DataBitTiming, + /// Enables or disables automatic retransmission of messages + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// util it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + pub automatic_retransmit: bool, + /// Enabled or disables the pausing between transmissions + /// + /// This feature looses up burst transmissions coming from a single node and it protects against + /// "babbling idiot" scenarios where the application program erroneously requests too many + /// transmissions. + pub transmit_pause: bool, + /// Enabled or disables the pausing between transmissions + /// + /// This feature looses up burst transmissions coming from a single node and it protects against + /// "babbling idiot" scenarios where the application program erroneously requests too many + /// transmissions. + pub frame_transmit: FrameTransmissionConfig, + /// Non Isoe Mode + /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN + /// FD Specification V1.0. + pub non_iso_mode: bool, + /// Edge Filtering: Two consecutive dominant tq required to detect an edge for hard synchronization + pub edge_filtering: bool, + /// Enables protocol exception handling + pub protocol_exception_handling: bool, + /// Sets the general clock divider for this FdCAN instance + pub clock_divider: ClockDivider, + /// Sets the timestamp source + pub timestamp_source: TimestampSource, + /// Configures the Global Filter + pub global_filter: GlobalFilter, +} + +impl FdCanConfig { + /// Configures the bit timings. + #[inline] + pub const fn set_nominal_bit_timing(mut self, btr: NominalBitTiming) -> Self { + self.nbtr = btr; + self + } + + /// Configures the bit timings. + #[inline] + pub const fn set_data_bit_timing(mut self, btr: DataBitTiming) -> Self { + self.dbtr = btr; + self + } + + /// Enables or disables automatic retransmission of messages + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// util it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + #[inline] + pub const fn set_automatic_retransmit(mut self, enabled: bool) -> Self { + self.automatic_retransmit = enabled; + self + } + + /// Enabled or disables the pausing between transmissions + /// + /// This feature looses up burst transmissions coming from a single node and it protects against + /// "babbling idiot" scenarios where the application program erroneously requests too many + /// transmissions. + #[inline] + pub const fn set_transmit_pause(mut self, enabled: bool) -> Self { + self.transmit_pause = enabled; + self + } + + /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN + /// FD Specification V1.0. + #[inline] + pub const fn set_non_iso_mode(mut self, enabled: bool) -> Self { + self.non_iso_mode = enabled; + self + } + + /// Two consecutive dominant tq required to detect an edge for hard synchronization + #[inline] + pub const fn set_edge_filtering(mut self, enabled: bool) -> Self { + self.edge_filtering = enabled; + self + } + + /// Sets the allowed transmission types for messages. + #[inline] + pub const fn set_frame_transmit(mut self, fts: FrameTransmissionConfig) -> Self { + self.frame_transmit = fts; + self + } + + /// Enables protocol exception handling + #[inline] + pub const fn set_protocol_exception_handling(mut self, peh: bool) -> Self { + self.protocol_exception_handling = peh; + self + } + + /// Sets the general clock divider for this FdCAN instance + #[inline] + pub const fn set_clock_divider(mut self, div: ClockDivider) -> Self { + self.clock_divider = div; + self + } + + /// Sets the timestamp source + #[inline] + pub const fn set_timestamp_source(mut self, tss: TimestampSource) -> Self { + self.timestamp_source = tss; + self + } + + /// Sets the global filter settings + #[inline] + pub const fn set_global_filter(mut self, filter: GlobalFilter) -> Self { + self.global_filter = filter; + self + } +} + +impl Default for FdCanConfig { + #[inline] + fn default() -> Self { + Self { + nbtr: NominalBitTiming::default(), + dbtr: DataBitTiming::default(), + automatic_retransmit: true, + transmit_pause: false, + frame_transmit: FrameTransmissionConfig::ClassicCanOnly, + non_iso_mode: false, + edge_filtering: false, + protocol_exception_handling: true, + clock_divider: ClockDivider::_1, + timestamp_source: TimestampSource::None, + global_filter: GlobalFilter::default(), + } + } +} diff --git a/embassy-stm32/src/can/fd/filter.rs b/embassy-stm32/src/can/fd/filter.rs new file mode 100644 index 000000000..3e2129e6e --- /dev/null +++ b/embassy-stm32/src/can/fd/filter.rs @@ -0,0 +1,379 @@ +//! Definition of Filter structs for FDCAN Module +//! Note: This file is copied and modified from fdcan crate by Richard Meadows + +use embedded_can::{ExtendedId, StandardId}; + +use crate::can::fd::message_ram; +pub use crate::can::fd::message_ram::{EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX}; + +/// A Standard Filter +pub type StandardFilter = Filter; +/// An Extended Filter +pub type ExtendedFilter = Filter; + +impl Default for StandardFilter { + fn default() -> Self { + StandardFilter::disable() + } +} +impl Default for ExtendedFilter { + fn default() -> Self { + ExtendedFilter::disable() + } +} + +impl StandardFilter { + /// Accept all messages in FIFO 0 + pub fn accept_all_into_fifo0() -> StandardFilter { + StandardFilter { + filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, + action: Action::StoreInFifo0, + } + } + + /// Accept all messages in FIFO 1 + pub fn accept_all_into_fifo1() -> StandardFilter { + StandardFilter { + filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, + action: Action::StoreInFifo1, + } + } + + /// Reject all messages + pub fn reject_all() -> StandardFilter { + StandardFilter { + filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, + action: Action::Reject, + } + } + + /// Disable the filter + pub fn disable() -> StandardFilter { + StandardFilter { + filter: FilterType::Disabled, + action: Action::Disable, + } + } +} + +impl ExtendedFilter { + /// Accept all messages in FIFO 0 + pub fn accept_all_into_fifo0() -> ExtendedFilter { + ExtendedFilter { + filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, + action: Action::StoreInFifo0, + } + } + + /// Accept all messages in FIFO 1 + pub fn accept_all_into_fifo1() -> ExtendedFilter { + ExtendedFilter { + filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, + action: Action::StoreInFifo1, + } + } + + /// Reject all messages + pub fn reject_all() -> ExtendedFilter { + ExtendedFilter { + filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, + action: Action::Reject, + } + } + + /// Disable the filter + pub fn disable() -> ExtendedFilter { + ExtendedFilter { + filter: FilterType::Disabled, + action: Action::Disable, + } + } +} + +/// Filter Type +#[derive(Clone, Copy, Debug)] +pub enum FilterType +where + ID: Copy + Clone + core::fmt::Debug, + UNIT: Copy + Clone + core::fmt::Debug, +{ + /// Match with a range between two messages + Range { + /// First Id of the range + from: ID, + /// Last Id of the range + to: ID, + }, + /// Match with a bitmask + BitMask { + /// Filter of the bitmask + filter: UNIT, + /// Mask of the bitmask + mask: UNIT, + }, + /// Match with a single ID + DedicatedSingle(ID), + /// Match with one of two ID's + DedicatedDual(ID, ID), + /// Filter is disabled + Disabled, +} +impl From> for message_ram::enums::FilterType +where + ID: Copy + Clone + core::fmt::Debug, + UNIT: Copy + Clone + core::fmt::Debug, +{ + fn from(f: FilterType) -> Self { + match f { + FilterType::Range { to: _, from: _ } => Self::RangeFilter, + FilterType::BitMask { filter: _, mask: _ } => Self::ClassicFilter, + FilterType::DedicatedSingle(_) => Self::DualIdFilter, + FilterType::DedicatedDual(_, _) => Self::DualIdFilter, + FilterType::Disabled => Self::FilterDisabled, + } + } +} + +/// Filter Action +#[derive(Clone, Copy, Debug)] +pub enum Action { + /// No Action + Disable = 0b000, + /// Store an matching message in FIFO 0 + StoreInFifo0 = 0b001, + /// Store an matching message in FIFO 1 + StoreInFifo1 = 0b010, + /// Reject an matching message + Reject = 0b011, + /// Flag a matching message (But not store?!?) + FlagHighPrio = 0b100, + /// Flag a matching message as a High Priority message and store it in FIFO 0 + FlagHighPrioAndStoreInFifo0 = 0b101, + /// Flag a matching message as a High Priority message and store it in FIFO 1 + FlagHighPrioAndStoreInFifo1 = 0b110, +} +impl From for message_ram::enums::FilterElementConfig { + fn from(a: Action) -> Self { + match a { + Action::Disable => Self::DisableFilterElement, + Action::StoreInFifo0 => Self::StoreInFifo0, + Action::StoreInFifo1 => Self::StoreInFifo1, + Action::Reject => Self::Reject, + Action::FlagHighPrio => Self::SetPriority, + Action::FlagHighPrioAndStoreInFifo0 => Self::SetPriorityAndStoreInFifo0, + Action::FlagHighPrioAndStoreInFifo1 => Self::SetPriorityAndStoreInFifo1, + } + } +} + +/// Filter +#[derive(Clone, Copy, Debug)] +pub struct Filter +where + ID: Copy + Clone + core::fmt::Debug, + UNIT: Copy + Clone + core::fmt::Debug, +{ + /// How to match an incoming message + pub filter: FilterType, + /// What to do with a matching message + pub action: Action, +} + +/// Standard Filter Slot +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum StandardFilterSlot { + /// 0 + _0 = 0, + /// 1 + _1 = 1, + /// 2 + _2 = 2, + /// 3 + _3 = 3, + /// 4 + _4 = 4, + /// 5 + _5 = 5, + /// 6 + _6 = 6, + /// 7 + _7 = 7, + /// 8 + _8 = 8, + /// 9 + _9 = 9, + /// 10 + _10 = 10, + /// 11 + _11 = 11, + /// 12 + _12 = 12, + /// 13 + _13 = 13, + /// 14 + _14 = 14, + /// 15 + _15 = 15, + /// 16 + _16 = 16, + /// 17 + _17 = 17, + /// 18 + _18 = 18, + /// 19 + _19 = 19, + /// 20 + _20 = 20, + /// 21 + _21 = 21, + /// 22 + _22 = 22, + /// 23 + _23 = 23, + /// 24 + _24 = 24, + /// 25 + _25 = 25, + /// 26 + _26 = 26, + /// 27 + _27 = 27, +} +impl From for StandardFilterSlot { + fn from(u: u8) -> Self { + match u { + 0 => StandardFilterSlot::_0, + 1 => StandardFilterSlot::_1, + 2 => StandardFilterSlot::_2, + 3 => StandardFilterSlot::_3, + 4 => StandardFilterSlot::_4, + 5 => StandardFilterSlot::_5, + 6 => StandardFilterSlot::_6, + 7 => StandardFilterSlot::_7, + 8 => StandardFilterSlot::_8, + 9 => StandardFilterSlot::_9, + 10 => StandardFilterSlot::_10, + 11 => StandardFilterSlot::_11, + 12 => StandardFilterSlot::_12, + 13 => StandardFilterSlot::_13, + 14 => StandardFilterSlot::_14, + 15 => StandardFilterSlot::_15, + 16 => StandardFilterSlot::_16, + 17 => StandardFilterSlot::_17, + 18 => StandardFilterSlot::_18, + 19 => StandardFilterSlot::_19, + 20 => StandardFilterSlot::_20, + 21 => StandardFilterSlot::_21, + 22 => StandardFilterSlot::_22, + 23 => StandardFilterSlot::_23, + 24 => StandardFilterSlot::_24, + 25 => StandardFilterSlot::_25, + 26 => StandardFilterSlot::_26, + 27 => StandardFilterSlot::_27, + _ => panic!("Standard Filter Slot Too High!"), + } + } +} + +/// Extended Filter Slot +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum ExtendedFilterSlot { + /// 0 + _0 = 0, + /// 1 + _1 = 1, + /// 2 + _2 = 2, + /// 3 + _3 = 3, + /// 4 + _4 = 4, + /// 5 + _5 = 5, + /// 6 + _6 = 6, + /// 7 + _7 = 7, +} +impl From for ExtendedFilterSlot { + fn from(u: u8) -> Self { + match u { + 0 => ExtendedFilterSlot::_0, + 1 => ExtendedFilterSlot::_1, + 2 => ExtendedFilterSlot::_2, + 3 => ExtendedFilterSlot::_3, + 4 => ExtendedFilterSlot::_4, + 5 => ExtendedFilterSlot::_5, + 6 => ExtendedFilterSlot::_6, + 7 => ExtendedFilterSlot::_7, + _ => panic!("Extended Filter Slot Too High!"), // Should be unreachable + } + } +} + +/// Enum over both Standard and Extended Filter ID's +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum FilterId { + /// Standard Filter Slots + Standard(StandardFilterSlot), + /// Extended Filter Slots + Extended(ExtendedFilterSlot), +} + +pub(crate) trait ActivateFilter +where + ID: Copy + Clone + core::fmt::Debug, + UNIT: Copy + Clone + core::fmt::Debug, +{ + fn activate(&mut self, f: Filter); + // fn read(&self) -> Filter; +} + +impl ActivateFilter for message_ram::StandardFilter { + fn activate(&mut self, f: Filter) { + let sft = f.filter.into(); + + let (sfid1, sfid2) = match f.filter { + FilterType::Range { to, from } => (to.as_raw(), from.as_raw()), + FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()), + FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()), + FilterType::BitMask { filter, mask } => (filter, mask), + FilterType::Disabled => (0x0, 0x0), + }; + let sfec = f.action.into(); + self.write(|w| { + unsafe { w.sfid1().bits(sfid1).sfid2().bits(sfid2) } + .sft() + .set_filter_type(sft) + .sfec() + .set_filter_element_config(sfec) + }); + } + // fn read(&self) -> Filter { + // todo!() + // } +} +impl ActivateFilter for message_ram::ExtendedFilter { + fn activate(&mut self, f: Filter) { + let eft = f.filter.into(); + + let (efid1, efid2) = match f.filter { + FilterType::Range { to, from } => (to.as_raw(), from.as_raw()), + FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()), + FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()), + FilterType::BitMask { filter, mask } => (filter, mask), + FilterType::Disabled => (0x0, 0x0), + }; + let efec = f.action.into(); + self.write(|w| { + unsafe { w.efid1().bits(efid1).efid2().bits(efid2) } + .eft() + .set_filter_type(eft) + .efec() + .set_filter_element_config(efec) + }); + } + // fn read(&self) -> Filter { + // todo!() + // } +} diff --git a/embassy-stm32/src/can/fd/message_ram/common.rs b/embassy-stm32/src/can/fd/message_ram/common.rs new file mode 100644 index 000000000..a67d68fa0 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/common.rs @@ -0,0 +1,134 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +use super::enums::{ + BitRateSwitching, ErrorStateIndicator, FilterElementConfig, FilterType, FrameFormat, IdType, + RemoteTransmissionRequest, +}; +use super::generic; + +#[doc = "Reader of field `ID`"] +pub type ID_R = generic::R; + +#[doc = "Reader of field `RTR`"] +pub type RTR_R = generic::R; +impl RTR_R { + pub fn rtr(&self) -> RemoteTransmissionRequest { + match self.bits { + false => RemoteTransmissionRequest::TransmitDataFrame, + true => RemoteTransmissionRequest::TransmitRemoteFrame, + } + } + pub fn is_transmit_remote_frame(&self) -> bool { + *self == RemoteTransmissionRequest::TransmitRemoteFrame + } + pub fn is_transmit_data_frame(&self) -> bool { + *self == RemoteTransmissionRequest::TransmitDataFrame + } +} + +#[doc = "Reader of field `XTD`"] +pub type XTD_R = generic::R; +impl XTD_R { + pub fn id_type(&self) -> IdType { + match self.bits() { + false => IdType::StandardId, + true => IdType::ExtendedId, + } + } + pub fn is_standard_id(&self) -> bool { + *self == IdType::StandardId + } + pub fn is_exteded_id(&self) -> bool { + *self == IdType::ExtendedId + } +} + +#[doc = "Reader of field `ESI`"] +pub type ESI_R = generic::R; +impl ESI_R { + pub fn error_state(&self) -> ErrorStateIndicator { + match self.bits() { + false => ErrorStateIndicator::ErrorActive, + true => ErrorStateIndicator::ErrorPassive, + } + } + pub fn is_error_active(&self) -> bool { + *self == ErrorStateIndicator::ErrorActive + } + pub fn is_error_passive(&self) -> bool { + *self == ErrorStateIndicator::ErrorPassive + } +} + +#[doc = "Reader of field `DLC`"] +pub type DLC_R = generic::R; + +#[doc = "Reader of field `BRS`"] +pub type BRS_R = generic::R; +impl BRS_R { + pub fn bit_rate_switching(&self) -> BitRateSwitching { + match self.bits() { + true => BitRateSwitching::WithBRS, + false => BitRateSwitching::WithoutBRS, + } + } + pub fn is_with_brs(&self) -> bool { + *self == BitRateSwitching::WithBRS + } + pub fn is_without_brs(&self) -> bool { + *self == BitRateSwitching::WithoutBRS + } +} + +#[doc = "Reader of field `FDF`"] +pub type FDF_R = generic::R; +impl FDF_R { + pub fn frame_format(&self) -> FrameFormat { + match self.bits() { + false => FrameFormat::Standard, + true => FrameFormat::Fdcan, + } + } + pub fn is_standard_format(&self) -> bool { + *self == FrameFormat::Standard + } + pub fn is_fdcan_format(&self) -> bool { + *self == FrameFormat::Fdcan + } +} + +#[doc = "Reader of field `(X|S)FT`"] +pub type ESFT_R = generic::R; +impl ESFT_R { + #[doc = r"Gets the Filtertype"] + #[inline(always)] + pub fn to_filter_type(&self) -> FilterType { + match self.bits() { + 0b00 => FilterType::RangeFilter, + 0b01 => FilterType::DualIdFilter, + 0b10 => FilterType::ClassicFilter, + 0b11 => FilterType::FilterDisabled, + _ => unreachable!(), + } + } +} + +#[doc = "Reader of field `(E|S)FEC`"] +pub type ESFEC_R = generic::R; +impl ESFEC_R { + pub fn to_filter_element_config(&self) -> FilterElementConfig { + match self.bits() { + 0b000 => FilterElementConfig::DisableFilterElement, + 0b001 => FilterElementConfig::StoreInFifo0, + 0b010 => FilterElementConfig::StoreInFifo1, + 0b011 => FilterElementConfig::Reject, + 0b100 => FilterElementConfig::SetPriority, + 0b101 => FilterElementConfig::SetPriorityAndStoreInFifo0, + 0b110 => FilterElementConfig::SetPriorityAndStoreInFifo1, + _ => unimplemented!(), + } + } +} diff --git a/embassy-stm32/src/can/fd/message_ram/enums.rs b/embassy-stm32/src/can/fd/message_ram/enums.rs new file mode 100644 index 000000000..78285bf81 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/enums.rs @@ -0,0 +1,233 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +/// Datalength is the message length generalised over +/// the Standard (Classic) and FDCAN message types + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum DataLength { + Standard(u8), + Fdcan(u8), +} +impl DataLength { + /// Creates a DataLength type + /// + /// Uses the byte length and Type of frame as input + pub fn new(len: u8, ff: FrameFormat) -> DataLength { + match ff { + FrameFormat::Standard => match len { + 0..=8 => DataLength::Standard(len), + _ => panic!("DataLength > 8"), + }, + FrameFormat::Fdcan => match len { + 0..=64 => DataLength::Fdcan(len), + _ => panic!("DataLength > 64"), + }, + } + } + /// Specialised function to create standard frames + pub fn new_standard(len: u8) -> DataLength { + Self::new(len, FrameFormat::Standard) + } + /// Specialised function to create FDCAN frames + pub fn new_fdcan(len: u8) -> DataLength { + Self::new(len, FrameFormat::Fdcan) + } + + /// returns the length in bytes + pub fn len(&self) -> u8 { + match self { + DataLength::Standard(l) | DataLength::Fdcan(l) => *l, + } + } + + pub(crate) fn dlc(&self) -> u8 { + match self { + DataLength::Standard(l) => *l, + // See RM0433 Rev 7 Table 475. DLC coding + DataLength::Fdcan(l) => match l { + 0..=8 => *l, + 9..=12 => 9, + 13..=16 => 10, + 17..=20 => 11, + 21..=24 => 12, + 25..=32 => 13, + 33..=48 => 14, + 49..=64 => 15, + _ => panic!("DataLength > 64"), + }, + } + } +} +impl From for FrameFormat { + fn from(dl: DataLength) -> FrameFormat { + match dl { + DataLength::Standard(_) => FrameFormat::Standard, + DataLength::Fdcan(_) => FrameFormat::Fdcan, + } + } +} + +/// Wheter or not to generate an Tx Event +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Event { + /// Do not generate an Tx Event + NoEvent, + /// Generate an Tx Event with a specified ID + Event(u8), +} + +impl From for EventControl { + fn from(e: Event) -> Self { + match e { + Event::NoEvent => EventControl::DoNotStore, + Event::Event(_) => EventControl::Store, + } + } +} + +impl From> for Event { + fn from(mm: Option) -> Self { + match mm { + None => Event::NoEvent, + Some(mm) => Event::Event(mm), + } + } +} + +impl From for Option { + fn from(e: Event) -> Option { + match e { + Event::NoEvent => None, + Event::Event(mm) => Some(mm), + } + } +} + +/// TODO +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ErrorStateIndicator { + /// TODO + ErrorActive = 0, + /// TODO + ErrorPassive = 1, +} +impl From for bool { + #[inline(always)] + fn from(e: ErrorStateIndicator) -> Self { + e as u8 != 0 + } +} + +/// Type of frame, standard (classic) or FdCAN +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FrameFormat { + Standard = 0, + Fdcan = 1, +} +impl From for bool { + #[inline(always)] + fn from(e: FrameFormat) -> Self { + e as u8 != 0 + } +} + +/// Type of Id, Standard or Extended +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum IdType { + /// Standard ID + StandardId = 0, + /// Extended ID + ExtendedId = 1, +} +impl From for bool { + #[inline(always)] + fn from(e: IdType) -> Self { + e as u8 != 0 + } +} + +/// Whether the frame contains data or requests data +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum RemoteTransmissionRequest { + /// Frame contains data + TransmitDataFrame = 0, + /// frame does not contain data + TransmitRemoteFrame = 1, +} +impl From for bool { + #[inline(always)] + fn from(e: RemoteTransmissionRequest) -> Self { + e as u8 != 0 + } +} + +/// Whether BitRateSwitching should be or was enabled +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BitRateSwitching { + /// disable bit rate switching + WithoutBRS = 0, + /// enable bit rate switching + WithBRS = 1, +} +impl From for bool { + #[inline(always)] + fn from(e: BitRateSwitching) -> Self { + e as u8 != 0 + } +} + +/// Whether to store transmit Events +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum EventControl { + /// do not store an tx event + DoNotStore, + /// store transmit events + Store, +} +impl From for bool { + #[inline(always)] + fn from(e: EventControl) -> Self { + e as u8 != 0 + } +} + +/// If an received message matched any filters +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FilterFrameMatch { + /// This did match filter + DidMatch(u8), + /// This received frame did not match any specific filters + DidNotMatch, +} + +/// Type of filter to be used +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FilterType { + /// Filter uses the range between two id's + RangeFilter = 0b00, + /// The filter matches on two specific id's (or one ID checked twice) + DualIdFilter = 0b01, + /// Filter is using a bitmask + ClassicFilter = 0b10, + /// Filter is disabled + FilterDisabled = 0b11, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FilterElementConfig { + /// Filter is disabled + DisableFilterElement = 0b000, + /// Store a matching message in FIFO 0 + StoreInFifo0 = 0b001, + /// Store a matching message in FIFO 1 + StoreInFifo1 = 0b010, + /// Reject a matching message + Reject = 0b011, + /// Flag that a priority message has been received, *But do note store!*?? + SetPriority = 0b100, + /// Flag and store message in FIFO 0 + SetPriorityAndStoreInFifo0 = 0b101, + /// Flag and store message in FIFO 1 + SetPriorityAndStoreInFifo1 = 0b110, + //_Unused = 0b111, +} diff --git a/embassy-stm32/src/can/fd/message_ram/extended_filter.rs b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs new file mode 100644 index 000000000..453e9056e --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs @@ -0,0 +1,136 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +use super::common::{ESFEC_R, ESFT_R}; +use super::enums::{FilterElementConfig, FilterType}; +use super::generic; + +#[doc = "Reader of register ExtendedFilter"] +pub(crate) type R = generic::R; +#[doc = "Writer for register ExtendedFilter"] +pub(crate) type W = generic::W; +#[doc = "Register ExtendedFilter `reset()`'s"] +impl generic::ResetValue for super::ExtendedFilter { + type Type = super::ExtendedFilterType; + #[inline(always)] + fn reset_value() -> Self::Type { + // Sets filter element to Disabled + [0x0, 0x0] + } +} + +#[doc = "Reader of field `EFID2`"] +pub(crate) type EFID2_R = generic::R; +#[doc = "Write proxy for field `EFID2`"] +pub(crate) struct EFID2_W<'a> { + w: &'a mut W, +} +impl<'a> EFID2_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u32) -> &'a mut W { + self.w.bits[1] = (self.w.bits[1] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); + self.w + } +} + +#[doc = "Reader of field `EFID1`"] +pub(crate) type EFID1_R = generic::R; +#[doc = "Write proxy for field `EFID1`"] +pub(crate) struct EFID1_W<'a> { + w: &'a mut W, +} +impl<'a> EFID1_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u32) -> &'a mut W { + self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); + self.w + } +} + +#[doc = "Write proxy for field `EFEC`"] +pub(crate) struct EFEC_W<'a> { + w: &'a mut W, +} +impl<'a> EFEC_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits[0] = (self.w.bits[0] & !(0x07 << 29)) | (((value as u32) & 0x07) << 29); + self.w + } + #[doc = r"Sets the field according to FilterElementConfig"] + #[inline(always)] + pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W { + //SAFETY: FilterElementConfig only be valid options + unsafe { self.bits(fec as u8) } + } +} + +#[doc = "Write proxy for field `EFT`"] +pub(crate) struct EFT_W<'a> { + w: &'a mut W, +} +impl<'a> EFT_W<'a> { + #[doc = r"Sets the field according the FilterType"] + #[inline(always)] + pub fn set_filter_type(self, filter: FilterType) -> &'a mut W { + //SAFETY: FilterType only be valid options + unsafe { self.bits(filter as u8) } + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits[1] = (self.w.bits[1] & !(0x03 << 30)) | (((value as u32) & 0x03) << 30); + self.w + } +} + +impl R { + #[doc = "Byte 0 - Bits 0:28 - EFID1"] + #[inline(always)] + pub fn sfid1(&self) -> EFID1_R { + EFID1_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) + } + #[doc = "Byte 0 - Bits 29:31 - EFEC"] + #[inline(always)] + pub fn efec(&self) -> ESFEC_R { + ESFEC_R::new(((self.bits[0] >> 29) & 0x07) as u8) + } + #[doc = "Byte 1 - Bits 0:28 - EFID2"] + #[inline(always)] + pub fn sfid2(&self) -> EFID2_R { + EFID2_R::new(((self.bits[1]) & 0x1FFFFFFF) as u32) + } + #[doc = "Byte 1 - Bits 30:31 - EFT"] + #[inline(always)] + pub fn eft(&self) -> ESFT_R { + ESFT_R::new(((self.bits[1] >> 30) & 0x03) as u8) + } +} +impl W { + #[doc = "Byte 0 - Bits 0:28 - EFID1"] + #[inline(always)] + pub fn efid1(&mut self) -> EFID1_W { + EFID1_W { w: self } + } + #[doc = "Byte 0 - Bits 29:31 - EFEC"] + #[inline(always)] + pub fn efec(&mut self) -> EFEC_W { + EFEC_W { w: self } + } + #[doc = "Byte 1 - Bits 0:28 - EFID2"] + #[inline(always)] + pub fn efid2(&mut self) -> EFID2_W { + EFID2_W { w: self } + } + #[doc = "Byte 1 - Bits 30:31 - EFT"] + #[inline(always)] + pub fn eft(&mut self) -> EFT_W { + EFT_W { w: self } + } +} diff --git a/embassy-stm32/src/can/fd/message_ram/generic.rs b/embassy-stm32/src/can/fd/message_ram/generic.rs new file mode 100644 index 000000000..1a5e121b4 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/generic.rs @@ -0,0 +1,168 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +use core::marker; + +///This trait shows that register has `read` method +/// +///Registers marked with `Writable` can be also `modify`'ed +pub trait Readable {} + +///This trait shows that register has `write`, `write_with_zero` and `reset` method +/// +///Registers marked with `Readable` can be also `modify`'ed +pub trait Writable {} + +///Reset value of the register +/// +///This value is initial value for `write` method. +///It can be also directly writed to register by `reset` method. +pub trait ResetValue { + ///Register size + type Type; + ///Reset value of the register + fn reset_value() -> Self::Type; +} + +///This structure provides volatile access to register +pub struct Reg { + register: vcell::VolatileCell, + _marker: marker::PhantomData, +} + +unsafe impl Send for Reg {} + +impl Reg +where + Self: Readable, + U: Copy, +{ + ///Reads the contents of `Readable` register + /// + ///You can read the contents of a register in such way: + ///```ignore + ///let bits = periph.reg.read().bits(); + ///``` + ///or get the content of a particular field of a register. + ///```ignore + ///let reader = periph.reg.read(); + ///let bits = reader.field1().bits(); + ///let flag = reader.field2().bit_is_set(); + ///``` + #[inline(always)] + pub fn read(&self) -> R { + R { + bits: self.register.get(), + _reg: marker::PhantomData, + } + } +} + +impl Reg +where + Self: ResetValue + Writable, + U: Copy, +{ + ///Writes the reset value to `Writable` register + /// + ///Resets the register to its initial state + #[inline(always)] + pub fn reset(&self) { + self.register.set(Self::reset_value()) + } +} + +impl Reg +where + Self: ResetValue + Writable, + U: Copy, +{ + ///Writes bits to `Writable` register + /// + ///You can write raw bits into a register: + ///```ignore + ///periph.reg.write(|w| unsafe { w.bits(rawbits) }); + ///``` + ///or write only the fields you need: + ///```ignore + ///periph.reg.write(|w| w + /// .field1().bits(newfield1bits) + /// .field2().set_bit() + /// .field3().variant(VARIANT) + ///); + ///``` + ///Other fields will have reset value. + #[inline(always)] + pub fn write(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W, + { + self.register.set( + f(&mut W { + bits: Self::reset_value(), + _reg: marker::PhantomData, + }) + .bits, + ); + } +} + +///Register/field reader +/// +///Result of the [`read`](Reg::read) method of a register. +///Also it can be used in the [`modify`](Reg::read) method +pub struct R { + pub(crate) bits: U, + _reg: marker::PhantomData, +} + +impl R +where + U: Copy, +{ + ///Create new instance of reader + #[inline(always)] + pub(crate) fn new(bits: U) -> Self { + Self { + bits, + _reg: marker::PhantomData, + } + } + ///Read raw bits from register/field + #[inline(always)] + pub fn bits(&self) -> U { + self.bits + } +} + +impl PartialEq for R +where + U: PartialEq, + FI: Copy + Into, +{ + #[inline(always)] + fn eq(&self, other: &FI) -> bool { + self.bits.eq(&(*other).into()) + } +} + +impl R { + ///Value of the field as raw bits + #[inline(always)] + pub fn bit(&self) -> bool { + self.bits + } + ///Returns `true` if the bit is clear (0) + #[inline(always)] + pub fn bit_is_clear(&self) -> bool { + !self.bit() + } +} + +///Register writer +/// +///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register +pub struct W { + ///Writable bits + pub(crate) bits: U, + _reg: marker::PhantomData, +} diff --git a/embassy-stm32/src/can/fd/message_ram/mod.rs b/embassy-stm32/src/can/fd/message_ram/mod.rs new file mode 100644 index 000000000..830edf3bb --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/mod.rs @@ -0,0 +1,170 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +use volatile_register::RW; + +pub(crate) mod common; +pub(crate) mod enums; +pub(crate) mod generic; + +/// Number of Receive Fifos configured by this module +pub const RX_FIFOS_MAX: u8 = 2; +/// Number of Receive Messages per RxFifo configured by this module +pub const RX_FIFO_MAX: u8 = 3; +/// Number of Transmit Messages configured by this module +pub const TX_FIFO_MAX: u8 = 3; +/// Number of Transmit Events configured by this module +pub const TX_EVENT_MAX: u8 = 3; +/// Number of Standard Filters configured by this module +pub const STANDARD_FILTER_MAX: u8 = 28; +/// Number of Extended Filters configured by this module +pub const EXTENDED_FILTER_MAX: u8 = 8; + +/// MessageRam Overlay +#[repr(C)] +pub struct RegisterBlock { + pub(crate) filters: Filters, + pub(crate) receive: [Receive; RX_FIFOS_MAX as usize], + pub(crate) transmit: Transmit, +} +impl RegisterBlock { + pub fn reset(&mut self) { + self.filters.reset(); + self.receive[0].reset(); + self.receive[1].reset(); + self.transmit.reset(); + } +} + +#[repr(C)] +pub(crate) struct Filters { + pub(crate) flssa: [StandardFilter; STANDARD_FILTER_MAX as usize], + pub(crate) flesa: [ExtendedFilter; EXTENDED_FILTER_MAX as usize], +} +impl Filters { + pub fn reset(&mut self) { + for sf in &mut self.flssa { + sf.reset(); + } + for ef in &mut self.flesa { + ef.reset(); + } + } +} + +#[repr(C)] +pub(crate) struct Receive { + pub(crate) fxsa: [RxFifoElement; RX_FIFO_MAX as usize], +} +impl Receive { + pub fn reset(&mut self) { + for fe in &mut self.fxsa { + fe.reset(); + } + } +} + +#[repr(C)] +pub(crate) struct Transmit { + pub(crate) efsa: [TxEventElement; TX_EVENT_MAX as usize], + pub(crate) tbsa: [TxBufferElement; TX_FIFO_MAX as usize], +} +impl Transmit { + pub fn reset(&mut self) { + for ee in &mut self.efsa { + ee.reset(); + } + for be in &mut self.tbsa { + be.reset(); + } + } +} + +pub(crate) mod standard_filter; +pub(crate) type StandardFilterType = u32; +pub(crate) type StandardFilter = generic::Reg; +pub(crate) struct _StandardFilter; +impl generic::Readable for StandardFilter {} +impl generic::Writable for StandardFilter {} + +pub(crate) mod extended_filter; +pub(crate) type ExtendedFilterType = [u32; 2]; +pub(crate) type ExtendedFilter = generic::Reg; +pub(crate) struct _ExtendedFilter; +impl generic::Readable for ExtendedFilter {} +impl generic::Writable for ExtendedFilter {} + +pub(crate) mod txevent_element; +pub(crate) type TxEventElementType = [u32; 2]; +pub(crate) type TxEventElement = generic::Reg; +pub(crate) struct _TxEventElement; +impl generic::Readable for TxEventElement {} +impl generic::Writable for TxEventElement {} + +pub(crate) mod rxfifo_element; +#[repr(C)] +pub(crate) struct RxFifoElement { + pub(crate) header: RxFifoElementHeader, + pub(crate) data: [RW; 16], +} +impl RxFifoElement { + pub(crate) fn reset(&mut self) { + self.header.reset(); + for byte in self.data.iter_mut() { + unsafe { byte.write(0) }; + } + } +} +pub(crate) type RxFifoElementHeaderType = [u32; 2]; +pub(crate) type RxFifoElementHeader = generic::Reg; +pub(crate) struct _RxFifoElement; +impl generic::Readable for RxFifoElementHeader {} +impl generic::Writable for RxFifoElementHeader {} + +pub(crate) mod txbuffer_element; +#[repr(C)] +pub(crate) struct TxBufferElement { + pub(crate) header: TxBufferElementHeader, + pub(crate) data: [RW; 16], +} +impl TxBufferElement { + pub(crate) fn reset(&mut self) { + self.header.reset(); + for byte in self.data.iter_mut() { + unsafe { byte.write(0) }; + } + } +} +pub(crate) type TxBufferElementHeader = generic::Reg; +pub(crate) type TxBufferElementHeaderType = [u32; 2]; +pub(crate) struct _TxBufferElement; +impl generic::Readable for TxBufferElementHeader {} +impl generic::Writable for TxBufferElementHeader {} + +/// FdCan Message RAM instance. +/// +/// # Safety +/// +/// It is only safe to implement this trait, when: +/// +/// * The implementing type has ownership of the Message RAM, preventing any +/// other accesses to the register block. +/// * `MSG_RAM` is a pointer to the Message RAM block and can be safely accessed +/// for as long as ownership or a borrow of the implementing type is present. +pub unsafe trait Instance { + const MSG_RAM: *mut RegisterBlock; + fn msg_ram(&self) -> &RegisterBlock { + unsafe { &*Self::MSG_RAM } + } + fn msg_ram_mut(&mut self) -> &mut RegisterBlock { + unsafe { &mut *Self::MSG_RAM } + } +} + +// Ensure the RegisterBlock is the same size as on pg 1957 of RM0440. +static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]); +static_assertions::assert_eq_size!(Receive, [u32; 54]); +static_assertions::assert_eq_size!(Transmit, [u32; 6 + 54]); +static_assertions::assert_eq_size!( + RegisterBlock, + [u32; 28 /*Standard Filters*/ +16 /*Extended Filters*/ +54 /*RxFifo0*/ +54 /*RxFifo1*/ +6 /*TxEvent*/ +54 /*TxFifo */] +); diff --git a/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs b/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs new file mode 100644 index 000000000..48fc3a091 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs @@ -0,0 +1,122 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R}; +use super::enums::{DataLength, FilterFrameMatch, FrameFormat}; +use super::generic; + +#[doc = "Reader of register RxFifoElement"] +pub(crate) type R = generic::R; +// #[doc = "Writer for register ExtendedFilter"] +// pub(crate) type W = generic::W; +#[doc = "Register ExtendedFilter `reset()`'s"] +impl generic::ResetValue for super::RxFifoElementHeader { + type Type = super::RxFifoElementHeaderType; + #[inline(always)] + fn reset_value() -> Self::Type { + [0x0, 0x0] + } +} + +#[doc = "Reader of field `RXTS`"] +pub(crate) type RXTS_R = generic::R; + +#[doc = "Reader of field `FIDX`"] +pub(crate) type FIDX_R = generic::R; + +pub(crate) struct _ANMF; +#[doc = "Reader of field `ANMF`"] +pub(crate) type ANMF_R = generic::R; +impl ANMF_R { + pub fn is_matching_frame(&self) -> bool { + self.bit_is_clear() + } +} + +impl R { + #[doc = "Byte 0 - Bits 0:28 - ID"] + #[inline(always)] + pub fn id(&self) -> ID_R { + ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) + } + #[doc = "Byte 0 - Bit 29 - RTR"] + #[inline(always)] + pub fn rtr(&self) -> RTR_R { + RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) + } + #[doc = "Byte 0 - Bit 30 - XTD"] + #[inline(always)] + pub fn xtd(&self) -> XTD_R { + XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) + } + #[doc = "Byte 0 - Bit 30 - ESI"] + #[inline(always)] + pub fn esi(&self) -> ESI_R { + ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 0:15 - RXTS"] + #[inline(always)] + pub fn txts(&self) -> RXTS_R { + RXTS_R::new(((self.bits[1]) & 0xFFFF) as u16) + } + #[doc = "Byte 1 - Bits 16:19 - DLC"] + #[inline(always)] + pub fn dlc(&self) -> DLC_R { + DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) + } + #[doc = "Byte 1 - Bits 20 - BRS"] + #[inline(always)] + pub fn brs(&self) -> BRS_R { + BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 20 - FDF"] + #[inline(always)] + pub fn fdf(&self) -> FDF_R { + FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 24:30 - FIDX"] + #[inline(always)] + pub fn fidx(&self) -> FIDX_R { + FIDX_R::new(((self.bits[1] >> 24) & 0xFF) as u8) + } + #[doc = "Byte 1 - Bits 31 - ANMF"] + #[inline(always)] + pub fn anmf(&self) -> ANMF_R { + ANMF_R::new(((self.bits[1] >> 31) & 0x01) != 0) + } + pub fn to_data_length(&self) -> DataLength { + let dlc = self.dlc().bits(); + let ff = self.fdf().frame_format(); + let len = if ff == FrameFormat::Fdcan { + // See RM0433 Rev 7 Table 475. DLC coding + match dlc { + 0..=8 => dlc, + 9 => 12, + 10 => 16, + 11 => 20, + 12 => 24, + 13 => 32, + 14 => 48, + 15 => 64, + _ => panic!("DLC > 15"), + } + } else { + match dlc { + 0..=8 => dlc, + 9..=15 => 8, + _ => panic!("DLC > 15"), + } + }; + DataLength::new(len, ff) + } + pub fn to_filter_match(&self) -> FilterFrameMatch { + if self.anmf().is_matching_frame() { + FilterFrameMatch::DidMatch(self.fidx().bits()) + } else { + FilterFrameMatch::DidNotMatch + } + } +} diff --git a/embassy-stm32/src/can/fd/message_ram/standard_filter.rs b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs new file mode 100644 index 000000000..3a3bbcf12 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs @@ -0,0 +1,136 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +use super::common::{ESFEC_R, ESFT_R}; +use super::enums::{FilterElementConfig, FilterType}; +use super::generic; + +#[doc = "Reader of register StandardFilter"] +pub(crate) type R = generic::R; +#[doc = "Writer for register StandardFilter"] +pub(crate) type W = generic::W; +#[doc = "Register StandardFilter `reset()`'s with value 0xC0000"] +impl generic::ResetValue for super::StandardFilter { + type Type = super::StandardFilterType; + #[inline(always)] + fn reset_value() -> Self::Type { + // Sets filter element to Disabled + 0xC000 + } +} + +#[doc = "Reader of field `SFID2`"] +pub(crate) type SFID2_R = generic::R; +#[doc = "Write proxy for field `SFID2`"] +pub(crate) struct SFID2_W<'a> { + w: &'a mut W, +} +impl<'a> SFID2_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u16) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x07ff)) | ((value as u32) & 0x07ff); + self.w + } +} + +#[doc = "Reader of field `SFID1`"] +pub(crate) type SFID1_R = generic::R; +#[doc = "Write proxy for field `SFID1`"] +pub(crate) struct SFID1_W<'a> { + w: &'a mut W, +} +impl<'a> SFID1_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u16) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x07ff << 16)) | (((value as u32) & 0x07ff) << 16); + self.w + } +} + +#[doc = "Write proxy for field `SFEC`"] +pub(crate) struct SFEC_W<'a> { + w: &'a mut W, +} +impl<'a> SFEC_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x07 << 27)) | (((value as u32) & 0x07) << 27); + self.w + } + #[doc = r"Sets the field according to FilterElementConfig"] + #[inline(always)] + pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W { + //SAFETY: FilterElementConfig only be valid options + unsafe { self.bits(fec as u8) } + } +} + +#[doc = "Write proxy for field `SFT`"] +pub(crate) struct SFT_W<'a> { + w: &'a mut W, +} +impl<'a> SFT_W<'a> { + #[doc = r"Sets the field according the FilterType"] + #[inline(always)] + pub fn set_filter_type(self, filter: FilterType) -> &'a mut W { + //SAFETY: FilterType only be valid options + unsafe { self.bits(filter as u8) } + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x03 << 30)) | (((value as u32) & 0x03) << 30); + self.w + } +} + +impl R { + #[doc = "Bits 0:10 - SFID2"] + #[inline(always)] + pub fn sfid2(&self) -> SFID2_R { + SFID2_R::new((self.bits & 0x07ff) as u16) + } + #[doc = "Bits 16:26 - SFID1"] + #[inline(always)] + pub fn sfid1(&self) -> SFID1_R { + SFID1_R::new(((self.bits >> 16) & 0x07ff) as u16) + } + #[doc = "Bits 27:29 - SFEC"] + #[inline(always)] + pub fn sfec(&self) -> ESFEC_R { + ESFEC_R::new(((self.bits >> 27) & 0x07) as u8) + } + #[doc = "Bits 30:31 - SFT"] + #[inline(always)] + pub fn sft(&self) -> ESFT_R { + ESFT_R::new(((self.bits >> 30) & 0x03) as u8) + } +} +impl W { + #[doc = "Bits 0:10 - SFID2"] + #[inline(always)] + pub fn sfid2(&mut self) -> SFID2_W { + SFID2_W { w: self } + } + #[doc = "Bits 16:26 - SFID1"] + #[inline(always)] + pub fn sfid1(&mut self) -> SFID1_W { + SFID1_W { w: self } + } + #[doc = "Bits 27:29 - SFEC"] + #[inline(always)] + pub fn sfec(&mut self) -> SFEC_W { + SFEC_W { w: self } + } + #[doc = "Bits 30:31 - SFT"] + #[inline(always)] + pub fn sft(&mut self) -> SFT_W { + SFT_W { w: self } + } +} diff --git a/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs new file mode 100644 index 000000000..455406a1c --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs @@ -0,0 +1,433 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R}; +use super::enums::{ + BitRateSwitching, DataLength, ErrorStateIndicator, Event, EventControl, FrameFormat, IdType, + RemoteTransmissionRequest, +}; +use super::generic; + +#[doc = "Reader of register TxBufferElement"] +pub(crate) type R = generic::R; +#[doc = "Writer for register TxBufferElement"] +pub(crate) type W = generic::W; +impl generic::ResetValue for super::TxBufferElementHeader { + type Type = super::TxBufferElementHeaderType; + + #[allow(dead_code)] + #[inline(always)] + fn reset_value() -> Self::Type { + [0; 2] + } +} + +#[doc = "Write proxy for field `ESI`"] +pub(crate) struct ESI_W<'a> { + w: &'a mut W, +} +impl<'a> ESI_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_error_indicator(self, esi: ErrorStateIndicator) -> &'a mut W { + self.bit(esi as u8 != 0) + } + + #[doc = r"Sets the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits[0] = (self.w.bits[0] & !(0x01 << 31)) | (((value as u32) & 0x01) << 31); + self.w + } +} + +#[doc = "Write proxy for field `XTD`"] +pub(crate) struct XTD_W<'a> { + w: &'a mut W, +} +impl<'a> XTD_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_id_type(self, idt: IdType) -> &'a mut W { + self.bit(idt as u8 != 0) + } + + #[doc = r"Sets the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits[0] = (self.w.bits[0] & !(0x01 << 30)) | (((value as u32) & 0x01) << 30); + self.w + } +} + +#[doc = "Write proxy for field `RTR`"] +pub(crate) struct RTR_W<'a> { + w: &'a mut W, +} +impl<'a> RTR_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_rtr(self, rtr: RemoteTransmissionRequest) -> &'a mut W { + self.bit(rtr as u8 != 0) + } + + #[doc = r"Sets the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits[0] = (self.w.bits[0] & !(0x01 << 29)) | (((value as u32) & 0x01) << 29); + self.w + } +} + +#[doc = "Write proxy for field `ID`"] +pub(crate) struct ID_W<'a> { + w: &'a mut W, +} +impl<'a> ID_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + #[allow(dead_code)] + pub unsafe fn bits(self, value: u32) -> &'a mut W { + self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); + self.w + } +} + +#[doc = "Write proxy for field `DLC`"] +pub(crate) struct DLC_W<'a> { + w: &'a mut W, +} +impl<'a> DLC_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + #[allow(dead_code)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits[1] = (self.w.bits[1] & !(0x0F << 16)) | (((value as u32) & 0x0F) << 16); + self.w + } +} + +#[doc = "Write proxy for field `BRS`"] +pub(crate) struct BRS_W<'a> { + w: &'a mut W, +} +impl<'a> BRS_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_brs(self, brs: BitRateSwitching) -> &'a mut W { + self.bit(brs as u8 != 0) + } + + #[doc = r"Sets the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits[1] = (self.w.bits[1] & !(0x01 << 20)) | (((value as u32) & 0x01) << 20); + self.w + } +} + +#[doc = "Write proxy for field `FDF`"] +pub(crate) struct FDF_W<'a> { + w: &'a mut W, +} +impl<'a> FDF_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_format(self, fdf: FrameFormat) -> &'a mut W { + self.bit(fdf as u8 != 0) + } + + #[doc = r"Sets the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits[1] = (self.w.bits[1] & !(0x01 << 21)) | (((value as u32) & 0x01) << 21); + self.w + } +} + +#[doc = "Reader of field `EFC`"] +pub(crate) type EFC_R = generic::R; +impl EFC_R { + pub fn to_event_control(&self) -> EventControl { + match self.bit() { + false => EventControl::DoNotStore, + true => EventControl::Store, + } + } +} +#[doc = "Write proxy for field `EFC`"] +pub(crate) struct EFC_W<'a> { + w: &'a mut W, +} +impl<'a> EFC_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_event_control(self, efc: EventControl) -> &'a mut W { + self.bit(match efc { + EventControl::DoNotStore => false, + EventControl::Store => true, + }) + } + + #[doc = r"Sets the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + #[allow(dead_code)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + #[allow(dead_code)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits[1] = (self.w.bits[1] & !(0x01 << 23)) | (((value as u32) & 0x01) << 23); + self.w + } +} + +struct Marker(u8); +impl From for Marker { + fn from(e: Event) -> Marker { + match e { + Event::NoEvent => Marker(0), + Event::Event(mm) => Marker(mm), + } + } +} + +#[doc = "Reader of field `MM`"] +pub(crate) type MM_R = generic::R; +#[doc = "Write proxy for field `MM`"] +pub(crate) struct MM_W<'a> { + w: &'a mut W, +} +impl<'a> MM_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits[1] = (self.w.bits[1] & !(0x7F << 24)) | (((value as u32) & 0x7F) << 24); + self.w + } + + fn set_message_marker(self, mm: Marker) -> &'a mut W { + unsafe { self.bits(mm.0) } + } +} + +impl R { + #[doc = "Byte 0 - Bits 0:28 - ID"] + #[inline(always)] + pub fn id(&self) -> ID_R { + ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) + } + #[doc = "Byte 0 - Bit 29 - RTR"] + #[inline(always)] + pub fn rtr(&self) -> RTR_R { + RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) + } + #[doc = "Byte 0 - Bit 30 - XTD"] + #[inline(always)] + pub fn xtd(&self) -> XTD_R { + XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) + } + #[doc = "Byte 0 - Bit 30 - ESI"] + #[inline(always)] + pub fn esi(&self) -> ESI_R { + ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 16:19 - DLC"] + #[inline(always)] + pub fn dlc(&self) -> DLC_R { + DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) + } + #[doc = "Byte 1 - Bits 20 - BRS"] + #[inline(always)] + pub fn brs(&self) -> BRS_R { + BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 20 - FDF"] + #[inline(always)] + pub fn fdf(&self) -> FDF_R { + FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 23 - EFC"] + #[inline(always)] + pub fn efc(&self) -> EFC_R { + EFC_R::new(((self.bits[1] >> 23) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 24:31 - MM"] + #[inline(always)] + pub fn mm(&self) -> MM_R { + MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8) + } + pub fn to_data_length(&self) -> DataLength { + let dlc = self.dlc().bits(); + let ff = self.fdf().frame_format(); + let len = if ff == FrameFormat::Fdcan { + // See RM0433 Rev 7 Table 475. DLC coding + match dlc { + 0..=8 => dlc, + 9 => 12, + 10 => 16, + 11 => 20, + 12 => 24, + 13 => 32, + 14 => 48, + 15 => 64, + _ => panic!("DLC > 15"), + } + } else { + match dlc { + 0..=8 => dlc, + 9..=15 => 8, + _ => panic!("DLC > 15"), + } + }; + DataLength::new(len, ff) + } + pub fn to_event(&self) -> Event { + let mm = self.mm().bits(); + let efc = self.efc().to_event_control(); + match efc { + EventControl::DoNotStore => Event::NoEvent, + EventControl::Store => Event::Event(mm), + } + } +} +impl W { + #[doc = "Byte 0 - Bits 0:28 - ID"] + #[inline(always)] + pub fn id(&mut self) -> ID_W { + ID_W { w: self } + } + #[doc = "Byte 0 - Bit 29 - RTR"] + #[inline(always)] + pub fn rtr(&mut self) -> RTR_W { + RTR_W { w: self } + } + #[doc = "Byte 0 - Bit 30 - XTD"] + #[inline(always)] + pub fn xtd(&mut self) -> XTD_W { + XTD_W { w: self } + } + #[doc = "Byte 0 - Bit 31 - ESI"] + #[inline(always)] + pub fn esi(&mut self) -> ESI_W { + ESI_W { w: self } + } + #[doc = "Byte 1 - Bit 16:19 - DLC"] + #[inline(always)] + pub fn dlc(&mut self) -> DLC_W { + DLC_W { w: self } + } + #[doc = "Byte 1 - Bit 20 - BRS"] + #[inline(always)] + pub fn brs(&mut self) -> BRS_W { + BRS_W { w: self } + } + #[doc = "Byte 1 - Bit 21 - FDF"] + #[inline(always)] + pub fn fdf(&mut self) -> FDF_W { + FDF_W { w: self } + } + #[doc = "Byte 1 - Bit 23 - EFC"] + #[inline(always)] + pub fn efc(&mut self) -> EFC_W { + EFC_W { w: self } + } + #[doc = "Byte 1 - Bit 24:31 - MM"] + #[inline(always)] + pub fn mm(&mut self) -> MM_W { + MM_W { w: self } + } + #[doc = "Convenience function for setting the data length and frame format"] + #[inline(always)] + pub fn set_len(&mut self, dl: impl Into) -> &mut Self { + let dl: DataLength = dl.into(); + self.fdf().set_format(dl.into()); + unsafe { self.dlc().bits(dl.dlc()) } + } + pub fn set_event(&mut self, event: Event) -> &mut Self { + self.mm().set_message_marker(event.into()); + self.efc().set_event_control(event.into()) + } +} diff --git a/embassy-stm32/src/can/fd/message_ram/txevent_element.rs b/embassy-stm32/src/can/fd/message_ram/txevent_element.rs new file mode 100644 index 000000000..817a4449f --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/txevent_element.rs @@ -0,0 +1,138 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +use super::common::{BRS_R, DLC_R, ESI_R, RTR_R, XTD_R}; +use super::generic; + +#[doc = "Reader of register TxEventElement"] +pub(crate) type R = generic::R; +// #[doc = "Writer for register TxEventElement"] +// pub(crate) type W = generic::W; +#[doc = "Register TxEventElement `reset()`'s"] +impl generic::ResetValue for super::TxEventElement { + type Type = super::TxEventElementType; + #[inline(always)] + fn reset_value() -> Self::Type { + [0, 0] + } +} + +#[doc = "Reader of field `ID`"] +pub(crate) type ID_R = generic::R; + +#[doc = "Reader of field `TXTS`"] +pub(crate) type TXTS_R = generic::R; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub(crate) enum DataLengthFormat { + StandardLength = 0, + FDCANLength = 1, +} +impl From for bool { + #[inline(always)] + fn from(dlf: DataLengthFormat) -> Self { + dlf as u8 != 0 + } +} + +#[doc = "Reader of field `EDL`"] +pub(crate) type EDL_R = generic::R; +impl EDL_R { + pub fn data_length_format(&self) -> DataLengthFormat { + match self.bits() { + false => DataLengthFormat::StandardLength, + true => DataLengthFormat::FDCANLength, + } + } + pub fn is_standard_length(&self) -> bool { + *self == DataLengthFormat::StandardLength + } + pub fn is_fdcan_length(&self) -> bool { + *self == DataLengthFormat::FDCANLength + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub(crate) enum EventType { + //_Reserved = 0b00, + TxEvent = 0b01, + TxDespiteAbort = 0b10, + //_Reserved = 0b10, +} + +#[doc = "Reader of field `EFC`"] +pub(crate) type EFC_R = generic::R; +impl EFC_R { + pub fn event_type(&self) -> EventType { + match self.bits() { + 0b01 => EventType::TxEvent, + 0b10 => EventType::TxDespiteAbort, + _ => unimplemented!(), + } + } + pub fn is_tx_event(&self) -> bool { + self.event_type() == EventType::TxEvent + } + pub fn is_despite_abort(&self) -> bool { + self.event_type() == EventType::TxDespiteAbort + } +} + +#[doc = "Reader of field `MM`"] +pub(crate) type MM_R = generic::R; + +impl R { + #[doc = "Byte 0 - Bits 0:28 - ID"] + #[inline(always)] + pub fn id(&self) -> ID_R { + ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) + } + #[doc = "Byte 0 - Bit 29 - RTR"] + #[inline(always)] + pub fn rtr(&self) -> RTR_R { + RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) + } + #[doc = "Byte 0 - Bit 30 - XTD"] + #[inline(always)] + pub fn xtd(&self) -> XTD_R { + XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) + } + #[doc = "Byte 0 - Bit 30 - ESI"] + #[inline(always)] + pub fn esi(&self) -> ESI_R { + ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 0:15 - TXTS"] + #[inline(always)] + pub fn txts(&self) -> TXTS_R { + TXTS_R::new(((self.bits[1]) & 0xFFFF) as u16) + } + #[doc = "Byte 1 - Bits 16:19 - DLC"] + #[inline(always)] + pub fn dlc(&self) -> DLC_R { + DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) + } + #[doc = "Byte 1 - Bits 20 - BRS"] + #[inline(always)] + pub fn brs(&self) -> BRS_R { + BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 21 - EDL"] + #[inline(always)] + pub fn edl(&self) -> EDL_R { + EDL_R::new(((self.bits[1] >> 21) & 0x01) != 0) + } + #[doc = "Byte 1 - Bits 22:23 - EFC"] + #[inline(always)] + pub fn efc(&self) -> EFC_R { + EFC_R::new(((self.bits[1] >> 22) & 0x03) as u8) + } + #[doc = "Byte 1 - Bits 24:31 - MM"] + #[inline(always)] + pub fn mm(&self) -> MM_R { + MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8) + } +} diff --git a/embassy-stm32/src/can/fd/mod.rs b/embassy-stm32/src/can/fd/mod.rs new file mode 100644 index 000000000..0008fd3a8 --- /dev/null +++ b/embassy-stm32/src/can/fd/mod.rs @@ -0,0 +1,6 @@ +//! Module containing that which is speciffic to fdcan hardware variant + +pub mod config; +pub mod filter; +pub(crate) mod message_ram; +pub(crate) mod peripheral; diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs new file mode 100644 index 000000000..6f390abb4 --- /dev/null +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -0,0 +1,776 @@ +// Note: This file is copied and modified from fdcan crate by Richard Meadows + +use core::convert::Infallible; +use core::slice; + +use crate::can::fd::config::*; +use crate::can::fd::message_ram::enums::*; +use crate::can::fd::message_ram::{RegisterBlock, RxFifoElement, TxBufferElement}; +use crate::can::frame::*; + +/// Loopback Mode +#[derive(Clone, Copy, Debug)] +enum LoopbackMode { + None, + Internal, + External, +} + +pub struct Registers { + pub regs: &'static crate::pac::can::Fdcan, + pub msgram: &'static crate::pac::fdcanram::Fdcanram, +} + +impl Registers { + fn tx_buffer_element(&self, bufidx: usize) -> &mut TxBufferElement { + &mut self.msg_ram_mut().transmit.tbsa[bufidx] + } + pub fn msg_ram_mut(&self) -> &mut RegisterBlock { + let ptr = self.msgram.as_ptr() as *mut RegisterBlock; + unsafe { &mut (*ptr) } + } + + fn rx_fifo_element(&self, fifonr: usize, bufnum: usize) -> &mut RxFifoElement { + &mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum] + } + + pub fn read_classic(&self, fifonr: usize) -> Option<(ClassicFrame, u16)> { + // Fill level - do we have a msg? + if self.regs.rxfs(fifonr).read().ffl() < 1 { + return None; + } + + let read_idx = self.regs.rxfs(fifonr).read().fgi(); + let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); + + let mut buffer: [u8; 8] = [0; 8]; + let maybe_header = extract_frame(mailbox, &mut buffer); + + // Clear FIFO, reduces count and increments read buf + self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx)); + + match maybe_header { + Some((header, ts)) => { + let data = ClassicData::new(&buffer[0..header.len() as usize]); + Some((ClassicFrame::new(header, data.unwrap()), ts)) + } + None => None, + } + } + + pub fn read_fd(&self, fifonr: usize) -> Option<(FdFrame, u16)> { + // Fill level - do we have a msg? + if self.regs.rxfs(fifonr).read().ffl() < 1 { + return None; + } + + let read_idx = self.regs.rxfs(fifonr).read().fgi(); + let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); + + let mut buffer: [u8; 64] = [0; 64]; + let maybe_header = extract_frame(mailbox, &mut buffer); + + // Clear FIFO, reduces count and increments read buf + self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx)); + + match maybe_header { + Some((header, ts)) => { + let data = FdData::new(&buffer[0..header.len() as usize]); + Some((FdFrame::new(header, data.unwrap()), ts)) + } + None => None, + } + } + + pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) { + // Fill level - do we have a msg? + //if self.regs.rxfs(fifonr).read().ffl() < 1 { return None; } + + //let read_idx = self.regs.rxfs(fifonr).read().fgi(); + + let mailbox = self.tx_buffer_element(bufidx); + + mailbox.reset(); + put_tx_header(mailbox, header); + put_tx_data(mailbox, &buffer[..header.len() as usize]); + + // Set as ready to transmit + self.regs.txbar().modify(|w| w.set_ar(bufidx, true)); + } + + /// Returns if the tx queue is able to accept new messages without having to cancel an existing one + #[inline] + pub fn tx_queue_is_full(&self) -> bool { + self.regs.txfqs().read().tfqf() + } + + #[inline] + pub fn has_pending_frame(&self, idx: usize) -> bool { + self.regs.txbrp().read().trp(idx) + } + + /// Returns `Ok` when the mailbox is free or if it contains pending frame with a + /// lower priority (higher ID) than the identifier `id`. + #[inline] + pub fn is_available(&self, bufidx: usize, id: &embedded_can::Id) -> bool { + if self.has_pending_frame(bufidx) { + let mailbox = self.tx_buffer_element(bufidx); + + let header_reg = mailbox.header.read(); + let old_id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); + + *id > old_id + } else { + true + } + } + + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// If there is a frame in the provided mailbox, and it is canceled successfully, this function + /// returns `true`. + #[inline] + pub fn abort(&self, bufidx: usize) -> bool { + let can = self.regs; + + // Check if there is a request pending to abort + if self.has_pending_frame(bufidx) { + // Abort Request + can.txbcr().write(|w| w.set_cr(bufidx, true)); + + // Wait for the abort request to be finished. + loop { + if can.txbcf().read().cf(bufidx) { + // Return false when a transmission has occured + break can.txbto().read().to(bufidx) == false; + } + } + } else { + false + } + } + + #[inline] + //fn abort_pending_mailbox(&mut self, idx: Mailbox, pending: PTX) -> Option + pub fn abort_pending_mailbox(&self, bufidx: usize) -> Option +//where + // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, + { + if self.abort(bufidx) { + let mailbox = self.tx_buffer_element(bufidx); + + let header_reg = mailbox.header.read(); + let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); + + let len = match header_reg.to_data_length() { + DataLength::Fdcan(len) => len, + DataLength::Standard(len) => len, + }; + if len as usize > ClassicFrame::MAX_DATA_LEN { + return None; + } + + //let tx_ram = self.tx_msg_ram(); + let mut data = [0u8; 64]; + data_from_tx_buffer(&mut data, mailbox, len as usize); + + let cd = ClassicData::new(&data).unwrap(); + Some(ClassicFrame::new(Header::new(id, len, header_reg.rtr().bit()), cd)) + } else { + // Abort request failed because the frame was already sent (or being sent) on + // the bus. All mailboxes are now free. This can happen for small prescaler + // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR + // has preempted the execution. + None + } + } + + #[inline] + //fn abort_pending_mailbox(&mut self, idx: Mailbox, pending: PTX) -> Option + pub fn abort_pending_fd_mailbox(&self, bufidx: usize) -> Option +//where + // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, + { + if self.abort(bufidx) { + let mailbox = self.tx_buffer_element(bufidx); + + let header_reg = mailbox.header.read(); + let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); + + let len = match header_reg.to_data_length() { + DataLength::Fdcan(len) => len, + DataLength::Standard(len) => len, + }; + if len as usize > FdFrame::MAX_DATA_LEN { + return None; + } + + //let tx_ram = self.tx_msg_ram(); + let mut data = [0u8; 64]; + data_from_tx_buffer(&mut data, mailbox, len as usize); + + let cd = FdData::new(&data).unwrap(); + + let header = if header_reg.fdf().frame_format() == FrameFormat::Fdcan { + Header::new_fd(id, len, header_reg.rtr().bit(), header_reg.brs().bit()) + } else { + Header::new(id, len, header_reg.rtr().bit()) + }; + + Some(FdFrame::new(header, cd)) + } else { + // Abort request failed because the frame was already sent (or being sent) on + // the bus. All mailboxes are now free. This can happen for small prescaler + // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR + // has preempted the execution. + None + } + } + + /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can + /// be preserved. + //pub fn transmit_preserve( + pub fn write_classic(&self, frame: &ClassicFrame) -> nb::Result, Infallible> { + let queue_is_full = self.tx_queue_is_full(); + + let id = frame.header().id(); + + // If the queue is full, + // Discard the first slot with a lower priority message + let (idx, pending_frame) = if queue_is_full { + if self.is_available(0, id) { + (0, self.abort_pending_mailbox(0)) + } else if self.is_available(1, id) { + (1, self.abort_pending_mailbox(1)) + } else if self.is_available(2, id) { + (2, self.abort_pending_mailbox(2)) + } else { + // For now we bail when there is no lower priority slot available + // Can this lead to priority inversion? + return Err(nb::Error::WouldBlock); + } + } else { + // Read the Write Pointer + let idx = self.regs.txfqs().read().tfqpi(); + + (idx, None) + }; + + self.put_tx_frame(idx as usize, frame.header(), frame.data()); + + Ok(pending_frame) + } + + /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can + /// be preserved. + //pub fn transmit_preserve( + pub fn write_fd(&self, frame: &FdFrame) -> nb::Result, Infallible> { + let queue_is_full = self.tx_queue_is_full(); + + let id = frame.header().id(); + + // If the queue is full, + // Discard the first slot with a lower priority message + let (idx, pending_frame) = if queue_is_full { + if self.is_available(0, id) { + (0, self.abort_pending_fd_mailbox(0)) + } else if self.is_available(1, id) { + (1, self.abort_pending_fd_mailbox(1)) + } else if self.is_available(2, id) { + (2, self.abort_pending_fd_mailbox(2)) + } else { + // For now we bail when there is no lower priority slot available + // Can this lead to priority inversion? + return Err(nb::Error::WouldBlock); + } + } else { + // Read the Write Pointer + let idx = self.regs.txfqs().read().tfqpi(); + + (idx, None) + }; + + self.put_tx_frame(idx as usize, frame.header(), frame.data()); + + Ok(pending_frame) + } + + #[inline] + fn reset_msg_ram(&mut self) { + self.msg_ram_mut().reset(); + } + + #[inline] + fn enter_init_mode(&mut self) { + self.regs.cccr().modify(|w| w.set_init(true)); + while false == self.regs.cccr().read().init() {} + self.regs.cccr().modify(|w| w.set_cce(true)); + } + + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + #[inline] + fn set_loopback_mode(&mut self, mode: LoopbackMode) { + let (test, mon, lbck) = match mode { + LoopbackMode::None => (false, false, false), + LoopbackMode::Internal => (true, true, true), + LoopbackMode::External => (true, false, true), + }; + + self.set_test_mode(test); + self.set_bus_monitoring_mode(mon); + + self.regs.test().modify(|w| w.set_lbck(lbck)); + } + + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + #[inline] + fn set_bus_monitoring_mode(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_mon(enabled)); + } + + #[inline] + fn set_restricted_operations(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_asm(enabled)); + } + + #[inline] + fn set_normal_operations(&mut self, _enabled: bool) { + self.set_loopback_mode(LoopbackMode::None); + } + + #[inline] + fn set_test_mode(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_test(enabled)); + } + + #[inline] + fn set_power_down_mode(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_csr(enabled)); + while self.regs.cccr().read().csa() != enabled {} + } + + /// Moves out of PoweredDownMode and into ConfigMode + #[inline] + pub fn into_config_mode(mut self, _config: FdCanConfig) { + self.set_power_down_mode(false); + self.enter_init_mode(); + + self.reset_msg_ram(); + + // check the FDCAN core matches our expections + assert!( + self.regs.crel().read().rel() == 3, + "Expected FDCAN core major release 3" + ); + assert!( + self.regs.endn().read().etv() == 0x87654321_u32, + "Error reading endianness test value from FDCAN core" + ); + + // Framework specific settings are set here + + // set TxBuffer to Queue Mode + self.regs.txbc().write(|w| w.set_tfqm(true)); + + // set standard filters list size to 28 + // set extended filters list size to 8 + // REQUIRED: we use the memory map as if these settings are set + // instead of re-calculating them. + #[cfg(not(stm32h7))] + { + self.regs.rxgfc().modify(|w| { + w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX); + w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX); + }); + } + #[cfg(stm32h7)] + { + self.regs + .sidfc() + .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX)); + self.regs + .xidfc() + .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX)); + } + + /* + for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX { + self.set_standard_filter((fid as u8).into(), StandardFilter::disable()); + } + for fid in 0..Ecrate::can::message_ram::XTENDED_FILTER_MAX { + self.set_extended_filter(fid.into(), ExtendedFilter::disable()); + } + */ + } + + /// Disables the CAN interface and returns back the raw peripheral it was created from. + #[inline] + pub fn free(mut self) { + //self.disable_interrupts(Interrupts::all()); + + //TODO check this! + self.enter_init_mode(); + self.set_power_down_mode(true); + //self.control.instance + } + + /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] + #[inline] + pub fn apply_config(&mut self, config: FdCanConfig) { + self.set_data_bit_timing(config.dbtr); + self.set_nominal_bit_timing(config.nbtr); + self.set_automatic_retransmit(config.automatic_retransmit); + self.set_transmit_pause(config.transmit_pause); + self.set_frame_transmit(config.frame_transmit); + //self.set_interrupt_line_config(config.interrupt_line_config); + self.set_non_iso_mode(config.non_iso_mode); + self.set_edge_filtering(config.edge_filtering); + self.set_protocol_exception_handling(config.protocol_exception_handling); + self.set_global_filter(config.global_filter); + } + + #[inline] + fn leave_init_mode(&mut self, config: FdCanConfig) { + self.apply_config(config); + + self.regs.cccr().modify(|w| w.set_cce(false)); + self.regs.cccr().modify(|w| w.set_init(false)); + while self.regs.cccr().read().init() == true {} + } + + /// Moves out of ConfigMode and into InternalLoopbackMode + #[inline] + pub fn into_internal_loopback(mut self, config: FdCanConfig) { + self.set_loopback_mode(LoopbackMode::Internal); + self.leave_init_mode(config); + } + + /// Moves out of ConfigMode and into ExternalLoopbackMode + #[inline] + pub fn into_external_loopback(mut self, config: FdCanConfig) { + self.set_loopback_mode(LoopbackMode::External); + self.leave_init_mode(config); + } + + /// Moves out of ConfigMode and into RestrictedOperationMode + #[inline] + pub fn into_restricted(mut self, config: FdCanConfig) { + self.set_restricted_operations(true); + self.leave_init_mode(config); + } + + /// Moves out of ConfigMode and into NormalOperationMode + #[inline] + pub fn into_normal(mut self, config: FdCanConfig) { + self.set_normal_operations(true); + self.leave_init_mode(config); + } + + /// Moves out of ConfigMode and into BusMonitoringMode + #[inline] + pub fn into_bus_monitoring(mut self, config: FdCanConfig) { + self.set_bus_monitoring_mode(true); + self.leave_init_mode(config); + } + + /// Moves out of ConfigMode and into Testmode + #[inline] + pub fn into_test_mode(mut self, config: FdCanConfig) { + self.set_test_mode(true); + self.leave_init_mode(config); + } + + /// Moves out of ConfigMode and into PoweredDownmode + #[inline] + pub fn into_powered_down(mut self, config: FdCanConfig) { + self.set_power_down_mode(true); + self.leave_init_mode(config); + } + + /// Configures the bit timings. + /// + /// You can use to calculate the `btr` parameter. Enter + /// parameters as follows: + /// + /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). + /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). + /// - *Sample Point*: Should normally be left at the default value of 87.5%. + /// - *SJW*: Should normally be left at the default value of 1. + /// + /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` + /// parameter to this method. + #[inline] + pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) { + //self.control.config.nbtr = btr; + + self.regs.nbtp().write(|w| { + w.set_nbrp(btr.nbrp() - 1); + w.set_ntseg1(btr.ntseg1() - 1); + w.set_ntseg2(btr.ntseg2() - 1); + w.set_nsjw(btr.nsjw() - 1); + }); + } + + /// Configures the data bit timings for the FdCan Variable Bitrates. + /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. + #[inline] + pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) { + //self.control.config.dbtr = btr; + + self.regs.dbtp().write(|w| { + w.set_dbrp(btr.dbrp() - 1); + w.set_dtseg1(btr.dtseg1() - 1); + w.set_dtseg2(btr.dtseg2() - 1); + w.set_dsjw(btr.dsjw() - 1); + }); + } + + /// Enables or disables automatic retransmission of messages + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// util it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + #[inline] + pub fn set_automatic_retransmit(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_dar(!enabled)); + //self.control.config.automatic_retransmit = enabled; + } + + /// Configures the transmit pause feature. See + /// [`FdCanConfig::set_transmit_pause`] + #[inline] + pub fn set_transmit_pause(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_txp(!enabled)); + //self.control.config.transmit_pause = enabled; + } + + /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`] + #[inline] + pub fn set_non_iso_mode(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_niso(enabled)); + //self.control.config.non_iso_mode = enabled; + } + + /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`] + #[inline] + pub fn set_edge_filtering(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_efbi(enabled)); + //self.control.config.edge_filtering = enabled; + } + + /// Configures frame transmission mode. See + /// [`FdCanConfig::set_frame_transmit`] + #[inline] + pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) { + let (fdoe, brse) = match fts { + FrameTransmissionConfig::ClassicCanOnly => (false, false), + FrameTransmissionConfig::AllowFdCan => (true, false), + FrameTransmissionConfig::AllowFdCanAndBRS => (true, true), + }; + + self.regs.cccr().modify(|w| { + w.set_fdoe(fdoe); + #[cfg(stm32h7)] + w.set_bse(brse); + #[cfg(not(stm32h7))] + w.set_brse(brse); + }); + + //self.control.config.frame_transmit = fts; + } + + /// Sets the protocol exception handling on/off + #[inline] + pub fn set_protocol_exception_handling(&mut self, enabled: bool) { + self.regs.cccr().modify(|w| w.set_pxhd(!enabled)); + + //self.control.config.protocol_exception_handling = enabled; + } + + /// Configures and resets the timestamp counter + #[inline] + pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { + #[cfg(stm32h7)] + let (tcp, tss) = match select { + TimestampSource::None => (0, 0), + TimestampSource::Prescaler(p) => (p as u8, 1), + TimestampSource::FromTIM3 => (0, 2), + }; + + #[cfg(not(stm32h7))] + let (tcp, tss) = match select { + TimestampSource::None => (0, stm32_metapac::can::vals::Tss::ZERO), + TimestampSource::Prescaler(p) => (p as u8, stm32_metapac::can::vals::Tss::INCREMENT), + TimestampSource::FromTIM3 => (0, stm32_metapac::can::vals::Tss::EXTERNAL), + }; + + self.regs.tscc().write(|w| { + w.set_tcp(tcp); + w.set_tss(tss); + }); + + //self.control.config.timestamp_source = select; + } + + #[cfg(not(stm32h7))] + /// Configures the global filter settings + #[inline] + pub fn set_global_filter(&mut self, filter: GlobalFilter) { + let anfs = match filter.handle_standard_frames { + crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0, + crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1, + crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfs::REJECT, + }; + let anfe = match filter.handle_extended_frames { + crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_0, + crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_1, + crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfe::REJECT, + }; + + self.regs.rxgfc().modify(|w| { + w.set_anfs(anfs); + w.set_anfe(anfe); + w.set_rrfs(filter.reject_remote_standard_frames); + w.set_rrfe(filter.reject_remote_extended_frames); + }); + } + + #[cfg(stm32h7)] + /// Configures the global filter settings + #[inline] + pub fn set_global_filter(&mut self, filter: GlobalFilter) { + let anfs = match filter.handle_standard_frames { + crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0, + crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1, + crate::can::fd::config::NonMatchingFilter::Reject => 2, + }; + + let anfe = match filter.handle_extended_frames { + crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0, + crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1, + crate::can::fd::config::NonMatchingFilter::Reject => 2, + }; + + self.regs.gfc().modify(|w| { + w.set_anfs(anfs); + w.set_anfe(anfe); + w.set_rrfs(filter.reject_remote_standard_frames); + w.set_rrfe(filter.reject_remote_extended_frames); + }); + } +} + +fn make_id(id: u32, extended: bool) -> embedded_can::Id { + if extended { + embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) }) + } else { + embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked((id & 0x000007FF) as u16) }) + } +} + +fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) { + let (id, id_type) = match header.id() { + embedded_can::Id::Standard(id) => (id.as_raw() as u32, IdType::StandardId), + embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId), + }; + + // Use FDCAN only for DLC > 8. FDCAN users can revise this if required. + let frame_format = if header.len() > 8 || header.fdcan() { + FrameFormat::Fdcan + } else { + FrameFormat::Standard + }; + let brs = header.len() > 8 || header.bit_rate_switching(); + + mailbox.header.write(|w| { + unsafe { w.id().bits(id) } + .rtr() + .bit(header.len() == 0 && header.rtr()) + .xtd() + .set_id_type(id_type) + .set_len(DataLength::new(header.len(), frame_format)) + .set_event(Event::NoEvent) + .fdf() + .set_format(frame_format) + .brs() + .bit(brs) + //esi.set_error_indicator(//TODO//) + }); +} + +fn put_tx_data(mailbox: &mut TxBufferElement, buffer: &[u8]) { + let mut lbuffer = [0_u32; 16]; + let len = buffer.len(); + let data = unsafe { slice::from_raw_parts_mut(lbuffer.as_mut_ptr() as *mut u8, len) }; + data[..len].copy_from_slice(&buffer[..len]); + let data_len = ((len) + 3) / 4; + for (register, byte) in mailbox.data.iter_mut().zip(lbuffer[..data_len].iter()) { + unsafe { register.write(*byte) }; + } +} + +fn data_from_fifo(buffer: &mut [u8], mailbox: &RxFifoElement, len: usize) { + for (i, register) in mailbox.data.iter().enumerate() { + let register_value = register.read(); + let register_bytes = unsafe { slice::from_raw_parts(®ister_value as *const u32 as *const u8, 4) }; + let num_bytes = (len) - i * 4; + if num_bytes <= 4 { + buffer[i * 4..i * 4 + num_bytes].copy_from_slice(®ister_bytes[..num_bytes]); + break; + } + buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes); + } +} + +fn data_from_tx_buffer(buffer: &mut [u8], mailbox: &TxBufferElement, len: usize) { + for (i, register) in mailbox.data.iter().enumerate() { + let register_value = register.read(); + let register_bytes = unsafe { slice::from_raw_parts(®ister_value as *const u32 as *const u8, 4) }; + let num_bytes = (len) - i * 4; + if num_bytes <= 4 { + buffer[i * 4..i * 4 + num_bytes].copy_from_slice(®ister_bytes[..num_bytes]); + break; + } + buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes); + } +} + +impl From<&RxFifoElement> for ClassicFrame { + fn from(mailbox: &RxFifoElement) -> Self { + let header_reg = mailbox.header.read(); + + let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); + let dlc = header_reg.to_data_length().len(); + let len = dlc as usize; + + let mut buffer: [u8; 64] = [0; 64]; + data_from_fifo(&mut buffer, mailbox, len); + let data = ClassicData::new(&buffer[0..len]); + let header = Header::new(id, dlc, header_reg.rtr().bits()); + ClassicFrame::new(header, data.unwrap()) + } +} + +fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> { + let header_reg = mailbox.header.read(); + + let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); + let dlc = header_reg.to_data_length().len(); + let len = dlc as usize; + let timestamp = header_reg.txts().bits; + if len > buffer.len() { + return None; + } + data_from_fifo(buffer, mailbox, len); + let header = if header_reg.fdf().bits { + Header::new_fd(id, dlc, header_reg.rtr().bits(), header_reg.brs().bits()) + } else { + Header::new(id, dlc, header_reg.rtr().bits()) + }; + Some((header, timestamp)) +} diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index faf4af73f..b94e42707 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -1,16 +1,15 @@ +#[allow(unused_variables)] use core::future::poll_fn; use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; use core::task::Poll; +pub mod fd; use cfg_if::cfg_if; use embassy_hal_internal::{into_ref, PeripheralRef}; -pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader}; -pub use fdcan::id::{ExtendedId, Id, StandardId}; -use fdcan::message_ram::RegisterBlock; -use fdcan::{self, LastErrorCode}; -pub use fdcan::{config, filter}; +use fd::config::*; +use fd::filter::*; +use crate::can::fd::peripheral::Registers; use crate::gpio::sealed::AFType; use crate::interrupt::typelevel::Interrupt; use crate::rcc::RccPeripheral; @@ -20,127 +19,14 @@ pub mod enums; use enums::*; pub mod util; -/// CAN Frame returned by read -pub struct RxFrame { - /// CAN Header info: frame ID, data length and other meta - pub header: RxFrameInfo, - /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data - pub data: Data, - /// Reception time. - #[cfg(feature = "time")] - pub timestamp: embassy_time::Instant, -} +pub mod frame; +use frame::*; -/// CAN frame used for write -pub struct TxFrame { - /// CAN Header info: frame ID, data length and other meta - pub header: TxFrameHeader, - /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data - pub data: Data, -} +#[cfg(feature = "time")] +type Timestamp = embassy_time::Instant; -impl TxFrame { - /// Create new TX frame from header and data - pub fn new(header: TxFrameHeader, data: &[u8]) -> Option { - if data.len() < header.len as usize { - return None; - } - - let Some(data) = Data::new(data) else { return None }; - - Some(TxFrame { header, data }) - } - - fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option { - let mut data = [0u8; 64]; - - for i in 0..data32.len() { - data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes()); - } - - let Some(data) = Data::new(&data) else { return None }; - - Some(TxFrame { header, data }) - } - - /// Access frame data. Slice length will match header. - pub fn data(&self) -> &[u8] { - &self.data.bytes[..(self.header.len as usize)] - } -} - -impl RxFrame { - pub(crate) fn new( - header: RxFrameInfo, - data: &[u8], - #[cfg(feature = "time")] timestamp: embassy_time::Instant, - ) -> Self { - let data = Data::new(&data).unwrap_or_else(|| Data::empty()); - - RxFrame { - header, - data, - #[cfg(feature = "time")] - timestamp, - } - } - - /// Access frame data. Slice length will match header. - pub fn data(&self) -> &[u8] { - &self.data.bytes[..(self.header.len as usize)] - } -} - -/// Payload of a (FD)CAN data frame. -/// -/// Contains 0 to 64 Bytes of data. -#[derive(Debug, Copy, Clone)] -pub struct Data { - pub(crate) bytes: [u8; 64], -} - -impl Data { - /// Creates a data payload from a raw byte slice. - /// - /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or - /// cannot be represented with an FDCAN DLC. - pub fn new(data: &[u8]) -> Option { - if !Data::is_valid_len(data.len()) { - return None; - } - - let mut bytes = [0; 64]; - bytes[..data.len()].copy_from_slice(data); - - Some(Self { bytes }) - } - - /// Raw read access to data. - pub fn raw(&self) -> &[u8] { - &self.bytes - } - - /// Checks if the length can be encoded in FDCAN DLC field. - pub const fn is_valid_len(len: usize) -> bool { - match len { - 0..=8 => true, - 12 => true, - 16 => true, - 20 => true, - 24 => true, - 32 => true, - 48 => true, - 64 => true, - _ => false, - } - } - - /// Creates an empty data payload containing 0 bytes. - #[inline] - pub const fn empty() -> Self { - Self { bytes: [0; 64] } - } -} +#[cfg(not(feature = "time"))] +type Timestamp = u16; /// Interrupt handler channel 0. pub struct IT0InterruptHandler { @@ -172,7 +58,9 @@ impl interrupt::typelevel::Handler for IT0Interrup } if ir.rfn(0) { - regs.ir().write(|w| w.set_rfn(0, true)); + let fifonr = 0 as usize; + regs.ir().write(|w| w.set_rfn(fifonr, true)); + T::state().rx_waker.wake(); } @@ -192,44 +80,82 @@ impl interrupt::typelevel::Handler for IT1Interrup unsafe fn on_interrupt() {} } -impl BusError { - fn try_from(lec: LastErrorCode) -> Option { - match lec { - LastErrorCode::AckError => Some(BusError::Acknowledge), - // `0` data bit encodes a dominant state. `1` data bit is recessive. - // Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1 - LastErrorCode::Bit0Error => Some(BusError::BitRecessive), - LastErrorCode::Bit1Error => Some(BusError::BitDominant), - LastErrorCode::CRCError => Some(BusError::Crc), - LastErrorCode::FormError => Some(BusError::Form), - LastErrorCode::StuffError => Some(BusError::Stuff), - _ => None, - } - } -} +/// Allows for Transmit Operations +pub trait Transmit {} +/// Allows for Receive Operations +pub trait Receive {} + +/// Allows for the FdCan Instance to be released or to enter ConfigMode +pub struct PoweredDownMode; +/// Allows for the configuration for the Instance +pub struct ConfigMode; +/// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without +/// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this +/// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held +/// recessive. +pub struct InternalLoopbackMode; +impl Transmit for InternalLoopbackMode {} +impl Receive for InternalLoopbackMode {} +/// This mode is provided for hardware self-test. To be independent from external stimulation, +/// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a +/// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal +/// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX +/// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the +/// FDCAN_TX transmit pin. +pub struct ExternalLoopbackMode; +impl Transmit for ExternalLoopbackMode {} +impl Receive for ExternalLoopbackMode {} +/// The normal use of the FdCan instance after configurations +pub struct NormalOperationMode; +impl Transmit for NormalOperationMode {} +impl Receive for NormalOperationMode {} +/// In Restricted operation mode the node is able to receive data and remote frames and to give +/// acknowledge to valid frames, but it does not send data frames, remote frames, active error +/// frames, or overload frames. In case of an error condition or overload condition, it does not +/// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize +/// itself to the CAN communication. The error counters for transmit and receive are frozen while +/// error logging (can_errors) is active. TODO: automatically enter in this mode? +pub struct RestrictedOperationMode; +impl Receive for RestrictedOperationMode {} +/// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring), +/// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a +/// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is +/// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is +/// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive +/// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring +/// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission +/// of dominant bits. +pub struct BusMonitoringMode; +impl Receive for BusMonitoringMode {} +/// Test mode must be used for production tests or self test only. The software control for +/// FDCAN_TX pin interferes with all CAN protocol functions. It is not recommended to use test +/// modes for application. +pub struct TestMode; /// Operating modes trait pub trait FdcanOperatingMode {} -impl FdcanOperatingMode for fdcan::PoweredDownMode {} -impl FdcanOperatingMode for fdcan::ConfigMode {} -impl FdcanOperatingMode for fdcan::InternalLoopbackMode {} -impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {} -impl FdcanOperatingMode for fdcan::NormalOperationMode {} -impl FdcanOperatingMode for fdcan::RestrictedOperationMode {} -impl FdcanOperatingMode for fdcan::BusMonitoringMode {} -impl FdcanOperatingMode for fdcan::TestMode {} +impl FdcanOperatingMode for PoweredDownMode {} +impl FdcanOperatingMode for ConfigMode {} +impl FdcanOperatingMode for InternalLoopbackMode {} +impl FdcanOperatingMode for ExternalLoopbackMode {} +impl FdcanOperatingMode for NormalOperationMode {} +impl FdcanOperatingMode for RestrictedOperationMode {} +impl FdcanOperatingMode for BusMonitoringMode {} +impl FdcanOperatingMode for TestMode {} /// FDCAN Instance pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { + config: crate::can::fd::config::FdCanConfig, /// Reference to internals. - pub can: fdcan::FdCan, M>, + instance: FdcanInstance<'d, T>, + _mode: PhantomData, ns_per_timer_tick: u64, // For FDCAN internal timer } -fn calc_ns_per_timer_tick(mode: config::FrameTransmissionConfig) -> u64 { +fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { match mode { // Use timestamp from Rx FIFO to adjust timestamp reported to user - config::FrameTransmissionConfig::ClassicCanOnly => { + crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => { let freq = T::frequency(); let prescale: u64 = ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; @@ -242,17 +168,22 @@ fn calc_ns_per_timer_tick(mode: config::FrameTransmissionConfig) -> } #[cfg(feature = "time")] -fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant { +fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { let now_embassy = embassy_time::Instant::now(); if ns_per_timer_tick == 0 { return now_embassy; } - let now_can = { T::regs().tscv().read().tsc() }; - let delta = now_can.overflowing_sub(ts_val).0 as u64; + let cantime = { T::regs().tscv().read().tsc() }; + let delta = cantime.overflowing_sub(ts_val).0 as u64; let ns = ns_per_timer_tick * delta as u64; now_embassy - embassy_time::Duration::from_nanos(ns) } +#[cfg(not(feature = "time"))] +fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + ts_val +} + fn curr_error() -> Option { let err = { T::regs().psr().read() }; if err.bo() { @@ -269,14 +200,14 @@ fn curr_error() -> Option { let lec = err.lec().to_bits(); } } - if let Ok(err) = LastErrorCode::try_from(lec) { - return BusError::try_from(err); + if let Ok(err) = BusError::try_from(lec) { + return Some(err); } } None } -impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { +impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. /// You must call [Fdcan::enable_non_blocking] to use the peripheral. pub fn new( @@ -286,7 +217,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { _irqs: impl interrupt::typelevel::Binding> + interrupt::typelevel::Binding> + 'd, - ) -> Fdcan<'d, T, fdcan::ConfigMode> { + ) -> Fdcan<'d, T, ConfigMode> { into_ref!(peri, rx, tx); rx.set_as_af(rx.af_num(), AFType::Input); @@ -294,11 +225,12 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { T::enable_and_reset(); + let mut config = crate::can::fd::config::FdCanConfig::default(); + T::registers().into_config_mode(config); + rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode(); - T::configure_msg_ram(); unsafe { // Enable timestamping @@ -308,6 +240,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); #[cfg(stm32h7)] T::regs().tscc().write(|w| w.set_tss(0x01)); + config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); T::IT0Interrupt::unpend(); // Not unsafe T::IT0Interrupt::enable(); @@ -320,38 +253,104 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); } - can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); - can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg); - can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete); - can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); - can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true); + T::regs().ie().modify(|w| { + w.set_rfne(0, true); // Rx Fifo 0 New Msg + w.set_rfne(1, true); // Rx Fifo 1 New Msg + w.set_tce(true); // Tx Complete + }); + T::regs().ile().modify(|w| { + w.set_eint0(true); // Interrupt Line 0 + w.set_eint1(true); // Interrupt Line 1 + }); - let ns_per_timer_tick = calc_ns_per_timer_tick::(can.get_config().frame_transmit); - Self { can, ns_per_timer_tick } + let ns_per_timer_tick = calc_ns_per_timer_tick::(config.frame_transmit); + Self { + config, + instance: FdcanInstance(peri), + _mode: PhantomData::, + ns_per_timer_tick, + } + } + + /// Get configuration + pub fn config(&self) -> crate::can::fd::config::FdCanConfig { + return self.config; + } + + /// Set configuration + pub fn set_config(&mut self, config: crate::can::fd::config::FdCanConfig) { + self.config = config; } /// Configures the bit timings calculated from supplied bitrate. pub fn set_bitrate(&mut self, bitrate: u32) { let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); - self.can.set_nominal_bit_timing(config::NominalBitTiming { + + let nbtr = crate::can::fd::config::NominalBitTiming { sync_jump_width: bit_timing.sync_jump_width, prescaler: bit_timing.prescaler, seg1: bit_timing.seg1, seg2: bit_timing.seg2, - }); + }; + self.config = self.config.set_nominal_bit_timing(nbtr); + } + + /// Configures the bit timings for VBR data calculated from supplied bitrate. + pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) { + let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); + // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M + let nbtr = crate::can::fd::config::DataBitTiming { + transceiver_delay_compensation, + sync_jump_width: bit_timing.sync_jump_width, + prescaler: bit_timing.prescaler, + seg1: bit_timing.seg1, + seg2: bit_timing.seg2, + }; + self.config.frame_transmit = FrameTransmissionConfig::AllowFdCanAndBRS; + self.config = self.config.set_data_bit_timing(nbtr); + } + + /// Set an Standard Address CAN filter into slot 'id' + #[inline] + pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) { + T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter); + } + + /// Set an array of Standard Address CAN filters and overwrite the current set + pub fn set_standard_filters(&mut self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) { + for (i, f) in filters.iter().enumerate() { + T::registers().msg_ram_mut().filters.flssa[i].activate(*f); + } + } + + /// Set an Extended Address CAN filter into slot 'id' + #[inline] + pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { + T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter); + } + + /// Set an array of Extended Address CAN filters and overwrite the current set + pub fn set_extended_filters(&mut self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) { + for (i, f) in filters.iter().enumerate() { + T::registers().msg_ram_mut().filters.flesa[i].activate(*f); + } } } macro_rules! impl_transition { ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => { - impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> { + impl<'d, T: Instance> Fdcan<'d, T, $from_mode> { /// Transition from $from_mode:ident mode to $to_mode:ident mode - pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> { - let ns_per_timer_tick = calc_ns_per_timer_tick::(self.can.get_config().frame_transmit); - Fdcan { - can: self.can.$func(), + pub fn $name(self) -> Fdcan<'d, T, $to_mode> { + let ns_per_timer_tick = calc_ns_per_timer_tick::(self.config.frame_transmit); + T::registers().$func(self.config); + let ret = Fdcan { + config: self.config, + instance: self.instance, + _mode: PhantomData::<$to_mode>, ns_per_timer_tick, - } + }; + ret } } }; @@ -376,38 +375,16 @@ impl_transition!( impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M> where - M: fdcan::Transmit, - M: fdcan::Receive, + M: Transmit, + M: Receive, { - /// Queues the message to be sent but exerts backpressure. If a lower-priority - /// frame is dropped from the mailbox, it is returned. If no lower-priority frames - /// can be replaced, this call asynchronously waits for a frame to be successfully - /// transmitted, then tries again. - pub async fn write(&mut self, frame: &TxFrame) -> Option { - poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); - if let Ok(dropped) = self - .can - .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { - TxFrame::from_preserved(hdr, data32) - }) - { - return Poll::Ready(dropped.flatten()); - } - - // Couldn't replace any lower priority frames. Need to wait for some mailboxes - // to clear. - Poll::Pending - }) - .await - } - /// Flush one of the TX mailboxes. - pub async fn flush(&self, mb: fdcan::Mailbox) { + pub async fn flush(&self, idx: usize) { poll_fn(|cx| { T::state().tx_waker.register(cx.waker()); - - let idx: u8 = mb.into(); + if idx > 3 { + panic!("Bad mailbox"); + } let idx = 1 << idx; if !T::regs().txbrp().read().trp(idx) { return Poll::Ready(()); @@ -418,37 +395,77 @@ where .await; } + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + pub async fn write(&mut self, frame: &ClassicFrame) -> Option { + poll_fn(|cx| { + T::state().tx_waker.register(cx.waker()); + + if let Ok(dropped) = T::registers().write_classic(frame) { + return Poll::Ready(dropped); + } + + // Couldn't replace any lower priority frames. Need to wait for some mailboxes + // to clear. + Poll::Pending + }) + .await + } + /// Returns the next received message frame - pub async fn read(&mut self) -> Result { + pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { poll_fn(|cx| { T::state().err_waker.register(cx.waker()); T::state().rx_waker.register(cx.waker()); - let mut buffer: [u8; 64] = [0; 64]; - if let Ok(rx) = self.can.receive0(&mut buffer) { - // rx: fdcan::ReceiveOverrun - // TODO: report overrun? - // for now we just drop it + if let Some((msg, ts)) = T::registers().read_classic(0) { + let ts = calc_timestamp::(self.ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some((msg, ts)) = T::registers().read_classic(1) { + let ts = calc_timestamp::(self.ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some(err) = curr_error::() { + // TODO: this is probably wrong + return Poll::Ready(Err(err)); + } + Poll::Pending + }) + .await + } - let frame: RxFrame = RxFrame::new( - rx.unwrap(), - &buffer, - #[cfg(feature = "time")] - calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), - ); - return Poll::Ready(Ok(frame)); - } else if let Ok(rx) = self.can.receive1(&mut buffer) { - // rx: fdcan::ReceiveOverrun - // TODO: report overrun? - // for now we just drop it + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { + poll_fn(|cx| { + T::state().tx_waker.register(cx.waker()); - let frame: RxFrame = RxFrame::new( - rx.unwrap(), - &buffer, - #[cfg(feature = "time")] - calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), - ); - return Poll::Ready(Ok(frame)); + if let Ok(dropped) = T::registers().write_fd(frame) { + return Poll::Ready(dropped); + } + + // Couldn't replace any lower priority frames. Need to wait for some mailboxes + // to clear. + Poll::Pending + }) + .await + } + + /// Returns the next received message frame + pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + T::state().rx_waker.register(cx.waker()); + + if let Some((msg, ts)) = T::registers().read_fd(0) { + let ts = calc_timestamp::(self.ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some((msg, ts)) = T::registers().read_fd(1) { + let ts = calc_timestamp::(self.ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); } else if let Some(err) = curr_error::() { // TODO: this is probably wrong return Poll::Ready(Err(err)); @@ -459,40 +476,67 @@ where } /// Split instance into separate Tx(write) and Rx(read) portions - pub fn split<'c>(&'c mut self) -> (FdcanTx<'c, 'd, T, M>, FdcanRx<'c, 'd, T, M>) { - let (mut _control, tx, rx0, rx1) = self.can.split_by_ref(); + pub fn split(self) -> (FdcanTx<'d, T, M>, FdcanRx<'d, T, M>) { ( - FdcanTx { _control, tx }, + FdcanTx { + _instance: self.instance, + _mode: self._mode, + }, FdcanRx { - rx0, - rx1, + _instance1: PhantomData::, + _instance2: T::regs(), + _mode: self._mode, ns_per_timer_tick: self.ns_per_timer_tick, }, ) } } -/// FDCAN Tx only Instance -pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> { - _control: &'c mut fdcan::FdCanControl, M>, - tx: &'c mut fdcan::Tx, M>, +/// FDCAN Rx only Instance +#[allow(dead_code)] +pub struct FdcanRx<'d, T: Instance, M: Receive> { + _instance1: PhantomData, + _instance2: &'d crate::pac::can::Fdcan, + _mode: PhantomData, + ns_per_timer_tick: u64, // For FDCAN internal timer } -impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> { +/// FDCAN Tx only Instance +pub struct FdcanTx<'d, T: Instance, M: Transmit> { + _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); + _mode: PhantomData, +} + +impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> { /// Queues the message to be sent but exerts backpressure. If a lower-priority /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. - pub async fn write(&mut self, frame: &TxFrame) -> Option { + pub async fn write(&mut self, frame: &ClassicFrame) -> Option { poll_fn(|cx| { T::state().tx_waker.register(cx.waker()); - if let Ok(dropped) = self - .tx - .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { - TxFrame::from_preserved(hdr, data32) - }) - { - return Poll::Ready(dropped.flatten()); + + if let Ok(dropped) = T::registers().write_classic(frame) { + return Poll::Ready(dropped); + } + + // Couldn't replace any lower priority frames. Need to wait for some mailboxes + // to clear. + Poll::Pending + }) + .await + } + + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { + poll_fn(|cx| { + T::state().tx_waker.register(cx.waker()); + + if let Ok(dropped) = T::registers().write_fd(frame) { + return Poll::Ready(dropped); } // Couldn't replace any lower priority frames. Need to wait for some mailboxes @@ -503,65 +547,47 @@ impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> { } } -/// FDCAN Rx only Instance -#[allow(dead_code)] -pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> { - rx0: &'c mut fdcan::Rx, M, fdcan::Fifo0>, - rx1: &'c mut fdcan::Rx, M, fdcan::Fifo1>, - ns_per_timer_tick: u64, // For FDCAN internal timer -} - -impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> { +impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> { /// Returns the next received message frame - pub async fn read(&mut self) -> Result { + pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { poll_fn(|cx| { T::state().err_waker.register(cx.waker()); T::state().rx_waker.register(cx.waker()); - let mut buffer: [u8; 64] = [0; 64]; - if let Ok(rx) = self.rx0.receive(&mut buffer) { - // rx: fdcan::ReceiveOverrun - // TODO: report overrun? - // for now we just drop it - let frame: RxFrame = RxFrame::new( - rx.unwrap(), - &buffer, - #[cfg(feature = "time")] - calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), - ); - return Poll::Ready(Ok(frame)); - } else if let Ok(rx) = self.rx1.receive(&mut buffer) { - // rx: fdcan::ReceiveOverrun - // TODO: report overrun? - // for now we just drop it - let frame: RxFrame = RxFrame::new( - rx.unwrap(), - &buffer, - #[cfg(feature = "time")] - calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), - ); - return Poll::Ready(Ok(frame)); + if let Some((msg, ts)) = T::registers().read_classic(0) { + let ts = calc_timestamp::(self.ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some((msg, ts)) = T::registers().read_classic(1) { + let ts = calc_timestamp::(self.ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); } else if let Some(err) = curr_error::() { // TODO: this is probably wrong return Poll::Ready(Err(err)); } - Poll::Pending }) .await } -} -impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> { - type Target = fdcan::FdCan, M>; - fn deref(&self) -> &Self::Target { - &self.can - } -} + /// Returns the next received message frame + pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + T::state().rx_waker.register(cx.waker()); -impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.can + if let Some((msg, ts)) = T::registers().read_fd(0) { + let ts = calc_timestamp::(self.ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some((msg, ts)) = T::registers().read_fd(1) { + let ts = calc_timestamp::(self.ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some(err) = curr_error::() { + // TODO: this is probably wrong + return Poll::Ready(Err(err)); + } + Poll::Pending + }) + .await } } @@ -585,11 +611,11 @@ pub(crate) mod sealed { } pub trait Instance { - const REGISTERS: *mut fdcan::RegisterBlock; - const MSG_RAM: *mut fdcan::message_ram::RegisterBlock; const MSG_RAM_OFFSET: usize; fn regs() -> &'static crate::pac::can::Fdcan; + fn registers() -> crate::can::fd::peripheral::Registers; + fn ram() -> &'static crate::pac::fdcanram::Fdcanram; fn state() -> &'static State; #[cfg(not(stm32h7))] @@ -599,7 +625,8 @@ pub(crate) mod sealed { fn configure_msg_ram() { let r = Self::regs(); - use fdcan::message_ram::*; + use crate::can::fd::message_ram::*; + //use fdcan::message_ram::*; let mut offset_words = Self::MSG_RAM_OFFSET as u16; // 11-bit filter @@ -677,28 +704,20 @@ pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + ' /// Fdcan Instance struct pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); -unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> { - const MSG_RAM: *mut RegisterBlock = T::MSG_RAM; -} - -unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T> -where - FdcanInstance<'d, T>: fdcan::message_ram::Instance, -{ - const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS; -} - macro_rules! impl_fdcan { ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { impl sealed::Instance for peripherals::$inst { - const REGISTERS: *mut fdcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; - const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = crate::pac::$msg_ram_inst.as_ptr() as *mut _; const MSG_RAM_OFFSET: usize = $msg_ram_offset; fn regs() -> &'static crate::pac::can::Fdcan { &crate::pac::$inst } - + fn registers() -> Registers { + Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst} + } + fn ram() -> &'static crate::pac::fdcanram::Fdcanram { + &crate::pac::$msg_ram_inst + } fn state() -> &'static sealed::State { static STATE: sealed::State = sealed::State::new(); &STATE diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs new file mode 100644 index 000000000..725a9b1ab --- /dev/null +++ b/embassy-stm32/src/can/frame.rs @@ -0,0 +1,370 @@ +//! Definition for CAN Frames +use bit_field::BitField; + +/// CAN Header, without meta data +#[derive(Debug, Copy, Clone)] +pub struct Header { + id: embedded_can::Id, + len: u8, + flags: u8, +} + +impl Header { + const FLAG_RTR: usize = 0; // Remote + const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN + const FLAG_BRS: usize = 2; // Bit-rate switching, ignored for Classic CAN + + /// Create new CAN Header + pub fn new(id: embedded_can::Id, len: u8, rtr: bool) -> Header { + let mut flags = 0u8; + flags.set_bit(Self::FLAG_RTR, rtr); + Header { id, len, flags } + } + + /// Create new CAN FD Header + pub fn new_fd(id: embedded_can::Id, len: u8, rtr: bool, brs: bool) -> Header { + let mut flags = 0u8; + flags.set_bit(Self::FLAG_RTR, rtr); + flags.set_bit(Self::FLAG_FDCAN, true); + flags.set_bit(Self::FLAG_BRS, brs); + Header { id, len, flags } + } + + /// Return ID + pub fn id(&self) -> &embedded_can::Id { + &self.id + } + + /// Return length as u8 + pub fn len(&self) -> u8 { + self.len + } + + /// Is remote frame + pub fn rtr(&self) -> bool { + self.flags.get_bit(Self::FLAG_RTR) + } + + /// Request/is FDCAN frame + pub fn fdcan(&self) -> bool { + self.flags.get_bit(Self::FLAG_FDCAN) + } + + /// Request/is Flexible Data Rate + pub fn bit_rate_switching(&self) -> bool { + self.flags.get_bit(Self::FLAG_BRS) + } +} + +/// Payload of a classic CAN data frame. +/// +/// Contains 0 to 8 Bytes of data. +#[derive(Debug, Copy, Clone)] +pub struct ClassicData { + pub(crate) bytes: [u8; 8], +} + +impl ClassicData { + /// Creates a data payload from a raw byte slice. + /// + /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or + /// cannot be represented with an FDCAN DLC. + pub fn new(data: &[u8]) -> Option { + if !FdData::is_valid_len(data.len()) { + return None; + } + + let mut bytes = [0; 8]; + bytes[..data.len()].copy_from_slice(data); + + Some(Self { bytes }) + } + + /// Raw read access to data. + pub fn raw(&self) -> &[u8] { + &self.bytes + } + + /// Checks if the length can be encoded in FDCAN DLC field. + pub const fn is_valid_len(len: usize) -> bool { + match len { + 0..=8 => true, + _ => false, + } + } + + /// Creates an empty data payload containing 0 bytes. + #[inline] + pub const fn empty() -> Self { + Self { bytes: [0; 8] } + } +} + +/// Frame with up to 8 bytes of data payload as per Classic CAN +#[derive(Debug, Copy, Clone)] +pub struct ClassicFrame { + can_header: Header, + data: ClassicData, +} + +impl ClassicFrame { + pub(crate) const MAX_DATA_LEN: usize = 8; + + /// Create a new CAN classic Frame + pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame { + ClassicFrame { can_header, data } + } + + /// Create new extended frame + pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option { + if let Some(id) = embedded_can::ExtendedId::new(raw_id) { + match ClassicData::new(raw_data) { + Some(data) => Some(ClassicFrame::new( + Header::new(id.into(), raw_data.len() as u8, false), + data, + )), + None => None, + } + } else { + None + } + } + + /// Create new standard frame + pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option { + if let Some(id) = embedded_can::StandardId::new(raw_id) { + match ClassicData::new(raw_data) { + Some(data) => Some(ClassicFrame::new( + Header::new(id.into(), raw_data.len() as u8, false), + data, + )), + None => None, + } + } else { + None + } + } + + /// Create new remote frame + pub fn new_remote(id: impl Into, len: usize) -> Option { + if len <= 8usize { + Some(ClassicFrame::new( + Header::new(id.into(), len as u8, true), + ClassicData::empty(), + )) + } else { + None + } + } + + /// Get reference to data + pub fn header(&self) -> &Header { + &self.can_header + } + + /// Return ID + pub fn id(&self) -> &embedded_can::Id { + &self.can_header.id + } + + /// Get reference to data + pub fn data(&self) -> &[u8] { + &self.data.raw() + } +} + +impl embedded_can::Frame for ClassicFrame { + fn new(id: impl Into, raw_data: &[u8]) -> Option { + match ClassicData::new(raw_data) { + Some(data) => Some(ClassicFrame::new( + Header::new(id.into(), raw_data.len() as u8, false), + data, + )), + None => None, + } + } + fn new_remote(id: impl Into, len: usize) -> Option { + if len <= 8 { + Some(ClassicFrame::new( + Header::new(id.into(), len as u8, true), + ClassicData::empty(), + )) + } else { + None + } + } + fn is_extended(&self) -> bool { + match self.can_header.id { + embedded_can::Id::Extended(_) => true, + embedded_can::Id::Standard(_) => true, + } + } + fn is_remote_frame(&self) -> bool { + self.can_header.rtr() + } + fn id(&self) -> embedded_can::Id { + self.can_header.id + } + fn dlc(&self) -> usize { + self.can_header.len as usize + } + fn data(&self) -> &[u8] { + &self.data.raw() + } +} + +/// Payload of a (FD)CAN data frame. +/// +/// Contains 0 to 64 Bytes of data. +#[derive(Debug, Copy, Clone)] +pub struct FdData { + pub(crate) bytes: [u8; 64], +} + +impl FdData { + /// Creates a data payload from a raw byte slice. + /// + /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or + /// cannot be represented with an FDCAN DLC. + pub fn new(data: &[u8]) -> Option { + if !FdData::is_valid_len(data.len()) { + return None; + } + + let mut bytes = [0; 64]; + bytes[..data.len()].copy_from_slice(data); + + Some(Self { bytes }) + } + + /// Raw read access to data. + pub fn raw(&self) -> &[u8] { + &self.bytes + } + + /// Checks if the length can be encoded in FDCAN DLC field. + pub const fn is_valid_len(len: usize) -> bool { + match len { + 0..=8 => true, + 12 => true, + 16 => true, + 20 => true, + 24 => true, + 32 => true, + 48 => true, + 64 => true, + _ => false, + } + } + + /// Creates an empty data payload containing 0 bytes. + #[inline] + pub const fn empty() -> Self { + Self { bytes: [0; 64] } + } +} + +/// Frame with up to 8 bytes of data payload as per Fd CAN +#[derive(Debug, Copy, Clone)] +pub struct FdFrame { + can_header: Header, + data: FdData, +} + +impl FdFrame { + pub(crate) const MAX_DATA_LEN: usize = 64; + + /// Create a new CAN classic Frame + pub fn new(can_header: Header, data: FdData) -> FdFrame { + FdFrame { can_header, data } + } + + /// Create new extended frame + pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option { + if let Some(id) = embedded_can::ExtendedId::new(raw_id) { + match FdData::new(raw_data) { + Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), + None => None, + } + } else { + None + } + } + + /// Create new standard frame + pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option { + if let Some(id) = embedded_can::StandardId::new(raw_id) { + match FdData::new(raw_data) { + Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), + None => None, + } + } else { + None + } + } + + /// Create new remote frame + pub fn new_remote(id: impl Into, len: usize) -> Option { + if len <= 8 { + Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty())) + } else { + None + } + } + + /// Get reference to data + pub fn header(&self) -> &Header { + &self.can_header + } + + /// Return ID + pub fn id(&self) -> &embedded_can::Id { + &self.can_header.id + } + + /// Get reference to data + pub fn data(&self) -> &[u8] { + &self.data.raw() + } +} + +impl embedded_can::Frame for FdFrame { + fn new(id: impl Into, raw_data: &[u8]) -> Option { + match FdData::new(raw_data) { + Some(data) => Some(FdFrame::new( + Header::new_fd(id.into(), raw_data.len() as u8, false, true), + data, + )), + None => None, + } + } + fn new_remote(id: impl Into, len: usize) -> Option { + if len <= 8 { + Some(FdFrame::new( + Header::new_fd(id.into(), len as u8, true, true), + FdData::empty(), + )) + } else { + None + } + } + fn is_extended(&self) -> bool { + match self.can_header.id { + embedded_can::Id::Extended(_) => true, + embedded_can::Id::Standard(_) => true, + } + } + fn is_remote_frame(&self) -> bool { + self.can_header.rtr() + } + fn id(&self) -> embedded_can::Id { + self.can_header.id + } + // Returns length in bytes even for CANFD packets which embedded-can does not really mention. + fn dlc(&self) -> usize { + self.can_header.len as usize + } + fn data(&self) -> &[u8] { + &self.data.raw() + } +} diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 895ad3e7c..fdb325f06 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -20,6 +20,7 @@ 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" +embedded-can = { version = "0.4" } 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 } diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 727921fba..5ff4f0ef0 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -20,32 +20,100 @@ async fn main(_spawner: Spawner) { let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + can.set_extended_filter( + can::fd::filter::ExtendedFilterSlot::_0, + can::fd::filter::ExtendedFilter::accept_all_into_fifo1(), + ); + // 250k bps can.set_bitrate(250_000); + // 1M bps + can.set_fd_data_bitrate(1_000_000, false); + info!("Configured"); - //let mut can = can.into_external_loopback_mode(); - let mut can = can.into_normal_mode(); + //let mut can = can.into_normal_mode(); + let mut can = can.into_internal_loopback_mode(); let mut i = 0; + let mut last_read_ts = embassy_time::Instant::now(); + loop { - let frame = can::TxFrame::new( - can::TxFrameHeader { - len: 1, - frame_format: can::FrameFormat::Standard, - id: can::StandardId::new(0x123).unwrap().into(), - bit_rate_switching: false, - marker: None, - }, - &[i], - ) - .unwrap(); + let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); + _ = can.write(&frame).await; match can.read().await { - Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {} {:02x} --- {}ms", + rx_frame.header().len(), + rx_frame.data()[0..rx_frame.header().len() as usize], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + if i > 2 { + break; + } + } + + // Use the FD API's even if we don't get FD packets. + loop { + let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap(); + info!("Writing frame using FD API"); + + _ = can.write_fd(&frame).await; + + match can.read_fd().await { + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {} {:02x} --- using FD API {}ms", + rx_frame.header().len(), + rx_frame.data()[0..rx_frame.header().len() as usize], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + if i > 4 { + break; + } + } + + let (mut tx, mut rx) = can.split(); + // With split + loop { + let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + _ = tx.write(&frame).await; + + match rx.read().await { + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {} {:02x} --- {}ms", + rx_frame.header().len(), + rx_frame.data()[0..rx_frame.header().len() as usize], + delta, + ) + } Err(_err) => error!("Error in frame"), } diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index 2906d1576..4b29a0d21 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -16,54 +16,77 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - // configure FDCAN to use PLL1_Q at 64 MHz - config.rcc.pll1 = Some(rcc::Pll { - source: rcc::PllSource::HSI, - prediv: rcc::PllPreDiv::DIV4, - mul: rcc::PllMul::MUL8, - divp: None, - divq: Some(rcc::PllDiv::DIV2), - divr: None, + config.rcc.hse = Some(rcc::Hse { + freq: embassy_stm32::time::Hertz(25_000_000), + mode: rcc::HseMode::Oscillator, }); - config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; + config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; let peripherals = embassy_stm32::init(config); + //let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); - can.can.apply_config( - can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { - sync_jump_width: 1.try_into().unwrap(), - prescaler: 8.try_into().unwrap(), - seg1: 13.try_into().unwrap(), - seg2: 2.try_into().unwrap(), - }), - ); + // 250k bps + can.set_bitrate(250_000); - info!("Configured"); + //let mut can = can.into_internal_loopback_mode(); + let mut can = can.into_normal_mode(); - let mut can = can.into_external_loopback_mode(); - //let mut can = can.into_normal_mode(); + info!("CAN Configured"); let mut i = 0; + let mut last_read_ts = embassy_time::Instant::now(); + loop { - let frame = can::TxFrame::new( - can::TxFrameHeader { - len: 1, - frame_format: can::FrameFormat::Standard, - id: can::StandardId::new(0x123).unwrap().into(), - bit_rate_switching: false, - marker: None, - }, - &[i], - ) - .unwrap(); + let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); _ = can.write(&frame).await; match can.read().await { - Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {:x} {:x} {:x} {:x} --- NEW {}", + rx_frame.data()[0], + rx_frame.data()[1], + rx_frame.data()[2], + rx_frame.data()[3], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + if i > 3 { + break; + } + } + + let (mut tx, mut rx) = can.split(); + // With split + loop { + let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + _ = tx.write(&frame).await; + + match rx.read().await { + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {:x} {:x} {:x} {:x} --- NEW {}", + rx_frame.data()[0], + rx_frame.data()[1], + rx_frame.data()[2], + rx_frame.data()[3], + delta, + ) + } Err(_err) => error!("Error in frame"), } diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 2906d1576..4b29a0d21 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -16,54 +16,77 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - // configure FDCAN to use PLL1_Q at 64 MHz - config.rcc.pll1 = Some(rcc::Pll { - source: rcc::PllSource::HSI, - prediv: rcc::PllPreDiv::DIV4, - mul: rcc::PllMul::MUL8, - divp: None, - divq: Some(rcc::PllDiv::DIV2), - divr: None, + config.rcc.hse = Some(rcc::Hse { + freq: embassy_stm32::time::Hertz(25_000_000), + mode: rcc::HseMode::Oscillator, }); - config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; + config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; let peripherals = embassy_stm32::init(config); + //let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); - can.can.apply_config( - can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { - sync_jump_width: 1.try_into().unwrap(), - prescaler: 8.try_into().unwrap(), - seg1: 13.try_into().unwrap(), - seg2: 2.try_into().unwrap(), - }), - ); + // 250k bps + can.set_bitrate(250_000); - info!("Configured"); + //let mut can = can.into_internal_loopback_mode(); + let mut can = can.into_normal_mode(); - let mut can = can.into_external_loopback_mode(); - //let mut can = can.into_normal_mode(); + info!("CAN Configured"); let mut i = 0; + let mut last_read_ts = embassy_time::Instant::now(); + loop { - let frame = can::TxFrame::new( - can::TxFrameHeader { - len: 1, - frame_format: can::FrameFormat::Standard, - id: can::StandardId::new(0x123).unwrap().into(), - bit_rate_switching: false, - marker: None, - }, - &[i], - ) - .unwrap(); + let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); _ = can.write(&frame).await; match can.read().await { - Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {:x} {:x} {:x} {:x} --- NEW {}", + rx_frame.data()[0], + rx_frame.data()[1], + rx_frame.data()[2], + rx_frame.data()[3], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + if i > 3 { + break; + } + } + + let (mut tx, mut rx) = can.split(); + // With split + loop { + let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + _ = tx.write(&frame).await; + + match rx.read().await { + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {:x} {:x} {:x} {:x} --- NEW {}", + rx_frame.data()[0], + rx_frame.data()[1], + rx_frame.data()[2], + rx_frame.data()[3], + delta, + ) + } Err(_err) => error!("Error in frame"), } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 8554682a4..5b28b5849 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -69,6 +69,7 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } +embedded-can = { version = "0.4" } micromath = "2.0.0" panic-probe = { version = "0.3.0", features = ["print-defmt"] } rand_core = { version = "0.6", default-features = false } diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index 7363eaa16..76c27d091 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -36,7 +36,7 @@ fn options() -> TestOptions { c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; TestOptions { config: c, - max_latency: Duration::from_micros(3800), + max_latency: Duration::from_micros(1200), second_fifo_working: false, } } @@ -53,12 +53,12 @@ fn options() -> TestOptions { c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; TestOptions { config: c, - max_latency: Duration::from_micros(5500), + max_latency: Duration::from_micros(1200), second_fifo_working: false, } } -#[cfg(any(feature = "stm32g491re"))] +#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] fn options() -> TestOptions { info!("G4 config"); TestOptions { @@ -80,9 +80,9 @@ async fn main(_spawner: Spawner) { // 250k bps can.set_bitrate(250_000); - can.can.set_extended_filter( - can::filter::ExtendedFilterSlot::_0, - can::filter::ExtendedFilter::accept_all_into_fifo1(), + can.set_extended_filter( + can::fd::filter::ExtendedFilterSlot::_0, + can::fd::filter::ExtendedFilter::accept_all_into_fifo1(), ); let mut can = can.into_internal_loopback_mode(); @@ -91,31 +91,21 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = can::TxFrame::new( - can::TxFrameHeader { - len: 1, - frame_format: can::FrameFormat::Standard, - id: can::StandardId::new(0x123).unwrap().into(), - bit_rate_switching: false, - marker: None, - }, - &[i], - ) - .unwrap(); + let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); info!("Transmitting frame..."); let tx_ts = Instant::now(); can.write(&tx_frame).await; - let envelope = can.read().await.unwrap(); + let (frame, timestamp) = can.read().await.unwrap(); info!("Frame received!"); // Check data. - assert!(i == envelope.data()[0], "{} == {}", i, envelope.data()[0]); + assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); - info!("loopback time {}", envelope.header.time_stamp); - info!("loopback frame {=u8}", envelope.data()[0]); - let latency = envelope.timestamp.saturating_duration_since(tx_ts); + info!("loopback time {}", timestamp); + info!("loopback frame {=u8}", frame.data()[0]); + let latency = timestamp.saturating_duration_since(tx_ts); info!("loopback latency {} us", latency.as_micros()); // Theoretical minimum latency is 55us, actual is usually ~80us @@ -143,47 +133,26 @@ async fn main(_spawner: Spawner) { // in each FIFO so make sure we write enough to fill them both up before reading. for i in 0..3 { // Try filling up the RX FIFO0 buffers with standard packets - let tx_frame = can::TxFrame::new( - can::TxFrameHeader { - len: 1, - frame_format: can::FrameFormat::Standard, - id: can::StandardId::new(0x123).unwrap().into(), - bit_rate_switching: false, - marker: None, - }, - &[i], - ) - .unwrap(); + let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); info!("Transmitting frame {}", i); can.write(&tx_frame).await; } for i in 3..max_buffered { // Try filling up the RX FIFO0 buffers with extended packets - let tx_frame = can::TxFrame::new( - can::TxFrameHeader { - len: 1, - frame_format: can::FrameFormat::Standard, - id: can::ExtendedId::new(0x1232344).unwrap().into(), - bit_rate_switching: false, - marker: None, - }, - &[i], - ) - .unwrap(); - + let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); info!("Transmitting frame {}", i); can.write(&tx_frame).await; } // Try and receive all 6 packets for i in 0..max_buffered { - let envelope = can.read().await.unwrap(); - match envelope.header.id { - can::Id::Extended(id) => { - info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); + let (frame, _ts) = can.read().await.unwrap(); + match frame.id() { + embedded_can::Id::Extended(id) => { + info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); } - can::Id::Standard(id) => { - info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); + embedded_can::Id::Standard(id) => { + info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); } } } @@ -192,48 +161,26 @@ async fn main(_spawner: Spawner) { let (mut tx, mut rx) = can.split(); for i in 0..3 { // Try filling up the RX FIFO0 buffers with standard packets - let tx_frame = can::TxFrame::new( - can::TxFrameHeader { - len: 1, - frame_format: can::FrameFormat::Standard, - id: can::StandardId::new(0x123).unwrap().into(), - bit_rate_switching: false, - marker: None, - }, - &[i], - ) - .unwrap(); - + let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); info!("Transmitting frame {}", i); tx.write(&tx_frame).await; } for i in 3..max_buffered { // Try filling up the RX FIFO0 buffers with extended packets - let tx_frame = can::TxFrame::new( - can::TxFrameHeader { - len: 1, - frame_format: can::FrameFormat::Standard, - id: can::ExtendedId::new(0x1232344).unwrap().into(), - bit_rate_switching: false, - marker: None, - }, - &[i], - ) - .unwrap(); - + let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); info!("Transmitting frame {}", i); tx.write(&tx_frame).await; } // Try and receive all 6 packets for i in 0..max_buffered { - let envelope = rx.read().await.unwrap(); - match envelope.header.id { - can::Id::Extended(id) => { - info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); + let (frame, _ts) = rx.read().await.unwrap(); + match frame.id() { + embedded_can::Id::Extended(id) => { + info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); } - can::Id::Standard(id) => { - info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); + embedded_can::Id::Standard(id) => { + info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); } } } From 200ace566f3da7db6f4119d6bd3b709a69293297 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 17 Feb 2024 10:51:31 +1000 Subject: [PATCH 496/760] Don't use word Standard for frame format because it can be confused with ID format. Use Classic instead to mean CAN 2.0B frames. --- .../src/can/fd/message_ram/common.rs | 6 +++--- embassy-stm32/src/can/fd/message_ram/enums.rs | 20 +++++++++---------- embassy-stm32/src/can/fd/mod.rs | 2 +- embassy-stm32/src/can/fd/peripheral.rs | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/src/can/fd/message_ram/common.rs b/embassy-stm32/src/can/fd/message_ram/common.rs index a67d68fa0..108c1a428 100644 --- a/embassy-stm32/src/can/fd/message_ram/common.rs +++ b/embassy-stm32/src/can/fd/message_ram/common.rs @@ -88,12 +88,12 @@ pub type FDF_R = generic::R; impl FDF_R { pub fn frame_format(&self) -> FrameFormat { match self.bits() { - false => FrameFormat::Standard, + false => FrameFormat::Classic, true => FrameFormat::Fdcan, } } - pub fn is_standard_format(&self) -> bool { - *self == FrameFormat::Standard + pub fn is_classic_format(&self) -> bool { + *self == FrameFormat::Classic } pub fn is_fdcan_format(&self) -> bool { *self == FrameFormat::Fdcan diff --git a/embassy-stm32/src/can/fd/message_ram/enums.rs b/embassy-stm32/src/can/fd/message_ram/enums.rs index 78285bf81..0ec5e0f34 100644 --- a/embassy-stm32/src/can/fd/message_ram/enums.rs +++ b/embassy-stm32/src/can/fd/message_ram/enums.rs @@ -5,7 +5,7 @@ #[derive(Clone, Copy, Debug, PartialEq)] pub enum DataLength { - Standard(u8), + Classic(u8), Fdcan(u8), } impl DataLength { @@ -14,8 +14,8 @@ impl DataLength { /// Uses the byte length and Type of frame as input pub fn new(len: u8, ff: FrameFormat) -> DataLength { match ff { - FrameFormat::Standard => match len { - 0..=8 => DataLength::Standard(len), + FrameFormat::Classic => match len { + 0..=8 => DataLength::Classic(len), _ => panic!("DataLength > 8"), }, FrameFormat::Fdcan => match len { @@ -24,9 +24,9 @@ impl DataLength { }, } } - /// Specialised function to create standard frames - pub fn new_standard(len: u8) -> DataLength { - Self::new(len, FrameFormat::Standard) + /// Specialised function to create classic frames + pub fn new_classic(len: u8) -> DataLength { + Self::new(len, FrameFormat::Classic) } /// Specialised function to create FDCAN frames pub fn new_fdcan(len: u8) -> DataLength { @@ -36,13 +36,13 @@ impl DataLength { /// returns the length in bytes pub fn len(&self) -> u8 { match self { - DataLength::Standard(l) | DataLength::Fdcan(l) => *l, + DataLength::Classic(l) | DataLength::Fdcan(l) => *l, } } pub(crate) fn dlc(&self) -> u8 { match self { - DataLength::Standard(l) => *l, + DataLength::Classic(l) => *l, // See RM0433 Rev 7 Table 475. DLC coding DataLength::Fdcan(l) => match l { 0..=8 => *l, @@ -61,7 +61,7 @@ impl DataLength { impl From for FrameFormat { fn from(dl: DataLength) -> FrameFormat { match dl { - DataLength::Standard(_) => FrameFormat::Standard, + DataLength::Classic(_) => FrameFormat::Classic, DataLength::Fdcan(_) => FrameFormat::Fdcan, } } @@ -121,7 +121,7 @@ impl From for bool { /// Type of frame, standard (classic) or FdCAN #[derive(Clone, Copy, Debug, PartialEq)] pub enum FrameFormat { - Standard = 0, + Classic = 0, Fdcan = 1, } impl From for bool { diff --git a/embassy-stm32/src/can/fd/mod.rs b/embassy-stm32/src/can/fd/mod.rs index 0008fd3a8..271ca0b3c 100644 --- a/embassy-stm32/src/can/fd/mod.rs +++ b/embassy-stm32/src/can/fd/mod.rs @@ -1,4 +1,4 @@ -//! Module containing that which is speciffic to fdcan hardware variant +//! Module containing that which is specific to fdcan hardware variant pub mod config; pub mod filter; diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 6f390abb4..3422d7148 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -167,7 +167,7 @@ impl Registers { let len = match header_reg.to_data_length() { DataLength::Fdcan(len) => len, - DataLength::Standard(len) => len, + DataLength::Classic(len) => len, }; if len as usize > ClassicFrame::MAX_DATA_LEN { return None; @@ -202,7 +202,7 @@ impl Registers { let len = match header_reg.to_data_length() { DataLength::Fdcan(len) => len, - DataLength::Standard(len) => len, + DataLength::Classic(len) => len, }; if len as usize > FdFrame::MAX_DATA_LEN { return None; @@ -683,7 +683,7 @@ fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) { let frame_format = if header.len() > 8 || header.fdcan() { FrameFormat::Fdcan } else { - FrameFormat::Standard + FrameFormat::Classic }; let brs = header.len() > 8 || header.bit_rate_switching(); From 5d8c54fdea752d4a52b33a7f776b436f5934409c Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 17 Feb 2024 11:19:05 +1000 Subject: [PATCH 497/760] Move error conversion to peripheral.rs --- embassy-stm32/src/can/enums.rs | 17 ----------- embassy-stm32/src/can/fd/peripheral.rs | 39 ++++++++++++++++++++++++++ embassy-stm32/src/can/fdcan.rs | 32 +++------------------ 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 135010011..36139a45c 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs @@ -1,5 +1,4 @@ //! Enums shared between CAN controller types. -use core::convert::TryFrom; /// Bus error #[derive(Debug)] @@ -29,19 +28,3 @@ pub enum BusError { /// At least one of error counter has reached the Error_Warning limit of 96. BusWarning, } -impl TryFrom for BusError { - type Error = (); - fn try_from(value: u8) -> Result { - match value { - //0b000 => None, - 0b001 => Ok(Self::Stuff), - 0b010 => Ok(Self::Form), - 0b011 => Ok(Self::Acknowledge), - 0b100 => Ok(Self::BitRecessive), - 0b101 => Ok(Self::BitDominant), - 0b110 => Ok(Self::Crc), - //0b111 => Ok(Self::NoError), - _ => Err(()), - } - } -} diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 3422d7148..487b8f413 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -3,6 +3,9 @@ use core::convert::Infallible; use core::slice; +use cfg_if::cfg_if; + +use crate::can::enums::*; use crate::can::fd::config::*; use crate::can::fd::message_ram::enums::*; use crate::can::fd::message_ram::{RegisterBlock, RxFifoElement, TxBufferElement}; @@ -98,6 +101,42 @@ impl Registers { self.regs.txbar().modify(|w| w.set_ar(bufidx, true)); } + fn reg_to_error(value: u8) -> Option { + match value { + //0b000 => None, + 0b001 => Some(BusError::Stuff), + 0b010 => Some(BusError::Form), + 0b011 => Some(BusError::Acknowledge), + 0b100 => Some(BusError::BitRecessive), + 0b101 => Some(BusError::BitDominant), + 0b110 => Some(BusError::Crc), + //0b111 => Some(BusError::NoError), + _ => None, + } + } + + pub fn curr_error(&self) -> Option { + let err = { self.regs.psr().read() }; + if err.bo() { + return Some(BusError::BusOff); + } else if err.ep() { + return Some(BusError::BusPassive); + } else if err.ew() { + return Some(BusError::BusWarning); + } else { + cfg_if! { + if #[cfg(stm32h7)] { + let lec = err.lec(); + } else { + let lec = err.lec().to_bits(); + } + } + if let Some(err) = Self::reg_to_error(lec) { + return Some(err); + } + } + None + } /// Returns if the tx queue is able to accept new messages without having to cancel an existing one #[inline] pub fn tx_queue_is_full(&self) -> bool { diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index b94e42707..987748e06 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -4,7 +4,6 @@ use core::marker::PhantomData; use core::task::Poll; pub mod fd; -use cfg_if::cfg_if; use embassy_hal_internal::{into_ref, PeripheralRef}; use fd::config::*; use fd::filter::*; @@ -184,29 +183,6 @@ fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestam ts_val } -fn curr_error() -> Option { - let err = { T::regs().psr().read() }; - if err.bo() { - return Some(BusError::BusOff); - } else if err.ep() { - return Some(BusError::BusPassive); - } else if err.ew() { - return Some(BusError::BusWarning); - } else { - cfg_if! { - if #[cfg(stm32h7)] { - let lec = err.lec(); - } else { - let lec = err.lec().to_bits(); - } - } - if let Ok(err) = BusError::try_from(lec) { - return Some(err); - } - } - None -} - impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. /// You must call [Fdcan::enable_non_blocking] to use the peripheral. @@ -426,7 +402,7 @@ where } else if let Some((msg, ts)) = T::registers().read_classic(1) { let ts = calc_timestamp::(self.ns_per_timer_tick, ts); return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = curr_error::() { + } else if let Some(err) = T::registers().curr_error() { // TODO: this is probably wrong return Poll::Ready(Err(err)); } @@ -466,7 +442,7 @@ where } else if let Some((msg, ts)) = T::registers().read_fd(1) { let ts = calc_timestamp::(self.ns_per_timer_tick, ts); return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = curr_error::() { + } else if let Some(err) = T::registers().curr_error() { // TODO: this is probably wrong return Poll::Ready(Err(err)); } @@ -560,7 +536,7 @@ impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> { } else if let Some((msg, ts)) = T::registers().read_classic(1) { let ts = calc_timestamp::(self.ns_per_timer_tick, ts); return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = curr_error::() { + } else if let Some(err) = T::registers().curr_error() { // TODO: this is probably wrong return Poll::Ready(Err(err)); } @@ -581,7 +557,7 @@ impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> { } else if let Some((msg, ts)) = T::registers().read_fd(1) { let ts = calc_timestamp::(self.ns_per_timer_tick, ts); return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = curr_error::() { + } else if let Some(err) = T::registers().curr_error() { // TODO: this is probably wrong return Poll::Ready(Err(err)); } From 91c75c92a0e67c93550a163ae62b22a652bf2012 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 17 Feb 2024 18:10:45 +1000 Subject: [PATCH 498/760] Clean up and prep for buffered IRQ mode. - Reduce code duplicaiton in read/write methods - General clean-up - Prepare for buffered mode --- embassy-stm32/src/can/fdcan.rs | 347 ++++++++++++++++++--------------- 1 file changed, 188 insertions(+), 159 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 987748e06..42ce73ded 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -39,14 +39,17 @@ impl interrupt::typelevel::Handler for IT0Interrup let ir = regs.ir().read(); - if ir.tc() { - regs.ir().write(|w| w.set_tc(true)); - T::state().tx_waker.wake(); - } + { + if ir.tc() { + regs.ir().write(|w| w.set_tc(true)); + } + if ir.tefn() { + regs.ir().write(|w| w.set_tefn(true)); + } - if ir.tefn() { - regs.ir().write(|w| w.set_tefn(true)); - T::state().tx_waker.wake(); + match &T::state().tx_mode { + sealed::TxMode::NonBuffered(waker) => waker.wake(), + } } if ir.ped() || ir.pea() { @@ -57,15 +60,11 @@ impl interrupt::typelevel::Handler for IT0Interrup } if ir.rfn(0) { - let fifonr = 0 as usize; - regs.ir().write(|w| w.set_rfn(fifonr, true)); - - T::state().rx_waker.wake(); + T::state().rx_mode.on_interrupt::(0); } if ir.rfn(1) { - regs.ir().write(|w| w.set_rfn(1, true)); - T::state().rx_waker.wake(); + T::state().rx_mode.on_interrupt::(1); } } } @@ -148,7 +147,6 @@ pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { /// Reference to internals. instance: FdcanInstance<'d, T>, _mode: PhantomData, - ns_per_timer_tick: u64, // For FDCAN internal timer } fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { @@ -166,23 +164,6 @@ fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransm } } -#[cfg(feature = "time")] -fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { - let now_embassy = embassy_time::Instant::now(); - if ns_per_timer_tick == 0 { - return now_embassy; - } - let cantime = { T::regs().tscv().read().tsc() }; - let delta = cantime.overflowing_sub(ts_val).0 as u64; - let ns = ns_per_timer_tick * delta as u64; - now_embassy - embassy_time::Duration::from_nanos(ns) -} - -#[cfg(not(feature = "time"))] -fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { - ts_val -} - impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. /// You must call [Fdcan::enable_non_blocking] to use the peripheral. @@ -239,12 +220,10 @@ impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { w.set_eint1(true); // Interrupt Line 1 }); - let ns_per_timer_tick = calc_ns_per_timer_tick::(config.frame_transmit); Self { config, instance: FdcanInstance(peri), _mode: PhantomData::, - ns_per_timer_tick, } } @@ -319,12 +298,14 @@ macro_rules! impl_transition { /// Transition from $from_mode:ident mode to $to_mode:ident mode pub fn $name(self) -> Fdcan<'d, T, $to_mode> { let ns_per_timer_tick = calc_ns_per_timer_tick::(self.config.frame_transmit); + critical_section::with(|_| unsafe { + T::mut_state().ns_per_timer_tick = ns_per_timer_tick; + }); T::registers().$func(self.config); let ret = Fdcan { config: self.config, instance: self.instance, _mode: PhantomData::<$to_mode>, - ns_per_timer_tick, }; ret } @@ -357,7 +338,8 @@ where /// Flush one of the TX mailboxes. pub async fn flush(&self, idx: usize) { poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); + T::state().tx_mode.register(cx.waker()); + if idx > 3 { panic!("Bad mailbox"); } @@ -376,39 +358,12 @@ where /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write(&mut self, frame: &ClassicFrame) -> Option { - poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); - - if let Ok(dropped) = T::registers().write_classic(frame) { - return Poll::Ready(dropped); - } - - // Couldn't replace any lower priority frames. Need to wait for some mailboxes - // to clear. - Poll::Pending - }) - .await + T::state().tx_mode.write::(frame).await } /// Returns the next received message frame pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - T::state().rx_waker.register(cx.waker()); - - if let Some((msg, ts)) = T::registers().read_classic(0) { - let ts = calc_timestamp::(self.ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some((msg, ts)) = T::registers().read_classic(1) { - let ts = calc_timestamp::(self.ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = T::registers().curr_error() { - // TODO: this is probably wrong - return Poll::Ready(Err(err)); - } - Poll::Pending - }) - .await + T::state().rx_mode.read::().await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -416,45 +371,29 @@ where /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { - poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); - - if let Ok(dropped) = T::registers().write_fd(frame) { - return Poll::Ready(dropped); - } - - // Couldn't replace any lower priority frames. Need to wait for some mailboxes - // to clear. - Poll::Pending - }) - .await + T::state().tx_mode.write_fd::(frame).await } /// Returns the next received message frame pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - T::state().rx_waker.register(cx.waker()); + T::state().rx_mode.read_fd::().await + } - if let Some((msg, ts)) = T::registers().read_fd(0) { - let ts = calc_timestamp::(self.ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some((msg, ts)) = T::registers().read_fd(1) { - let ts = calc_timestamp::(self.ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = T::registers().curr_error() { - // TODO: this is probably wrong - return Poll::Ready(Err(err)); - } - Poll::Pending - }) - .await + /// Join split rx and tx portions back together + pub fn join(tx: FdcanTx<'d, T, M>, rx: FdcanRx<'d, T, M>) -> Self { + Fdcan { + config: tx.config, + //_instance2: T::regs(), + instance: tx._instance, + _mode: rx._mode, + } } /// Split instance into separate Tx(write) and Rx(read) portions pub fn split(self) -> (FdcanTx<'d, T, M>, FdcanRx<'d, T, M>) { ( FdcanTx { + config: self.config, _instance: self.instance, _mode: self._mode, }, @@ -462,10 +401,10 @@ where _instance1: PhantomData::, _instance2: T::regs(), _mode: self._mode, - ns_per_timer_tick: self.ns_per_timer_tick, }, ) } + } /// FDCAN Rx only Instance @@ -474,11 +413,11 @@ pub struct FdcanRx<'d, T: Instance, M: Receive> { _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, _mode: PhantomData, - ns_per_timer_tick: u64, // For FDCAN internal timer } /// FDCAN Tx only Instance pub struct FdcanTx<'d, T: Instance, M: Transmit> { + config: crate::can::fd::config::FdCanConfig, _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); _mode: PhantomData, } @@ -489,18 +428,7 @@ impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write(&mut self, frame: &ClassicFrame) -> Option { - poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); - - if let Ok(dropped) = T::registers().write_classic(frame) { - return Poll::Ready(dropped); - } - - // Couldn't replace any lower priority frames. Need to wait for some mailboxes - // to clear. - Poll::Pending - }) - .await + T::state().tx_mode.write::(frame).await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -508,80 +436,158 @@ impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { - poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); - - if let Ok(dropped) = T::registers().write_fd(frame) { - return Poll::Ready(dropped); - } - - // Couldn't replace any lower priority frames. Need to wait for some mailboxes - // to clear. - Poll::Pending - }) - .await + T::state().tx_mode.write_fd::(frame).await } } impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> { /// Returns the next received message frame pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - T::state().rx_waker.register(cx.waker()); - - if let Some((msg, ts)) = T::registers().read_classic(0) { - let ts = calc_timestamp::(self.ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some((msg, ts)) = T::registers().read_classic(1) { - let ts = calc_timestamp::(self.ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = T::registers().curr_error() { - // TODO: this is probably wrong - return Poll::Ready(Err(err)); - } - Poll::Pending - }) - .await + T::state().rx_mode.read::().await } /// Returns the next received message frame pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - T::state().rx_waker.register(cx.waker()); - - if let Some((msg, ts)) = T::registers().read_fd(0) { - let ts = calc_timestamp::(self.ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some((msg, ts)) = T::registers().read_fd(1) { - let ts = calc_timestamp::(self.ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = T::registers().curr_error() { - // TODO: this is probably wrong - return Poll::Ready(Err(err)); - } - Poll::Pending - }) - .await + T::state().rx_mode.read_fd::().await } } pub(crate) mod sealed { + use core::future::poll_fn; + use core::task::Poll; + use embassy_sync::waitqueue::AtomicWaker; + use crate::can::_version::{BusError, Timestamp}; + use crate::can::frame::{ClassicFrame, FdFrame}; + pub enum RxMode { + NonBuffered(AtomicWaker), + } + + impl RxMode { + pub fn register(&self, arg: &core::task::Waker) { + match self { + RxMode::NonBuffered(waker) => waker.register(arg), + } + } + + pub fn on_interrupt(&self, fifonr: usize) { + T::regs().ir().write(|w| w.set_rfn(fifonr, true)); + match self { + RxMode::NonBuffered(waker) => { + waker.wake(); + } + } + } + + pub async fn read(&self) -> Result<(ClassicFrame, Timestamp), BusError> { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + self.register(cx.waker()); + + if let Some((msg, ts)) = T::registers().read_classic(0) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some((msg, ts)) = T::registers().read_classic(1) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some(err) = T::registers().curr_error() { + // TODO: this is probably wrong + return Poll::Ready(Err(err)); + } + Poll::Pending + }) + .await + } + + pub async fn read_fd(&self) -> Result<(FdFrame, Timestamp), BusError> { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + self.register(cx.waker()); + + if let Some((msg, ts)) = T::registers().read_fd(0) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some((msg, ts)) = T::registers().read_fd(1) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + return Poll::Ready(Ok((msg, ts))); + } else if let Some(err) = T::registers().curr_error() { + // TODO: this is probably wrong + return Poll::Ready(Err(err)); + } + Poll::Pending + }) + .await + } + } + + pub enum TxMode { + NonBuffered(AtomicWaker), + } + + impl TxMode { + pub fn register(&self, arg: &core::task::Waker) { + match self { + TxMode::NonBuffered(waker) => { + waker.register(arg); + } + } + } + + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + pub async fn write(&self, frame: &ClassicFrame) -> Option { + poll_fn(|cx| { + self.register(cx.waker()); + + if let Ok(dropped) = T::registers().write_classic(frame) { + return Poll::Ready(dropped); + } + + // Couldn't replace any lower priority frames. Need to wait for some mailboxes + // to clear. + Poll::Pending + }) + .await + } + + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + pub async fn write_fd(&self, frame: &FdFrame) -> Option { + poll_fn(|cx| { + self.register(cx.waker()); + + if let Ok(dropped) = T::registers().write_fd(frame) { + return Poll::Ready(dropped); + } + + // Couldn't replace any lower priority frames. Need to wait for some mailboxes + // to clear. + Poll::Pending + }) + .await + } + } + pub struct State { - pub tx_waker: AtomicWaker, + pub rx_mode: RxMode, + pub tx_mode: TxMode, + pub ns_per_timer_tick: u64, + pub err_waker: AtomicWaker, - pub rx_waker: AtomicWaker, } impl State { pub const fn new() -> Self { Self { - tx_waker: AtomicWaker::new(), + rx_mode: RxMode::NonBuffered(AtomicWaker::new()), + tx_mode: TxMode::NonBuffered(AtomicWaker::new()), + ns_per_timer_tick: 0, err_waker: AtomicWaker::new(), - rx_waker: AtomicWaker::new(), } } } @@ -593,6 +599,8 @@ pub(crate) mod sealed { fn registers() -> crate::can::fd::peripheral::Registers; fn ram() -> &'static crate::pac::fdcanram::Fdcanram; fn state() -> &'static State; + unsafe fn mut_state() -> &'static mut State; + fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; #[cfg(not(stm32h7))] fn configure_msg_ram() {} @@ -694,10 +702,31 @@ macro_rules! impl_fdcan { fn ram() -> &'static crate::pac::fdcanram::Fdcanram { &crate::pac::$msg_ram_inst } - fn state() -> &'static sealed::State { - static STATE: sealed::State = sealed::State::new(); - &STATE + unsafe fn mut_state() -> & 'static mut sealed::State { + static mut STATE: sealed::State = sealed::State::new(); + & mut STATE } + fn state() -> &'static sealed::State { + unsafe { peripherals::$inst::mut_state() } + } + +#[cfg(feature = "time")] +fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + let now_embassy = embassy_time::Instant::now(); + if ns_per_timer_tick == 0 { + return now_embassy; + } + let cantime = { Self::regs().tscv().read().tsc() }; + let delta = cantime.overflowing_sub(ts_val).0 as u64; + let ns = ns_per_timer_tick * delta as u64; + now_embassy - embassy_time::Duration::from_nanos(ns) +} + +#[cfg(not(feature = "time"))] +fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + ts_val +} + } impl Instance for peripherals::$inst {} From 5ad291b708528b5772d6ebcc9309fbd3f8a002c8 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 17 Feb 2024 18:12:47 +1000 Subject: [PATCH 499/760] Add a buffered mode. --- embassy-stm32/src/can/fdcan.rs | 233 ++++++++++++++++++++++++++++++++ examples/stm32g4/src/bin/can.rs | 97 ++++++++++++- 2 files changed, 323 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 42ce73ded..3ae330e14 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -5,6 +5,8 @@ use core::task::Poll; pub mod fd; use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::channel::Channel; use fd::config::*; use fd::filter::*; @@ -49,6 +51,26 @@ impl interrupt::typelevel::Handler for IT0Interrup match &T::state().tx_mode { sealed::TxMode::NonBuffered(waker) => waker.wake(), + sealed::TxMode::ClassicBuffered(buf) => { + if !T::registers().tx_queue_is_full() { + match buf.tx_receiver.try_receive() { + Ok(frame) => { + _ = T::registers().write_classic(&frame); + } + Err(_) => {} + } + } + } + sealed::TxMode::FdBuffered(buf) => { + if !T::registers().tx_queue_is_full() { + match buf.tx_receiver.try_receive() { + Ok(frame) => { + _ = T::registers().write_fd(&frame); + } + Err(_) => {} + } + } + } } } @@ -405,6 +427,179 @@ where ) } + /// Return a buffered instance of driver without CAN FD support. User must supply Buffers + pub fn buffered( + &self, + tx_buf: &'static mut TxBuf, + rxb: &'static mut RxBuf, + ) -> BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> { + BufferedCan::new(PhantomData::, T::regs(), self._mode, tx_buf, rxb) + } + + /// Return a buffered instance of driver with CAN FD support. User must supply Buffers + pub fn buffered_fd( + &self, + tx_buf: &'static mut TxFdBuf, + rxb: &'static mut RxFdBuf, + ) -> BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> { + BufferedCanFd::new(PhantomData::, T::regs(), self._mode, tx_buf, rxb) + } +} + +/// User supplied buffer for RX Buffering +pub type RxBuf = Channel; + +/// User supplied buffer for TX buffering +pub type TxBuf = Channel; + +/// Buffered FDCAN Instance +#[allow(dead_code)] +pub struct BufferedCan<'d, T: Instance, M: FdcanOperatingMode, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { + _instance1: PhantomData, + _instance2: &'d crate::pac::can::Fdcan, + _mode: PhantomData, + tx_buf: &'static TxBuf, + rx_buf: &'static RxBuf, +} + +impl<'c, 'd, T: Instance, M: Transmit, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> + BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> +where + M: FdcanOperatingMode, +{ + fn new( + _instance1: PhantomData, + _instance2: &'d crate::pac::can::Fdcan, + _mode: PhantomData, + tx_buf: &'static TxBuf, + rx_buf: &'static RxBuf, + ) -> Self { + BufferedCan { + _instance1, + _instance2, + _mode, + tx_buf, + rx_buf, + } + .setup() + } + + fn setup(self) -> Self { + // We don't want interrupts being processed while we change modes. + critical_section::with(|_| unsafe { + let rx_inner = sealed::ClassicBufferedRxInner { + rx_sender: self.rx_buf.sender().into(), + }; + let tx_inner = sealed::ClassicBufferedTxInner { + tx_receiver: self.tx_buf.receiver().into(), + }; + T::mut_state().rx_mode = sealed::RxMode::ClassicBuffered(rx_inner); + T::mut_state().tx_mode = sealed::TxMode::ClassicBuffered(tx_inner); + }); + self + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: ClassicFrame) { + self.tx_buf.send(frame).await; + T::IT0Interrupt::pend(); // Wake for Tx + } + + /// Async read frame from RX buffer. + pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { + Ok(self.rx_buf.receive().await) + } +} + +impl<'c, 'd, T: Instance, M, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop + for BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> +where + M: FdcanOperatingMode, +{ + fn drop(&mut self) { + critical_section::with(|_| unsafe { + T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + }); + } +} + +/// User supplied buffer for RX Buffering +pub type RxFdBuf = Channel; + +/// User supplied buffer for TX buffering +pub type TxFdBuf = Channel; + +/// Buffered FDCAN Instance +#[allow(dead_code)] +pub struct BufferedCanFd<'d, T: Instance, M: FdcanOperatingMode, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { + _instance1: PhantomData, + _instance2: &'d crate::pac::can::Fdcan, + _mode: PhantomData, + tx_buf: &'static TxFdBuf, + rx_buf: &'static RxFdBuf, +} + +impl<'c, 'd, T: Instance, M: Transmit, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> + BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> +where + M: FdcanOperatingMode, +{ + fn new( + _instance1: PhantomData, + _instance2: &'d crate::pac::can::Fdcan, + _mode: PhantomData, + tx_buf: &'static TxFdBuf, + rx_buf: &'static RxFdBuf, + ) -> Self { + BufferedCanFd { + _instance1, + _instance2, + _mode, + tx_buf, + rx_buf, + } + .setup() + } + + fn setup(self) -> Self { + // We don't want interrupts being processed while we change modes. + critical_section::with(|_| unsafe { + let rx_inner = sealed::FdBufferedRxInner { + rx_sender: self.rx_buf.sender().into(), + }; + let tx_inner = sealed::FdBufferedTxInner { + tx_receiver: self.tx_buf.receiver().into(), + }; + T::mut_state().rx_mode = sealed::RxMode::FdBuffered(rx_inner); + T::mut_state().tx_mode = sealed::TxMode::FdBuffered(tx_inner); + }); + self + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: FdFrame) { + self.tx_buf.send(frame).await; + T::IT0Interrupt::pend(); // Wake for Tx + } + + /// Async read frame from RX buffer. + pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> { + Ok(self.rx_buf.receive().await) + } +} + +impl<'c, 'd, T: Instance, M, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop + for BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> +where + M: FdcanOperatingMode, +{ + fn drop(&mut self) { + critical_section::with(|_| unsafe { + T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + }); + } } /// FDCAN Rx only Instance @@ -456,18 +651,39 @@ pub(crate) mod sealed { use core::future::poll_fn; use core::task::Poll; + use embassy_sync::channel::{DynamicReceiver, DynamicSender}; use embassy_sync::waitqueue::AtomicWaker; use crate::can::_version::{BusError, Timestamp}; use crate::can::frame::{ClassicFrame, FdFrame}; + + pub struct ClassicBufferedRxInner { + pub rx_sender: DynamicSender<'static, (ClassicFrame, Timestamp)>, + } + pub struct ClassicBufferedTxInner { + pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, + } + + pub struct FdBufferedRxInner { + pub rx_sender: DynamicSender<'static, (FdFrame, Timestamp)>, + } + pub struct FdBufferedTxInner { + pub tx_receiver: DynamicReceiver<'static, FdFrame>, + } + pub enum RxMode { NonBuffered(AtomicWaker), + ClassicBuffered(ClassicBufferedRxInner), + FdBuffered(FdBufferedRxInner), } impl RxMode { pub fn register(&self, arg: &core::task::Waker) { match self { RxMode::NonBuffered(waker) => waker.register(arg), + _ => { + panic!("Bad Mode") + } } } @@ -477,6 +693,18 @@ pub(crate) mod sealed { RxMode::NonBuffered(waker) => { waker.wake(); } + RxMode::ClassicBuffered(buf) => { + if let Some(r) = T::registers().read_classic(fifonr) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); + let _ = buf.rx_sender.try_send((r.0, ts)); + } + } + RxMode::FdBuffered(buf) => { + if let Some(r) = T::registers().read_fd(fifonr) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); + let _ = buf.rx_sender.try_send((r.0, ts)); + } + } } } @@ -523,6 +751,8 @@ pub(crate) mod sealed { pub enum TxMode { NonBuffered(AtomicWaker), + ClassicBuffered(ClassicBufferedTxInner), + FdBuffered(FdBufferedTxInner), } impl TxMode { @@ -531,6 +761,9 @@ pub(crate) mod sealed { TxMode::NonBuffered(waker) => { waker.register(arg); } + _ => { + panic!("Bad mode"); + } } } diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 5ff4f0ef0..043ca7144 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -5,6 +5,7 @@ use embassy_executor::Spawner; use embassy_stm32::peripherals::*; use embassy_stm32::{bind_interrupts, can, Config}; use embassy_time::Timer; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -28,13 +29,17 @@ async fn main(_spawner: Spawner) { // 250k bps can.set_bitrate(250_000); + let use_fd = false; + // 1M bps - can.set_fd_data_bitrate(1_000_000, false); + if use_fd { + can.set_fd_data_bitrate(1_000_000, false); + } info!("Configured"); - //let mut can = can.into_normal_mode(); - let mut can = can.into_internal_loopback_mode(); + let mut can = can.into_normal_mode(); + //let mut can = can.into_internal_loopback_mode(); let mut i = 0; let mut last_read_ts = embassy_time::Instant::now(); @@ -68,11 +73,17 @@ async fn main(_spawner: Spawner) { } // Use the FD API's even if we don't get FD packets. - loop { - let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap(); - info!("Writing frame using FD API"); - _ = can.write_fd(&frame).await; + loop { + if use_fd { + let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap(); + info!("Writing frame using FD API"); + _ = can.write_fd(&frame).await; + } else { + let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame using FD API"); + _ = can.write_fd(&frame).await; + } match can.read_fd().await { Ok((rx_frame, ts)) => { @@ -96,6 +107,7 @@ async fn main(_spawner: Spawner) { } } + i = 0; let (mut tx, mut rx) = can.split(); // With split loop { @@ -120,5 +132,76 @@ async fn main(_spawner: Spawner) { Timer::after_millis(250).await; i += 1; + + if i > 2 { + break; + } + } + + let can = can::Fdcan::join(tx, rx); + + info!("\n\n\nBuffered\n"); + if use_fd { + static TX_BUF: StaticCell> = StaticCell::new(); + static RX_BUF: StaticCell> = StaticCell::new(); + let mut can = can.buffered_fd( + TX_BUF.init(can::TxFdBuf::<8>::new()), + RX_BUF.init(can::RxFdBuf::<10>::new()), + ); + loop { + let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap(); + info!("Writing frame"); + + _ = can.write(frame).await; + + match can.read().await { + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {} {:02x} --- {}ms", + rx_frame.header().len(), + rx_frame.data()[0..rx_frame.header().len() as usize], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + } + } else { + static TX_BUF: StaticCell> = StaticCell::new(); + static RX_BUF: StaticCell> = StaticCell::new(); + let mut can = can.buffered( + TX_BUF.init(can::TxBuf::<8>::new()), + RX_BUF.init(can::RxBuf::<10>::new()), + ); + loop { + let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + + _ = can.write(frame).await; + + match can.read().await { + Ok((rx_frame, ts)) => { + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {} {:02x} --- {}ms", + rx_frame.header().len(), + rx_frame.data()[0..rx_frame.header().len() as usize], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + } } } From 1aa999c2a825bdaf6fa4c980f47428d9b1d9263f Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 17 Feb 2024 12:52:20 +0200 Subject: [PATCH 500/760] nrf: Use .is_empty() instead of .len() == 0 --- embassy-nrf/src/pdm.rs | 2 +- embassy-nrf/src/qspi.rs | 8 ++++---- embassy-nrf/src/rng.rs | 2 +- embassy-nrf/src/twim.rs | 6 +++--- embassy-nrf/src/uarte.rs | 10 +++++----- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 6ddc4dc0a..754d38310 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -185,7 +185,7 @@ impl<'d, T: Instance> Pdm<'d, T> { /// Sample data into the given buffer pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { - if buffer.len() == 0 { + if buffer.is_empty() { return Err(Error::BufferZeroLength); } if buffer.len() > EASY_DMA_SIZE { diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 8eec09c96..4134a4c87 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -402,7 +402,7 @@ impl<'d, T: Instance> Qspi<'d, T> { /// a raw bus, not with flash memory. pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { // Avoid blocking_wait_ready() blocking forever on zero-length buffers. - if data.len() == 0 { + if data.is_empty() { return Ok(()); } @@ -423,7 +423,7 @@ impl<'d, T: Instance> Qspi<'d, T> { /// a raw bus, not with flash memory. pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { // Avoid blocking_wait_ready() blocking forever on zero-length buffers. - if data.len() == 0 { + if data.is_empty() { return Ok(()); } @@ -444,7 +444,7 @@ impl<'d, T: Instance> Qspi<'d, T> { /// a raw bus, not with flash memory. pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { // Avoid blocking_wait_ready() blocking forever on zero-length buffers. - if data.len() == 0 { + if data.is_empty() { return Ok(()); } @@ -460,7 +460,7 @@ impl<'d, T: Instance> Qspi<'d, T> { /// a raw bus, not with flash memory. pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { // Avoid blocking_wait_ready() blocking forever on zero-length buffers. - if data.len() == 0 { + if data.is_empty() { return Ok(()); } diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 40b73231b..1c463fb7c 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -108,7 +108,7 @@ impl<'d, T: Instance> Rng<'d, T> { /// Fill the buffer with random bytes. pub async fn fill_bytes(&mut self, dest: &mut [u8]) { - if dest.len() == 0 { + if dest.is_empty() { return; // Nothing to fill } diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index da8e15d02..83971463f 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -372,7 +372,7 @@ impl<'d, T: Instance> Twim<'d, T> { // Start write operation. r.shorts.write(|w| w.lasttx_stop().enabled()); r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - if buffer.len() == 0 { + if buffer.is_empty() { // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. r.tasks_stop.write(|w| unsafe { w.bits(1) }); } @@ -403,7 +403,7 @@ impl<'d, T: Instance> Twim<'d, T> { // Start read operation. r.shorts.write(|w| w.lastrx_stop().enabled()); r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - if buffer.len() == 0 { + if buffer.is_empty() { // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. r.tasks_stop.write(|w| unsafe { w.bits(1) }); } @@ -447,7 +447,7 @@ impl<'d, T: Instance> Twim<'d, T> { w }); r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - if wr_buffer.len() == 0 && rd_buffer.len() == 0 { + if wr_buffer.is_empty() && rd_buffer.is_empty() { // With a zero-length buffer, LASTRX/LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. // TODO handle when only one of the buffers is zero length r.tasks_stop.write(|w| unsafe { w.bits(1) }); diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index de2966ba5..3d486452f 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -386,7 +386,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { /// Same as [`write`](Self::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { - if buffer.len() == 0 { + if buffer.is_empty() { return Ok(()); } @@ -456,7 +456,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { /// Same as [`write_from_ram`](Self::write_from_ram) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { - if buffer.len() == 0 { + if buffer.is_empty() { return Ok(()); } @@ -694,7 +694,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { /// Read bytes until the buffer is filled. pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - if buffer.len() == 0 { + if buffer.is_empty() { return Ok(()); } if buffer.len() > EASY_DMA_SIZE { @@ -775,7 +775,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { /// /// Returns the amount of bytes read. pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result { - if buffer.len() == 0 { + if buffer.is_empty() { return Ok(0); } if buffer.len() > EASY_DMA_SIZE { @@ -848,7 +848,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { /// /// Returns the amount of bytes read. pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result { - if buffer.len() == 0 { + if buffer.is_empty() { return Ok(0); } if buffer.len() > EASY_DMA_SIZE { From bb2fb59a87d3aa1322cb13280287851d3ec39f59 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 17 Feb 2024 13:02:56 +0200 Subject: [PATCH 501/760] nrf: Remove useless borrows --- embassy-nrf/src/buffered_uarte.rs | 2 +- embassy-nrf/src/pwm.rs | 4 ++-- embassy-nrf/src/twim.rs | 4 ++-- embassy-nrf/src/twis.rs | 2 +- embassy-nrf/src/uarte.rs | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 2c620798d..fb72422bd 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -377,7 +377,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { }); // Enable UARTE instance - apply_workaround_for_enable_anomaly(&r); + apply_workaround_for_enable_anomaly(r); r.enable.write(|w| w.enable().enabled()); // Configure byte counter. diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index e0583b770..bfcff60a1 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -697,7 +697,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { // Enable r.enable.write(|w| w.enable().enabled()); - r.seq0.ptr.write(|w| unsafe { w.bits((&pwm.duty).as_ptr() as u32) }); + r.seq0.ptr.write(|w| unsafe { w.bits((pwm.duty).as_ptr() as u32) }); r.seq0.cnt.write(|w| unsafe { w.bits(4) }); r.seq0.refresh.write(|w| unsafe { w.bits(0) }); @@ -748,7 +748,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { self.duty[channel] = duty & 0x7FFF; // reload ptr in case self was moved - r.seq0.ptr.write(|w| unsafe { w.bits((&self.duty).as_ptr() as u32) }); + r.seq0.ptr.write(|w| unsafe { w.bits((self.duty).as_ptr() as u32) }); // defensive before seqstart compiler_fence(Ordering::SeqCst); diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 83971463f..30699283f 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -469,7 +469,7 @@ impl<'d, T: Instance> Twim<'d, T> { trace!("Copying TWIM tx buffer into RAM for DMA"); let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; tx_ram_buf.copy_from_slice(wr_buffer); - self.setup_write_read_from_ram(address, &tx_ram_buf, rd_buffer, inten) + self.setup_write_read_from_ram(address, tx_ram_buf, rd_buffer, inten) } Err(error) => Err(error), } @@ -482,7 +482,7 @@ impl<'d, T: Instance> Twim<'d, T> { trace!("Copying TWIM tx buffer into RAM for DMA"); let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; tx_ram_buf.copy_from_slice(wr_buffer); - self.setup_write_from_ram(address, &tx_ram_buf, inten) + self.setup_write_from_ram(address, tx_ram_buf, inten) } Err(error) => Err(error), } diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index c6c020557..415150447 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -577,7 +577,7 @@ impl<'d, T: Instance> Twis<'d, T> { trace!("Copying TWIS tx buffer into RAM for DMA"); let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; tx_ram_buf.copy_from_slice(wr_buffer); - self.setup_respond_from_ram(&tx_ram_buf, inten) + self.setup_respond_from_ram(tx_ram_buf, inten) } Err(error) => Err(error), } diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 3d486452f..67b3feae7 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -308,7 +308,7 @@ fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) { r.events_txstarted.reset(); // Enable - apply_workaround_for_enable_anomaly(&r); + apply_workaround_for_enable_anomaly(r); r.enable.write(|w| w.enable().enabled()); } @@ -378,7 +378,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { trace!("Copying UARTE tx buffer into RAM for DMA"); let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; ram_buf.copy_from_slice(buffer); - self.write_from_ram(&ram_buf).await + self.write_from_ram(ram_buf).await } Err(error) => Err(error), } @@ -448,7 +448,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { trace!("Copying UARTE tx buffer into RAM for DMA"); let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; ram_buf.copy_from_slice(buffer); - self.blocking_write_from_ram(&ram_buf) + self.blocking_write_from_ram(ram_buf) } Err(error) => Err(error), } @@ -504,7 +504,7 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> { let s = T::state(); - drop_tx_rx(&r, &s); + drop_tx_rx(r, s); } } @@ -744,7 +744,7 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> { let s = T::state(); - drop_tx_rx(&r, &s); + drop_tx_rx(r, s); } } From a8710e943d620f3da878821ec74d44bfae0f9fb2 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 17 Feb 2024 13:08:53 +0200 Subject: [PATCH 502/760] nrf: Drop needless let --- embassy-nrf/src/pwm.rs | 4 ++-- embassy-nrf/src/qdec.rs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index bfcff60a1..833370d4b 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -444,7 +444,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { return Err(Error::SequenceTimesAtLeastOne); } - let _ = self.stop(); + self.stop(); let r = T::regs(); @@ -507,7 +507,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { impl<'d, 's, T: Instance> Drop for Sequencer<'d, 's, T> { fn drop(&mut self) { - let _ = self.stop(); + self.stop(); } } diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs index 2aa50a2ba..932790d4f 100644 --- a/embassy-nrf/src/qdec.rs +++ b/embassy-nrf/src/qdec.rs @@ -172,7 +172,7 @@ impl<'d, T: Instance> Qdec<'d, T> { t.intenset.write(|w| w.reportrdy().set()); unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; - let value = poll_fn(|cx| { + poll_fn(|cx| { T::state().waker.register(cx.waker()); if t.events_reportrdy.read().bits() == 0 { return Poll::Pending; @@ -182,8 +182,7 @@ impl<'d, T: Instance> Qdec<'d, T> { Poll::Ready(acc as i16) } }) - .await; - value + .await } } From 580ab484515d8a75f514bd34a5041090ffd9248c Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 17 Feb 2024 13:18:36 +0200 Subject: [PATCH 503/760] nrf: More nits cleaned up - useless cast and struct item --- embassy-nrf/src/nvmc.rs | 2 +- embassy-nrf/src/uarte.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs index de840b886..4f9eda167 100644 --- a/embassy-nrf/src/nvmc.rs +++ b/embassy-nrf/src/nvmc.rs @@ -160,7 +160,7 @@ impl<'d> NorFlash for Nvmc<'d> { if offset as usize + bytes.len() > FLASH_SIZE { return Err(Error::OutOfBounds); } - if offset as usize % 4 != 0 || bytes.len() as usize % 4 != 0 { + if offset as usize % 4 != 0 || bytes.len() % 4 != 0 { return Err(Error::Unaligned); } diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 67b3feae7..9e5b85dea 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -619,7 +619,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { UarteRxWithIdle { rx: self, timer, - ppi_ch1: ppi_ch1, + ppi_ch1, _ppi_ch2: ppi_ch2, } } From 7f2f701c87fbbced32c5586bc7b9a3b61ad25c8d Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 17 Feb 2024 13:20:25 +0200 Subject: [PATCH 504/760] nrf: Remove useless returns --- embassy-nrf/src/qdec.rs | 2 +- embassy-nrf/src/temp.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs index 932790d4f..9455ec925 100644 --- a/embassy-nrf/src/qdec.rs +++ b/embassy-nrf/src/qdec.rs @@ -175,7 +175,7 @@ impl<'d, T: Instance> Qdec<'d, T> { poll_fn(|cx| { T::state().waker.register(cx.waker()); if t.events_reportrdy.read().bits() == 0 { - return Poll::Pending; + Poll::Pending } else { t.events_reportrdy.reset(); let acc = t.accread.read().bits(); diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index 5e2998b10..ed4a47713 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -83,7 +83,7 @@ impl<'d> Temp<'d> { let value = poll_fn(|cx| { WAKER.register(cx.waker()); if t.events_datardy.read().bits() == 0 { - return Poll::Pending; + Poll::Pending } else { t.events_datardy.reset(); let raw = t.temp.read().bits(); From 8507b0ad30d8b801545046e8789aea4f68ec3f22 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 17 Feb 2024 13:24:10 +0200 Subject: [PATCH 505/760] nrf: Remove useless lifetimes --- embassy-nrf/src/twim.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 30699283f..24810a08c 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -779,7 +779,7 @@ mod eh02 { impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Write for Twim<'a, T> { type Error = Error; - fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> { + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { if slice_in_ram(bytes) { self.blocking_write(addr, bytes) } else { @@ -796,7 +796,7 @@ mod eh02 { impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Read for Twim<'a, T> { type Error = Error; - fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> { + fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> { self.blocking_read(addr, bytes) } } @@ -847,10 +847,10 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { self.blocking_write_read(address, wr_buffer, rd_buffer) } - fn transaction<'a>( + fn transaction( &mut self, _address: u8, - _operations: &mut [embedded_hal_1::i2c::Operation<'a>], + _operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { todo!(); } From 6734f52676a9669586492f6c203c10f354f6cf04 Mon Sep 17 00:00:00 2001 From: Andelf Date: Sat, 17 Feb 2024 20:44:59 +0800 Subject: [PATCH 506/760] rp/gpio: fix wrong io _bank calc --- embassy-rp/src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index a121a8036..62eeb4cf6 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -815,7 +815,7 @@ pub(crate) mod sealed { #[inline] fn _bank(&self) -> Bank { - match self.pin_bank() & 0x20 { + match self.pin_bank() >> 5 { #[cfg(feature = "qspi-as-gpio")] 1 => Bank::Qspi, _ => Bank::Bank0, From dd9f0d9d9e73feffce371ab7fda714b09b268715 Mon Sep 17 00:00:00 2001 From: Zach Date: Sat, 17 Feb 2024 12:04:53 -0600 Subject: [PATCH 507/760] support u5 flash --- embassy-stm32/src/flash/mod.rs | 3 +- embassy-stm32/src/flash/u5.rs | 105 ++++++++++++++++++++++++++++++ examples/stm32u5/src/bin/flash.rs | 55 ++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 embassy-stm32/src/flash/u5.rs create mode 100644 examples/stm32u5/src/bin/flash.rs diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 47232f4a4..4f43a7a48 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -101,10 +101,11 @@ pub enum FlashBank { #[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")] #[cfg_attr(flash_h7, path = "h7.rs")] #[cfg_attr(flash_h7ab, path = "h7.rs")] +#[cfg_attr(flash_u5, path = "u5.rs")] #[cfg_attr( not(any( flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, - flash_g4, flash_h7, flash_h7ab + flash_g4, flash_h7, flash_h7ab, flash_u5 )), path = "other.rs" )] diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs new file mode 100644 index 000000000..3787082f9 --- /dev/null +++ b/embassy-stm32/src/flash/u5.rs @@ -0,0 +1,105 @@ +use core::convert::TryInto; +use core::ptr::write_volatile; +use core::sync::atomic::{fence, Ordering}; + +use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use crate::flash::Error; +use crate::pac; + +pub(crate) const fn is_default_layout() -> bool { + true +} + +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + +pub(crate) unsafe fn lock() { + pac::FLASH.seccr().modify(|w| w.set_lock(true)); +} + +pub(crate) unsafe fn unlock() { + if pac::FLASH.seccr().read().lock() { + pac::FLASH.seckeyr().write_value(0x4567_0123); + pac::FLASH.seckeyr().write_value(0xCDEF_89AB); + } +} + +pub(crate) unsafe fn enable_blocking_write() { + assert_eq!(0, WRITE_SIZE % 4); + + pac::FLASH.seccr().write(|w| { + w.set_pg(pac::flash::vals::SeccrPg::B_0X1); + }); +} + +pub(crate) unsafe fn disable_blocking_write() { + pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0)); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); + } + + blocking_wait_ready() +} + +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + pac::FLASH.seccr().modify(|w| { + w.set_per(pac::flash::vals::SeccrPer::B_0X1); + w.set_pnb(sector.index_in_bank) + }); + + pac::FLASH.seccr().modify(|w| { + w.set_strt(true); + }); + + let ret: Result<(), Error> = blocking_wait_ready(); + pac::FLASH + .seccr() + .modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0)); + clear_all_err(); + ret +} + +pub(crate) unsafe fn clear_all_err() { + // read and write back the same value. + // This clears all "write 1 to clear" bits. + pac::FLASH.secsr().modify(|_| {}); +} + +unsafe fn blocking_wait_ready() -> Result<(), Error> { + loop { + let sr = pac::FLASH.secsr().read(); + + if !sr.bsy() { + if sr.pgserr() { + return Err(Error::Seq); + } + + if sr.sizerr() { + return Err(Error::Size); + } + + if sr.pgaerr() { + return Err(Error::Unaligned); + } + + if sr.wrperr() { + return Err(Error::Protected); + } + + if sr.progerr() { + return Err(Error::Prog); + } + + return Ok(()); + } + } +} diff --git a/examples/stm32u5/src/bin/flash.rs b/examples/stm32u5/src/bin/flash.rs new file mode 100644 index 000000000..e4fd6bb9c --- /dev/null +++ b/examples/stm32u5/src/bin/flash.rs @@ -0,0 +1,55 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_stm32::flash::Flash; +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 Flash!"); + + const ADDR: u32 = 0x8_0000; // This is the offset into the third region, the absolute address is 4x32K + 128K + 0x8_0000. + + // wait a bit before accessing the flash + Timer::after_millis(300).await; + + let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.blocking_read(ADDR, &mut buf)); + info!("Read: {=[u8]:x}", buf); + + info!("Erasing..."); + unwrap!(f.blocking_erase(ADDR, ADDR + 256 * 1024)); + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.blocking_read(ADDR, &mut buf)); + info!("Read after erase: {=[u8]:x}", buf); + + info!("Writing..."); + unwrap!(f.blocking_write( + ADDR, + &[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32 + ] + )); + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.blocking_read(ADDR, &mut buf)); + info!("Read: {=[u8]:x}", buf); + assert_eq!( + &buf[..], + &[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32 + ] + ); +} From f9e7fc6e5e3a8c50fb425735a48e65040185413b Mon Sep 17 00:00:00 2001 From: Zach Date: Sat, 17 Feb 2024 14:00:03 -0600 Subject: [PATCH 508/760] u5 - add working rng example --- examples/stm32u5/src/bin/rng.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 examples/stm32u5/src/bin/rng.rs diff --git a/examples/stm32u5/src/bin/rng.rs b/examples/stm32u5/src/bin/rng.rs new file mode 100644 index 000000000..3a5bce097 --- /dev/null +++ b/examples/stm32u5/src/bin/rng.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, peripherals, rng}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RNG => rng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + info!("Hello World!"); + + let mut rng = Rng::new(p.RNG, Irqs); + + let mut buf = [0u8; 16]; + unwrap!(rng.async_fill_bytes(&mut buf).await); + info!("random bytes: {:02x}", buf); +} From eafa90cd0707298f354d5d1e496f8364117bd781 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 18 Feb 2024 13:09:37 +1000 Subject: [PATCH 509/760] Remove the OperatingMode typestates Instead have two explcit types(without the mode generic arg)types: - One for config - One for all operating modes --- embassy-stm32/src/can/fd/peripheral.rs | 13 ++ embassy-stm32/src/can/fdcan.rs | 265 +++++++++++-------------- examples/stm32g4/src/bin/can.rs | 9 +- examples/stm32h5/src/bin/can.rs | 3 +- examples/stm32h7/src/bin/can.rs | 3 +- tests/stm32/src/bin/fdcan.rs | 2 +- 6 files changed, 133 insertions(+), 162 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 487b8f413..0771d6fbb 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -481,6 +481,19 @@ impl Registers { while self.regs.cccr().read().init() == true {} } + /// Moves out of ConfigMode and into specified mode + #[inline] + pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) { + match mode { + crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), + crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), + crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true), + crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), + crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), + } + self.leave_init_mode(config); + } + /// Moves out of ConfigMode and into InternalLoopbackMode #[inline] pub fn into_internal_loopback(mut self, config: FdCanConfig) { diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 3ae330e14..f1f6f935e 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -100,75 +100,50 @@ impl interrupt::typelevel::Handler for IT1Interrup unsafe fn on_interrupt() {} } -/// Allows for Transmit Operations -pub trait Transmit {} -/// Allows for Receive Operations -pub trait Receive {} - -/// Allows for the FdCan Instance to be released or to enter ConfigMode -pub struct PoweredDownMode; -/// Allows for the configuration for the Instance -pub struct ConfigMode; -/// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without -/// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this -/// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held -/// recessive. -pub struct InternalLoopbackMode; -impl Transmit for InternalLoopbackMode {} -impl Receive for InternalLoopbackMode {} -/// This mode is provided for hardware self-test. To be independent from external stimulation, -/// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a -/// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal -/// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX -/// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the -/// FDCAN_TX transmit pin. -pub struct ExternalLoopbackMode; -impl Transmit for ExternalLoopbackMode {} -impl Receive for ExternalLoopbackMode {} -/// The normal use of the FdCan instance after configurations -pub struct NormalOperationMode; -impl Transmit for NormalOperationMode {} -impl Receive for NormalOperationMode {} -/// In Restricted operation mode the node is able to receive data and remote frames and to give -/// acknowledge to valid frames, but it does not send data frames, remote frames, active error -/// frames, or overload frames. In case of an error condition or overload condition, it does not -/// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize -/// itself to the CAN communication. The error counters for transmit and receive are frozen while -/// error logging (can_errors) is active. TODO: automatically enter in this mode? -pub struct RestrictedOperationMode; -impl Receive for RestrictedOperationMode {} -/// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring), -/// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a -/// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is -/// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is -/// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive -/// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring -/// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission -/// of dominant bits. -pub struct BusMonitoringMode; -impl Receive for BusMonitoringMode {} -/// Test mode must be used for production tests or self test only. The software control for -/// FDCAN_TX pin interferes with all CAN protocol functions. It is not recommended to use test -/// modes for application. -pub struct TestMode; - -/// Operating modes trait -pub trait FdcanOperatingMode {} -impl FdcanOperatingMode for PoweredDownMode {} -impl FdcanOperatingMode for ConfigMode {} -impl FdcanOperatingMode for InternalLoopbackMode {} -impl FdcanOperatingMode for ExternalLoopbackMode {} -impl FdcanOperatingMode for NormalOperationMode {} -impl FdcanOperatingMode for RestrictedOperationMode {} -impl FdcanOperatingMode for BusMonitoringMode {} -impl FdcanOperatingMode for TestMode {} +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Different operating modes +pub enum FdcanOperatingMode { + //PoweredDownMode, + //ConfigMode, + /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without + /// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this + /// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held + /// recessive. + InternalLoopbackMode, + /// This mode is provided for hardware self-test. To be independent from external stimulation, + /// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a + /// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal + /// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX + /// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the + /// FDCAN_TX transmit pin. + ExternalLoopbackMode, + /// The normal use of the Fdcan instance after configurations + NormalOperationMode, + /// In Restricted operation mode the node is able to receive data and remote frames and to give + /// acknowledge to valid frames, but it does not send data frames, remote frames, active error + /// frames, or overload frames. In case of an error condition or overload condition, it does not + /// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize + /// itself to the CAN communication. The error counters for transmit and receive are frozen while + /// error logging (can_errors) is active. TODO: automatically enter in this mode? + RestrictedOperationMode, + /// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring), + /// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a + /// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is + /// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is + /// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive + /// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring + /// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission + /// of dominant bits. + BusMonitoringMode, + //TestMode, +} /// FDCAN Instance -pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { +pub struct FdcanConfigurator<'d, T: Instance> { config: crate::can::fd::config::FdCanConfig, /// Reference to internals. instance: FdcanInstance<'d, T>, - _mode: PhantomData, } fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { @@ -186,7 +161,7 @@ fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransm } } -impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { +impl<'d, T: Instance> FdcanConfigurator<'d, T> { /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. /// You must call [Fdcan::enable_non_blocking] to use the peripheral. pub fn new( @@ -196,7 +171,7 @@ impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { _irqs: impl interrupt::typelevel::Binding> + interrupt::typelevel::Binding> + 'd, - ) -> Fdcan<'d, T, ConfigMode> { + ) -> FdcanConfigurator<'d, T> { into_ref!(peri, rx, tx); rx.set_as_af(rx.af_num(), AFType::Input); @@ -245,7 +220,6 @@ impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { Self { config, instance: FdcanInstance(peri), - _mode: PhantomData::, } } @@ -272,7 +246,7 @@ impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { self.config = self.config.set_nominal_bit_timing(nbtr); } - /// Configures the bit timings for VBR data calculated from supplied bitrate. + /// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) { let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M @@ -312,51 +286,47 @@ impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { T::registers().msg_ram_mut().filters.flesa[i].activate(*f); } } + + /// Start in mode. + pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> { + let ns_per_timer_tick = calc_ns_per_timer_tick::(self.config.frame_transmit); + critical_section::with(|_| unsafe { + T::mut_state().ns_per_timer_tick = ns_per_timer_tick; + }); + T::registers().into_mode(self.config, mode); + let ret = Fdcan { + config: self.config, + instance: self.instance, + _mode: mode, + }; + ret + } + + /// Start, entering mode. Does same as start(mode) + pub fn into_normal_mode(self) -> Fdcan<'d, T> { + self.start(FdcanOperatingMode::NormalOperationMode) + } + + /// Start, entering mode. Does same as start(mode) + pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> { + self.start(FdcanOperatingMode::InternalLoopbackMode) + } + + /// Start, entering mode. Does same as start(mode) + pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> { + self.start(FdcanOperatingMode::ExternalLoopbackMode) + } } -macro_rules! impl_transition { - ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => { - impl<'d, T: Instance> Fdcan<'d, T, $from_mode> { - /// Transition from $from_mode:ident mode to $to_mode:ident mode - pub fn $name(self) -> Fdcan<'d, T, $to_mode> { - let ns_per_timer_tick = calc_ns_per_timer_tick::(self.config.frame_transmit); - critical_section::with(|_| unsafe { - T::mut_state().ns_per_timer_tick = ns_per_timer_tick; - }); - T::registers().$func(self.config); - let ret = Fdcan { - config: self.config, - instance: self.instance, - _mode: PhantomData::<$to_mode>, - }; - ret - } - } - }; +/// FDCAN Instance +pub struct Fdcan<'d, T: Instance> { + config: crate::can::fd::config::FdCanConfig, + /// Reference to internals. + instance: FdcanInstance<'d, T>, + _mode: FdcanOperatingMode, } -impl_transition!(PoweredDownMode, ConfigMode, into_config_mode, into_config_mode); -impl_transition!(InternalLoopbackMode, ConfigMode, into_config_mode, into_config_mode); - -impl_transition!(ConfigMode, NormalOperationMode, into_normal_mode, into_normal); -impl_transition!( - ConfigMode, - ExternalLoopbackMode, - into_external_loopback_mode, - into_external_loopback -); -impl_transition!( - ConfigMode, - InternalLoopbackMode, - into_internal_loopback_mode, - into_internal_loopback -); - -impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M> -where - M: Transmit, - M: Receive, -{ +impl<'d, T: Instance> Fdcan<'d, T> { /// Flush one of the TX mailboxes. pub async fn flush(&self, idx: usize) { poll_fn(|cx| { @@ -401,18 +371,8 @@ where T::state().rx_mode.read_fd::().await } - /// Join split rx and tx portions back together - pub fn join(tx: FdcanTx<'d, T, M>, rx: FdcanRx<'d, T, M>) -> Self { - Fdcan { - config: tx.config, - //_instance2: T::regs(), - instance: tx._instance, - _mode: rx._mode, - } - } - /// Split instance into separate Tx(write) and Rx(read) portions - pub fn split(self) -> (FdcanTx<'d, T, M>, FdcanRx<'d, T, M>) { + pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) { ( FdcanTx { config: self.config, @@ -427,12 +387,22 @@ where ) } + /// Join split rx and tx portions back together + pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self { + Fdcan { + config: tx.config, + //_instance2: T::regs(), + instance: tx._instance, + _mode: rx._mode, + } + } + /// Return a buffered instance of driver without CAN FD support. User must supply Buffers pub fn buffered( &self, tx_buf: &'static mut TxBuf, rxb: &'static mut RxBuf, - ) -> BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> { + ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { BufferedCan::new(PhantomData::, T::regs(), self._mode, tx_buf, rxb) } @@ -441,7 +411,7 @@ where &self, tx_buf: &'static mut TxFdBuf, rxb: &'static mut RxFdBuf, - ) -> BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> { + ) -> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { BufferedCanFd::new(PhantomData::, T::regs(), self._mode, tx_buf, rxb) } } @@ -453,24 +423,21 @@ pub type RxBuf = Channel = Channel; /// Buffered FDCAN Instance -#[allow(dead_code)] -pub struct BufferedCan<'d, T: Instance, M: FdcanOperatingMode, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { +pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: PhantomData, + _mode: FdcanOperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, } -impl<'c, 'd, T: Instance, M: Transmit, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> - BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> -where - M: FdcanOperatingMode, +impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> + BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { fn new( _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: PhantomData, + _mode: FdcanOperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, ) -> Self { @@ -511,10 +478,8 @@ where } } -impl<'c, 'd, T: Instance, M, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop - for BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> -where - M: FdcanOperatingMode, +impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop + for BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { fn drop(&mut self) { critical_section::with(|_| unsafe { @@ -531,24 +496,21 @@ pub type RxFdBuf = Channel = Channel; /// Buffered FDCAN Instance -#[allow(dead_code)] -pub struct BufferedCanFd<'d, T: Instance, M: FdcanOperatingMode, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { +pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: PhantomData, + _mode: FdcanOperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, } -impl<'c, 'd, T: Instance, M: Transmit, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> - BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> -where - M: FdcanOperatingMode, +impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> + BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { fn new( _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: PhantomData, + _mode: FdcanOperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, ) -> Self { @@ -589,10 +551,8 @@ where } } -impl<'c, 'd, T: Instance, M, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop - for BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> -where - M: FdcanOperatingMode, +impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop + for BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { fn drop(&mut self) { critical_section::with(|_| unsafe { @@ -603,21 +563,20 @@ where } /// FDCAN Rx only Instance -#[allow(dead_code)] -pub struct FdcanRx<'d, T: Instance, M: Receive> { +pub struct FdcanRx<'d, T: Instance> { _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: PhantomData, + _mode: FdcanOperatingMode, } /// FDCAN Tx only Instance -pub struct FdcanTx<'d, T: Instance, M: Transmit> { +pub struct FdcanTx<'d, T: Instance> { config: crate::can::fd::config::FdCanConfig, _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); - _mode: PhantomData, + _mode: FdcanOperatingMode, } -impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> { +impl<'c, 'd, T: Instance> FdcanTx<'d, T> { /// Queues the message to be sent but exerts backpressure. If a lower-priority /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully @@ -635,7 +594,7 @@ impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> { } } -impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> { +impl<'c, 'd, T: Instance> FdcanRx<'d, T> { /// Returns the next received message frame pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { T::state().rx_mode.read::().await diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 043ca7144..affa97039 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -19,7 +19,7 @@ async fn main(_spawner: Spawner) { let peripherals = embassy_stm32::init(config); - let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); can.set_extended_filter( can::fd::filter::ExtendedFilterSlot::_0, @@ -38,8 +38,10 @@ async fn main(_spawner: Spawner) { info!("Configured"); - let mut can = can.into_normal_mode(); - //let mut can = can.into_internal_loopback_mode(); + let mut can = can.start(match use_fd { + true => can::FdcanOperatingMode::InternalLoopbackMode, + false => can::FdcanOperatingMode::NormalOperationMode, + }); let mut i = 0; let mut last_read_ts = embassy_time::Instant::now(); @@ -106,7 +108,6 @@ async fn main(_spawner: Spawner) { break; } } - i = 0; let (mut tx, mut rx) = can.split(); // With split diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index 4b29a0d21..e5ccfe4f7 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -24,8 +24,7 @@ async fn main(_spawner: Spawner) { let peripherals = embassy_stm32::init(config); - //let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); - let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); // 250k bps can.set_bitrate(250_000); diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 4b29a0d21..e5ccfe4f7 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -24,8 +24,7 @@ async fn main(_spawner: Spawner) { let peripherals = embassy_stm32::init(config); - //let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); - let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); // 250k bps can.set_bitrate(250_000); diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index 76c27d091..398e31ffc 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -75,7 +75,7 @@ async fn main(_spawner: Spawner) { let options = options(); let peripherals = embassy_stm32::init(options.config); - let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); + let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); // 250k bps can.set_bitrate(250_000); From 20cd7d09f429be84481a314f6eb174bcfb82612a Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 18 Feb 2024 17:01:09 +0000 Subject: [PATCH 510/760] time: cloneable delay --- embassy-time/src/delay.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-time/src/delay.rs b/embassy-time/src/delay.rs index 7ef5961f0..f77859d4a 100644 --- a/embassy-time/src/delay.rs +++ b/embassy-time/src/delay.rs @@ -13,6 +13,7 @@ pub fn block_for(duration: Duration) { /// the amount provided, but accuracy can be affected by many factors, including interrupt usage. /// Make sure to use a suitable tick rate for your use case. The tick rate is defined by the currently /// active driver. +#[derive(Clone)] pub struct Delay; impl embedded_hal_1::delay::DelayNs for Delay { From f12bba8a6db167582b072b007927b1a9920e86ba Mon Sep 17 00:00:00 2001 From: Zach Date: Sun, 18 Feb 2024 16:23:01 -0600 Subject: [PATCH 511/760] Add simple i2c example for u5 --- examples/stm32u5/src/bin/i2c.rs | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 examples/stm32u5/src/bin/i2c.rs diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs new file mode 100644 index 000000000..e376c6bc8 --- /dev/null +++ b/examples/stm32u5/src/bin/i2c.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_stm32::dma::NoDma; +use embassy_stm32::i2c::I2c; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; +use {defmt_rtt as _, panic_probe as _}; + +const HTS221_ADDRESS: u8 = 0x5F; +const WHOAMI: u8 = 0x0F; + +bind_interrupts!(struct Irqs { + I2C2_EV => i2c::EventInterruptHandler; + I2C2_ER => i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + let mut i2c = I2c::new( + p.I2C2, + p.PH4, + p.PH5, + Irqs, + NoDma, + NoDma, + Hertz(100_000), + Default::default(), + ); + + let mut data = [0u8; 1]; + unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); + + // HTS221 data sheet is here: https://www.st.com/resource/en/datasheet/hts221.pdf + // 7.1 WHO_AM_I command is x0F which expected response xBC. + info!("Whoami: 0x{:02x}", data[0]); + assert_eq!(0xBC, data[0]); +} From 3f93105e9fe7c5cbdada46a4367b01448fd61c62 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Mon, 19 Feb 2024 08:33:19 +1000 Subject: [PATCH 512/760] Add dep for static_cell to example. --- examples/stm32g4/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index fdb325f06..74ccfa3b0 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -24,6 +24,7 @@ embedded-can = { version = "0.4" } 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 } +static_cell = "2.0.0" [profile.release] debug = 2 From 6ecac3bc950212eba68d579c83ce5b52a17b8806 Mon Sep 17 00:00:00 2001 From: NBonaparte Date: Thu, 15 Feb 2024 22:33:23 -0800 Subject: [PATCH 513/760] feat(nrf/spim): allow specifying drive of SPI pins --- embassy-nrf/src/spim.rs | 42 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 8937159df..0de35490b 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -50,6 +50,15 @@ pub struct Config { /// When doing bidirectional transfers, if the TX buffer is shorter than the RX buffer, /// this byte will be transmitted in the MOSI line for the left-over bytes. pub orc: u8, + + /// Enable high drive for the SCK line. + pub sck_high_drive: bool, + + /// Enable high drive for the MOSI line. + pub mosi_high_drive: bool, + + /// Enable high drive for the MISO line. + pub miso_high_drive: bool, } impl Default for Config { @@ -59,6 +68,9 @@ impl Default for Config { mode: MODE_0, bit_order: BitOrder::MSB_FIRST, orc: 0x00, + sck_high_drive: false, + mosi_high_drive: false, + miso_high_drive: false, } } } @@ -159,13 +171,37 @@ impl<'d, T: Instance> Spim<'d, T> { // Configure pins if let Some(sck) = &sck { - sck.conf().write(|w| w.dir().output().drive().h0h1()); + sck.conf().write(|w| { + w.dir().output(); + if config.sck_high_drive { + w.drive().h0h1(); + } else { + w.drive().s0s1(); + } + w + }); } if let Some(mosi) = &mosi { - mosi.conf().write(|w| w.dir().output().drive().h0h1()); + mosi.conf().write(|w| { + w.dir().output(); + if config.mosi_high_drive { + w.drive().h0h1(); + } else { + w.drive().s0s1(); + } + w + }); } if let Some(miso) = &miso { - miso.conf().write(|w| w.input().connect().drive().h0h1()); + miso.conf().write(|w| { + w.input().connect(); + if config.miso_high_drive { + w.drive().h0h1(); + } else { + w.drive().s0s1(); + } + w + }); } match config.mode.polarity { From 5b7e2d88265b5633fa53047961598fbc38bffed0 Mon Sep 17 00:00:00 2001 From: fe1es <157477981+fe1es@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:25:24 +0900 Subject: [PATCH 514/760] stm32/rcc: reset RTC on stm32l0 --- embassy-stm32/src/rcc/bd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index d20f58185..d381ec1bd 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -206,7 +206,7 @@ impl LsConfig { bdcr().modify(|w| w.set_vswrst(true)); bdcr().modify(|w| w.set_vswrst(false)); } - #[cfg(any(stm32c0))] + #[cfg(any(stm32c0, stm32l0))] { bdcr().modify(|w| w.set_rtcrst(true)); bdcr().modify(|w| w.set_rtcrst(false)); From 67230dc4443d82aac14b590ba873fa647e5fc548 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Mon, 19 Feb 2024 15:49:43 +0000 Subject: [PATCH 515/760] flash: h50: first pass at implementation --- embassy-stm32/src/flash/h50.rs | 124 +++++++++++++++++++++++++++++++++ embassy-stm32/src/flash/mod.rs | 3 +- 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 embassy-stm32/src/flash/h50.rs diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs new file mode 100644 index 000000000..db05bef5d --- /dev/null +++ b/embassy-stm32/src/flash/h50.rs @@ -0,0 +1,124 @@ +/// STM32H50 series flash impl. See RM0492 +use core::{ + ptr::write_volatile, + sync::atomic::{fence, Ordering}, +}; + +use cortex_m::interrupt; +use pac::flash::regs::Nssr; +use pac::flash::vals::Bksel; + +use super::{Error, FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use crate::pac; + +pub(crate) const fn is_default_layout() -> bool { + true +} + +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + +pub(crate) unsafe fn lock() { + pac::FLASH.nscr().modify(|w| w.set_lock(true)); +} + +pub(crate) unsafe fn unlock() { + while busy() {} + + if pac::FLASH.nscr().read().lock() { + pac::FLASH.nskeyr().write_value(0x4567_0123); + pac::FLASH.nskeyr().write_value(0xCDEF_89AB); + } +} + +pub(crate) unsafe fn enable_blocking_write() { + assert_eq!(0, WRITE_SIZE % 4); + pac::FLASH.nscr().write(|w| w.set_pg(true)); +} + +pub(crate) unsafe fn disable_blocking_write() { + pac::FLASH.nscr().write(|w| w.set_pg(false)); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); + } + + wait_ready_blocking() +} + +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + assert!(sector.bank != FlashBank::Otp); + assert!(sector.index_in_bank < 8); + + while busy() {} + + interrupt::free(|_| { + pac::FLASH.nscr().modify(|w| { + w.set_bksel(match sector.bank { + FlashBank::Bank1 => Bksel::B_0X0, + FlashBank::Bank2 => Bksel::B_0X1, + _ => unreachable!(), + }); + w.set_snb(sector.index_in_bank); + w.set_ser(true); + w.set_strt(true); + }) + }); + + let ret = wait_ready_blocking(); + pac::FLASH.nscr().modify(|w| w.set_ser(false)); + ret +} + +pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { + loop { + let sr = pac::FLASH.nssr().read(); + + if !sr_busy(sr) { + if sr.wrperr() { + return Err(Error::Protected); + } + if sr.pgserr() { + return Err(Error::Seq); + } + if sr.strberr() { + // writing several times to the same byte in the write buffer + return Err(Error::Prog); + } + if sr.incerr() { + // attempting write operation before completion of previous + // write operation + return Err(Error::Seq); + } + + return Ok(()); + } + } +} + +pub(crate) unsafe fn clear_all_err() { + pac::FLASH.nsccr().modify(|w| { + w.set_clr_wrperr(true); + w.set_clr_pgserr(true); + w.set_clr_strberr(true); + w.set_clr_incerr(true); + }) +} + +fn sr_busy(sr: Nssr) -> bool { + // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE + sr.bsy() || sr.dbne() || sr.wbne() +} + +fn busy() -> bool { + let sr = pac::FLASH.nssr().read(); + sr_busy(sr) +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 4f43a7a48..1d8031e82 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -102,10 +102,11 @@ pub enum FlashBank { #[cfg_attr(flash_h7, path = "h7.rs")] #[cfg_attr(flash_h7ab, path = "h7.rs")] #[cfg_attr(flash_u5, path = "u5.rs")] +#[cfg_attr(flash_h50, path = "h50.rs")] #[cfg_attr( not(any( flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, - flash_g4, flash_h7, flash_h7ab, flash_u5 + flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50 )), path = "other.rs" )] From f3b96d8ba0d5143035a03679d94a4ba14f9652ac Mon Sep 17 00:00:00 2001 From: Mick Chanthaseth Date: Mon, 19 Feb 2024 15:14:28 -0800 Subject: [PATCH 516/760] Updated formatting in usb_hid_mouse.rs. --- examples/rp/src/bin/usb_hid_mouse.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index a812b22c3..d2c63605a 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -10,8 +10,8 @@ use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; -use embassy_time::Timer; use embassy_rp::usb::{Driver, InterruptHandler}; +use embassy_time::Timer; use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; @@ -92,18 +92,18 @@ async fn main(_spawner: Spawner) { loop { // every 1 second _ = Timer::after_secs(1).await; - let report = MouseReport{ + let report = MouseReport { buttons: 0, x: rng.gen_range(-100..100), // random small x movement y: rng.gen_range(-100..100), // random small y movement wheel: 0, pan: 0, }; - match writer.write_serialize(&report).await{ - Ok(())=>{}, - Err(e)=>{ + match writer.write_serialize(&report).await { + Ok(()) => {}, + Err(e) => { warn!("Failed to send report: {:?}", e); - }, + } } } }; From 9c870981e3696c8afb16951c806cc6678073f7ca Mon Sep 17 00:00:00 2001 From: Mick Chanthaseth Date: Mon, 19 Feb 2024 15:28:57 -0800 Subject: [PATCH 517/760] fixed formatting in usb_hid_mouse.rs --- examples/rp/src/bin/usb_hid_mouse.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index d2c63605a..3a5201b59 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -99,11 +99,10 @@ async fn main(_spawner: Spawner) { wheel: 0, pan: 0, }; + // Send the report. match writer.write_serialize(&report).await { - Ok(()) => {}, - Err(e) => { - warn!("Failed to send report: {:?}", e); - } + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), } } }; From bae30fb3973e0c35613422b1ecff299961b0dda4 Mon Sep 17 00:00:00 2001 From: Mick Chanthaseth Date: Mon, 19 Feb 2024 15:41:15 -0800 Subject: [PATCH 518/760] removed extra spaces. --- examples/rp/src/bin/usb_hid_mouse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index 3a5201b59..afebd8813 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -88,7 +88,7 @@ async fn main(_spawner: Spawner) { // Do stuff with the class! let in_fut = async { let mut rng = RoscRng; - + loop { // every 1 second _ = Timer::after_secs(1).await; From e8474426d8c0ca60ac222845b9c6f7befe3f6a4a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 20 Feb 2024 01:02:15 +0100 Subject: [PATCH 519/760] hal-internal: remove impl DerefMut for PeripheralRef. if you have `PeripheralRef<'a, AnyPIn>` for pin A, and `AnyPin` (owned) for pin B, you can `mem::swap` them. so, getting access forever to pin A, just by "sacrificing" pin B this defeats the point of PeripheralRef, which is if you got a `PeripheralRef<'a, T>` then you're only allowed to use the peripheral for `'a`. Also some drivers rely on the fact only one instance of a singleton exists for soundness, so this is a soundness fix for those. --- embassy-hal-internal/src/peripheral.rs | 11 +---- embassy-stm32/src/dma/bdma.rs | 6 +-- embassy-stm32/src/dma/dma.rs | 8 ++-- embassy-stm32/src/dma/dmamux.rs | 2 +- embassy-stm32/src/dma/gpdma.rs | 2 +- embassy-stm32/src/timer/mod.rs | 64 +++++++++++++------------- 6 files changed, 43 insertions(+), 50 deletions(-) diff --git a/embassy-hal-internal/src/peripheral.rs b/embassy-hal-internal/src/peripheral.rs index 16d49edfb..f03f41507 100644 --- a/embassy-hal-internal/src/peripheral.rs +++ b/embassy-hal-internal/src/peripheral.rs @@ -1,5 +1,5 @@ use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; +use core::ops::Deref; /// An exclusive reference to a peripheral. /// @@ -86,13 +86,6 @@ impl<'a, T> Deref for PeripheralRef<'a, T> { } } -impl<'a, T> DerefMut for PeripheralRef<'a, T> { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - /// Trait for any type that can be used as a peripheral of type `P`. /// /// This is used in driver constructors, to allow passing either owned peripherals (e.g. `TWISPI0`), @@ -162,7 +155,7 @@ pub trait Peripheral: Sized { } } -impl<'b, T: DerefMut> Peripheral for T +impl<'b, T: Deref> Peripheral for T where T::Target: Peripheral, { diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 077cfdcd9..994bdb1e6 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -299,7 +299,7 @@ impl<'a, C: Channel> Transfer<'a, C> { STATE.complete_count[this.channel.index()].store(0, Ordering::Release); #[cfg(dmamux)] - super::dmamux::configure_dmamux(&mut *this.channel, _request); + super::dmamux::configure_dmamux(&*this.channel, _request); ch.par().write_value(peri_addr as u32); ch.mar().write_value(mem_addr as u32); @@ -483,7 +483,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { this.clear_irqs(); #[cfg(dmamux)] - super::dmamux::configure_dmamux(&mut *this.channel, _request); + super::dmamux::configure_dmamux(&*this.channel, _request); let ch = dma.ch(channel_number); ch.par().write_value(peri_addr as u32); @@ -641,7 +641,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { this.clear_irqs(); #[cfg(dmamux)] - super::dmamux::configure_dmamux(&mut *this.channel, _request); + super::dmamux::configure_dmamux(&*this.channel, _request); let ch = dma.ch(channel_number); ch.par().write_value(peri_addr as u32); diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index ef9bb3d78..e762b1bde 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -366,7 +366,7 @@ impl<'a, C: Channel> Transfer<'a, C> { this.clear_irqs(); #[cfg(dmamux)] - super::dmamux::configure_dmamux(&mut *this.channel, _request); + super::dmamux::configure_dmamux(&*this.channel, _request); ch.par().write_value(peri_addr as u32); ch.m0ar().write_value(mem_addr as u32); @@ -522,7 +522,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { this.clear_irqs(); #[cfg(dmamux)] - super::dmamux::configure_dmamux(&mut *this.channel, _request); + super::dmamux::configure_dmamux(&*this.channel, _request); let ch = dma.st(channel_number); ch.par().write_value(peri_addr as u32); @@ -726,7 +726,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { this.clear_irqs(); #[cfg(dmamux)] - super::dmamux::configure_dmamux(&mut *this.channel, _request); + super::dmamux::configure_dmamux(&*this.channel, _request); let ch = dma.st(channel_number); ch.par().write_value(peri_addr as u32); @@ -901,7 +901,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { this.clear_irqs(); #[cfg(dmamux)] - super::dmamux::configure_dmamux(&mut *this.channel, _request); + super::dmamux::configure_dmamux(&*this.channel, _request); let ch = dma.st(channel_number); ch.par().write_value(peri_addr as u32); diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 9cd494724..ac6f44107 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -2,7 +2,7 @@ use crate::{pac, peripherals}; -pub(crate) fn configure_dmamux(channel: &mut M, request: u8) { +pub(crate) fn configure_dmamux(channel: &M, request: u8) { let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); ch_mux_regs.write(|reg| { reg.set_nbreq(0); diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 34b2426b9..337e7b309 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -259,7 +259,7 @@ impl<'a, C: Channel> Transfer<'a, C> { let this = Self { channel }; #[cfg(dmamux)] - super::dmamux::configure_dmamux(&mut *this.channel, request); + super::dmamux::configure_dmamux(&*this.channel, request); ch.cr().write(|w| w.set_reset(true)); ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9480d6972..9397da2a1 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -65,17 +65,17 @@ pub(crate) mod sealed { fn regs_core() -> crate::pac::timer::TimCore; /// Start the timer. - fn start(&mut self) { + fn start(&self) { Self::regs_core().cr1().modify(|r| r.set_cen(true)); } /// Stop the timer. - fn stop(&mut self) { + fn stop(&self) { Self::regs_core().cr1().modify(|r| r.set_cen(false)); } /// Reset the counter value to 0 - fn reset(&mut self) { + fn reset(&self) { Self::regs_core().cnt().write(|r| r.set_cnt(0)); } @@ -85,7 +85,7 @@ pub(crate) mod sealed { /// the timer counter will wrap around at the same frequency as is being set. /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved /// because it needs to count up and down. - fn set_frequency(&mut self, frequency: Hertz) { + fn set_frequency(&self, frequency: Hertz) { let f = frequency.0; let timer_f = Self::frequency().0; assert!(f > 0); @@ -108,7 +108,7 @@ pub(crate) mod sealed { /// Clear update interrupt. /// /// Returns whether the update interrupt flag was set. - fn clear_update_interrupt(&mut self) -> bool { + fn clear_update_interrupt(&self) -> bool { let regs = Self::regs_core(); let sr = regs.sr().read(); if sr.uif() { @@ -122,12 +122,12 @@ pub(crate) mod sealed { } /// Enable/disable the update interrupt. - fn enable_update_interrupt(&mut self, enable: bool) { + fn enable_update_interrupt(&self, enable: bool) { Self::regs_core().dier().modify(|r| r.set_uie(enable)); } /// Enable/disable autoreload preload. - fn set_autoreload_preload(&mut self, enable: bool) { + fn set_autoreload_preload(&self, enable: bool) { Self::regs_core().cr1().modify(|r| r.set_arpe(enable)); } @@ -154,7 +154,7 @@ pub(crate) mod sealed { fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2; /// Enable/disable the update dma. - fn enable_update_dma(&mut self, enable: bool) { + fn enable_update_dma(&self, enable: bool) { Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); } @@ -186,7 +186,7 @@ pub(crate) mod sealed { fn regs_1ch() -> crate::pac::timer::Tim1ch; /// Set clock divider. - fn set_clock_division(&mut self, ckd: vals::Ckd) { + fn set_clock_division(&self, ckd: vals::Ckd) { Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); } @@ -218,7 +218,7 @@ pub(crate) mod sealed { fn regs_gp16() -> crate::pac::timer::TimGp16; /// Set counting mode. - fn set_counting_mode(&mut self, mode: CountingMode) { + fn set_counting_mode(&self, mode: CountingMode) { let (cms, dir) = mode.into(); let timer_enabled = Self::regs_core().cr1().read().cen(); @@ -237,7 +237,7 @@ pub(crate) mod sealed { } /// Set input capture filter. - fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { + fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) { let raw_channel = channel.index(); Self::regs_gp16() .ccmr_input(raw_channel / 2) @@ -245,17 +245,17 @@ pub(crate) mod sealed { } /// Clear input interrupt. - fn clear_input_interrupt(&mut self, channel: Channel) { + fn clear_input_interrupt(&self, channel: Channel) { Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); } /// Enable input interrupt. - fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + fn enable_input_interrupt(&self, channel: Channel, enable: bool) { Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); } /// Set input capture prescaler. - fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) { let raw_channel = channel.index(); Self::regs_gp16() .ccmr_input(raw_channel / 2) @@ -263,7 +263,7 @@ pub(crate) mod sealed { } /// Set input TI selection. - fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) { let raw_channel = channel.index(); Self::regs_gp16() .ccmr_input(raw_channel / 2) @@ -271,7 +271,7 @@ pub(crate) mod sealed { } /// Set input capture mode. - fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) { Self::regs_gp16().ccer().modify(|r| match mode { InputCaptureMode::Rising => { r.set_ccnp(channel.index(), false); @@ -289,7 +289,7 @@ pub(crate) mod sealed { } /// Set output compare mode. - fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { + fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) { let raw_channel: usize = channel.index(); Self::regs_gp16() .ccmr_output(raw_channel / 2) @@ -297,14 +297,14 @@ pub(crate) mod sealed { } /// Set output polarity. - fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { Self::regs_gp16() .ccer() .modify(|w| w.set_ccp(channel.index(), polarity.into())); } /// Enable/disable a channel. - fn enable_channel(&mut self, channel: Channel, enable: bool) { + fn enable_channel(&self, channel: Channel, enable: bool) { Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); } @@ -314,12 +314,12 @@ pub(crate) mod sealed { } /// Set compare value for a channel. - fn set_compare_value(&mut self, channel: Channel, value: u16) { + fn set_compare_value(&self, channel: Channel, value: u16) { Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); } /// Get capture value for a channel. - fn get_capture_value(&mut self, channel: Channel) -> u16 { + fn get_capture_value(&self, channel: Channel) -> u16 { Self::regs_gp16().ccr(channel.index()).read().ccr() } @@ -329,7 +329,7 @@ pub(crate) mod sealed { } /// Set output compare preload. - fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { + fn set_output_compare_preload(&self, channel: Channel, preload: bool) { let channel_index = channel.index(); Self::regs_gp16() .ccmr_output(channel_index / 2) @@ -342,7 +342,7 @@ pub(crate) mod sealed { } /// Set capture compare DMA selection - fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { + fn set_cc_dma_selection(&self, ccds: super::vals::Ccds) { Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) } @@ -352,7 +352,7 @@ pub(crate) mod sealed { } /// Set capture compare DMA enable state - fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { + fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) } } @@ -369,7 +369,7 @@ pub(crate) mod sealed { fn regs_gp32() -> crate::pac::timer::TimGp32; /// Set timer frequency. - fn set_frequency(&mut self, frequency: Hertz) { + fn set_frequency(&self, frequency: Hertz) { let f = frequency.0; assert!(f > 0); let timer_f = Self::frequency().0; @@ -398,12 +398,12 @@ pub(crate) mod sealed { } /// Set comapre value for a channel. - fn set_compare_value(&mut self, channel: Channel, value: u32) { + fn set_compare_value(&self, channel: Channel, value: u32) { Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); } /// Get capture value for a channel. - fn get_capture_value(&mut self, channel: Channel) -> u32 { + fn get_capture_value(&self, channel: Channel) -> u32 { Self::regs_gp32().ccr(channel.index()).read().ccr() } @@ -430,17 +430,17 @@ pub(crate) mod sealed { fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; /// Set clock divider for the dead time. - fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { + fn set_dead_time_clock_division(&self, value: vals::Ckd) { Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); } /// Set dead time, as a fraction of the max duty value. - fn set_dead_time_value(&mut self, value: u8) { + fn set_dead_time_value(&self, value: u8) { Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); } /// Enable timer outputs. - fn enable_outputs(&mut self) { + fn enable_outputs(&self) { Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); } } @@ -468,14 +468,14 @@ pub(crate) mod sealed { fn regs_advanced() -> crate::pac::timer::TimAdv; /// Set complementary output polarity. - fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { Self::regs_advanced() .ccer() .modify(|w| w.set_ccnp(channel.index(), polarity.into())); } /// Enable/disable a complementary channel. - fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { + fn enable_complementary_channel(&self, channel: Channel, enable: bool) { Self::regs_advanced() .ccer() .modify(|w| w.set_ccne(channel.index(), enable)); From ba2b4aad81c37727e05d2ddfbcc77ce247787b35 Mon Sep 17 00:00:00 2001 From: NBonaparte Date: Mon, 19 Feb 2024 17:46:25 -0800 Subject: [PATCH 520/760] fix(nrf/spim): use `OutputDrive` to set pin drives --- embassy-nrf/src/gpio.rs | 2 +- embassy-nrf/src/spim.rs | 53 +++++++++++++---------------------------- 2 files changed, 17 insertions(+), 38 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index b2f987109..3649ea61a 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -189,7 +189,7 @@ impl<'d> Output<'d> { } } -fn convert_drive(drive: OutputDrive) -> DRIVE_A { +pub(crate) fn convert_drive(drive: OutputDrive) -> DRIVE_A { match drive { OutputDrive::Standard => DRIVE_A::S0S1, OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1, diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 0de35490b..a4ab7e9da 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -15,7 +15,7 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::sealed::Pin as _; -use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; +use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; use crate::{interrupt, pac, Peripheral}; @@ -51,14 +51,14 @@ pub struct Config { /// this byte will be transmitted in the MOSI line for the left-over bytes. pub orc: u8, - /// Enable high drive for the SCK line. - pub sck_high_drive: bool, + /// Drive strength for the SCK line. + pub sck_drive: OutputDrive, - /// Enable high drive for the MOSI line. - pub mosi_high_drive: bool, + /// Drive strength for the MOSI line. + pub mosi_drive: OutputDrive, - /// Enable high drive for the MISO line. - pub miso_high_drive: bool, + /// Drive strength for the MISO line. + pub miso_drive: OutputDrive, } impl Default for Config { @@ -68,9 +68,9 @@ impl Default for Config { mode: MODE_0, bit_order: BitOrder::MSB_FIRST, orc: 0x00, - sck_high_drive: false, - mosi_high_drive: false, - miso_high_drive: false, + sck_drive: OutputDrive::HighDrive, + mosi_drive: OutputDrive::HighDrive, + miso_drive: OutputDrive::HighDrive, } } } @@ -171,37 +171,16 @@ impl<'d, T: Instance> Spim<'d, T> { // Configure pins if let Some(sck) = &sck { - sck.conf().write(|w| { - w.dir().output(); - if config.sck_high_drive { - w.drive().h0h1(); - } else { - w.drive().s0s1(); - } - w - }); + sck.conf() + .write(|w| w.dir().output().drive().variant(convert_drive(config.sck_drive))); } if let Some(mosi) = &mosi { - mosi.conf().write(|w| { - w.dir().output(); - if config.mosi_high_drive { - w.drive().h0h1(); - } else { - w.drive().s0s1(); - } - w - }); + mosi.conf() + .write(|w| w.dir().output().drive().variant(convert_drive(config.mosi_drive))); } if let Some(miso) = &miso { - miso.conf().write(|w| { - w.input().connect(); - if config.miso_high_drive { - w.drive().h0h1(); - } else { - w.drive().s0s1(); - } - w - }); + miso.conf() + .write(|w| w.input().connect().drive().variant(convert_drive(config.miso_drive))); } match config.mode.polarity { From 9b2d096f4f8b8db3747a29fb96f7b2a228dd571f Mon Sep 17 00:00:00 2001 From: Joonas Javanainen Date: Tue, 20 Feb 2024 21:33:03 +0200 Subject: [PATCH 521/760] USB needs PWR_CR2 USV set on STM32L4 Confirmed to be needed on an STM32L422, and based on a quick look at L4/L4+ reference manuals, this bit is present and required to be set on all L4 chips that have some kind of USB peripheral (USB or OTG_FS). The `usb_otg` driver already sets it for `cfg(stm32l4)` and we should do the same thing here. --- embassy-stm32/src/usb/usb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 34d6b52fd..be321a19b 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -264,7 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> { let regs = T::regs(); - #[cfg(any(stm32l5, stm32wb))] + #[cfg(any(stm32l4, stm32l5, stm32wb))] crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); #[cfg(pwr_h5)] From 2ee9b373738cf78cf784bf8753a7f55568f85d9b Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Tue, 20 Feb 2024 17:54:35 -0800 Subject: [PATCH 522/760] Move to a single Mux Struct. --- embassy-stm32/build.rs | 26 ++++++++++---------------- embassy-stm32/src/rcc/f013.rs | 12 ++++++------ embassy-stm32/src/rcc/mod.rs | 2 ++ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index f45a571f2..2ffbadfc3 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -430,7 +430,7 @@ fn main() { let mut clock_names = BTreeSet::new(); - let mut rcc_cfgr_regs = BTreeMap::new(); + let mut rcc_cfgr_regs = BTreeSet::new(); for p in METADATA.peripherals { if !singletons.contains(&p.name.to_string()) { @@ -510,11 +510,7 @@ fn main() { let field_name = format_ident!("{}", field_name); let enum_name = format_ident!("{}", enum_name); - if !rcc_cfgr_regs.contains_key(mux.register) { - rcc_cfgr_regs.insert(mux.register, Vec::new()); - } - - rcc_cfgr_regs.get_mut(mux.register).unwrap().push(( + rcc_cfgr_regs.insert(( fieldset_name.clone(), field_name.clone(), enum_name.clone(), @@ -602,10 +598,10 @@ fn main() { } } - for (rcc_cfgr_reg, fields) in rcc_cfgr_regs { - println!("cargo:rustc-cfg={}", rcc_cfgr_reg.to_ascii_lowercase()); + if !rcc_cfgr_regs.is_empty() { + println!("cargo:rustc-cfg=clock_mux"); - let struct_fields: Vec<_> = fields + let struct_fields: Vec<_> = rcc_cfgr_regs .iter() .map(|(_fieldset, fieldname, enum_name)| { quote! { @@ -614,12 +610,12 @@ fn main() { }) .collect(); - let field_names: Vec<_> = fields + let field_names: Vec<_> = rcc_cfgr_regs .iter() .map(|(_fieldset, fieldname, _enum_name)| fieldname) .collect(); - let inits: Vec<_> = fields + let inits: Vec<_> = rcc_cfgr_regs .iter() .map(|(fieldset, fieldname, _enum_name)| { let setter = format_ident!("set_{}", fieldname); @@ -635,15 +631,13 @@ fn main() { }) .collect(); - let cfgr_reg = format_ident!("{}", rcc_cfgr_reg); - g.extend(quote! { #[derive(Clone, Copy)] - pub struct #cfgr_reg { + pub struct ClockMux { #( #struct_fields, )* } - impl Default for #cfgr_reg { + impl Default for ClockMux { fn default() -> Self { Self { #( #field_names: None, )* @@ -651,7 +645,7 @@ fn main() { } } - impl #cfgr_reg { + impl ClockMux { pub fn init(self) { #( #inits )* } diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index a61aae0e8..86af4bd68 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -99,8 +99,8 @@ pub struct Config { pub adc34: AdcClockSource, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, - #[cfg(cfgr3)] - pub cfgr3: crate::_generated::CFGR3, + #[cfg(clock_mux)] + pub mux: crate::rcc::ClockMux, pub ls: super::LsConfig, } @@ -130,8 +130,8 @@ impl Default for Config { adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(stm32f334)] hrtim: HrtimClockSource::BusClk, - #[cfg(cfgr3)] - cfgr3: Default::default(), + #[cfg(clock_mux)] + mux: Default::default(), } } } @@ -367,8 +367,8 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(cfgr3)] - config.cfgr3.init(); + #[cfg(clock_mux)] + config.mux.init(); set_clocks!( hsi: hsi, diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0f3467151..f71211925 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -32,6 +32,8 @@ mod _version; pub use _version::*; pub use crate::_generated::Clocks; +#[cfg(clock_mux)] +pub use crate::_generated::ClockMux; #[cfg(feature = "low-power")] /// Must be written within a critical section From 95056958300d92b34d5f8f77c7429894efbc0fa1 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Tue, 20 Feb 2024 17:55:05 -0800 Subject: [PATCH 523/760] Move compile test to the STM32F334 example. --- examples/stm32f3/src/bin/usart_dma.rs | 4 +--- examples/stm32f334/src/bin/pwm.rs | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 7dc905adc..5234e53b9 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs @@ -17,9 +17,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut init_config = embassy_stm32::Config::default(); - init_config.rcc.cfgr3.usart1sw = Some(embassy_stm32::pac::rcc::vals::Usart1sw::HSI); - let p = embassy_stm32::init(init_config); + let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let config = Config::default(); diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 7fc1ea926..24606b9b6 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -28,6 +28,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; config.rcc.hrtim = HrtimClockSource::PllClk; + config.rcc.mux.hrtim1sw = Some(embassy_stm32::pac::rcc::vals::Timsw::PLL1_P); // TODO: The two lines here do the same thing } let p = embassy_stm32::init(config); From 88e29608ed5425f5dbc3edf56acff1654d587a5e Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Tue, 20 Feb 2024 17:59:51 -0800 Subject: [PATCH 524/760] Rust fmt --- embassy-stm32/build.rs | 6 +----- embassy-stm32/src/rcc/mod.rs | 2 +- examples/stm32f334/src/bin/pwm.rs | 4 +++- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 2ffbadfc3..a0b74c0b9 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -510,11 +510,7 @@ fn main() { let field_name = format_ident!("{}", field_name); let enum_name = format_ident!("{}", enum_name); - rcc_cfgr_regs.insert(( - fieldset_name.clone(), - field_name.clone(), - enum_name.clone(), - )); + rcc_cfgr_regs.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone())); let match_arms: TokenStream = enumm .variants diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index f71211925..24516d426 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -31,9 +31,9 @@ mod _version; pub use _version::*; -pub use crate::_generated::Clocks; #[cfg(clock_mux)] pub use crate::_generated::ClockMux; +pub use crate::_generated::Clocks; #[cfg(feature = "low-power")] /// Must be written within a critical section diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 24606b9b6..cf5eb7b26 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -27,8 +27,10 @@ async fn main(_spawner: Spawner) { config.rcc.ahb_pre = AHBPrescaler::DIV1; config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; + + // TODO: The two lines here do the same thing config.rcc.hrtim = HrtimClockSource::PllClk; - config.rcc.mux.hrtim1sw = Some(embassy_stm32::pac::rcc::vals::Timsw::PLL1_P); // TODO: The two lines here do the same thing + config.rcc.mux.hrtim1sw = Some(embassy_stm32::pac::rcc::vals::Timsw::PLL1_P); } let p = embassy_stm32::init(config); From 111306ac0c93b2a7f12545067d23466f6f976742 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Feb 2024 19:09:58 +0100 Subject: [PATCH 525/760] nrf/buffered_uart: simplify split lifetimes. --- embassy-nrf/src/buffered_uarte.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index fb72422bd..e0916f775 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -426,7 +426,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// Split the UART in reader and writer parts. /// /// This allows reading and writing concurrently from independent tasks. - pub fn split<'u>(&'u mut self) -> (BufferedUarteRx<'u, 'd, U, T>, BufferedUarteTx<'u, 'd, U, T>) { + pub fn split(&mut self) -> (BufferedUarteRx<'_, U, T>, BufferedUarteTx<'_, U, T>) { (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self }) } @@ -570,11 +570,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { } /// Reader part of the buffered UARTE driver. -pub struct BufferedUarteTx<'u, 'd, U: UarteInstance, T: TimerInstance> { - inner: &'u BufferedUarte<'d, U, T>, +pub struct BufferedUarteTx<'d, U: UarteInstance, T: TimerInstance> { + inner: &'d BufferedUarte<'d, U, T>, } -impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'u, 'd, U, T> { +impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'d, U, T> { /// Write a buffer into this writer, returning how many bytes were written. pub async fn write(&mut self, buf: &[u8]) -> Result { self.inner.inner_write(buf).await @@ -587,11 +587,11 @@ impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'u, 'd, U, T> { } /// Writer part of the buffered UARTE driver. -pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> { - inner: &'u BufferedUarte<'d, U, T>, +pub struct BufferedUarteRx<'d, U: UarteInstance, T: TimerInstance> { + inner: &'d BufferedUarte<'d, U, T>, } -impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'u, 'd, U, T> { +impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.inner.inner_read(buf).await @@ -621,11 +621,11 @@ mod _embedded_io { type Error = Error; } - impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteRx<'u, 'd, U, T> { + impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteRx<'d, U, T> { type Error = Error; } - impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteTx<'u, 'd, U, T> { + impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteTx<'d, U, T> { type Error = Error; } @@ -635,7 +635,7 @@ mod _embedded_io { } } - impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarteRx<'u, 'd, U, T> { + impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarteRx<'d, U, T> { async fn read(&mut self, buf: &mut [u8]) -> Result { self.inner.inner_read(buf).await } @@ -651,7 +651,7 @@ mod _embedded_io { } } - impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarteRx<'u, 'd, U, T> { + impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarteRx<'d, U, T> { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { self.inner.inner_fill_buf().await } @@ -671,7 +671,7 @@ mod _embedded_io { } } - impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarteTx<'u, 'd, U, T> { + impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarteTx<'d, U, T> { async fn write(&mut self, buf: &[u8]) -> Result { self.inner.inner_write(buf).await } From 250cfa5f5f97107fc6c7b8beaa52c61c3a4423df Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Feb 2024 21:07:10 +0100 Subject: [PATCH 526/760] net/tcp: fix flush() not waiting for ACK of FIN. --- embassy-net/src/tcp.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index c508ff97a..57c9b7a04 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -491,10 +491,16 @@ impl<'d> TcpIo<'d> { async fn flush(&mut self) -> Result<(), Error> { poll_fn(move |cx| { self.with_mut(|s, _| { - let waiting_close = s.state() == tcp::State::Closed && s.remote_endpoint().is_some(); + let data_pending = s.send_queue() > 0; + let fin_pending = matches!( + s.state(), + tcp::State::FinWait1 | tcp::State::Closing | tcp::State::LastAck + ); + let rst_pending = s.state() == tcp::State::Closed && s.remote_endpoint().is_some(); + // If there are outstanding send operations, register for wake up and wait // smoltcp issues wake-ups when octets are dequeued from the send buffer - if s.send_queue() > 0 || waiting_close { + if data_pending || fin_pending || rst_pending { s.register_send_waker(cx.waker()); Poll::Pending // No outstanding sends, socket is flushed From c2e429205d2834f255e065475cefd123448d156a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Feb 2024 21:48:48 +0100 Subject: [PATCH 527/760] nrf/uart: add split_by_ref. --- embassy-nrf/src/uarte.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 9e5b85dea..90820acab 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -242,6 +242,14 @@ impl<'d, T: Instance> Uarte<'d, T> { (self.tx, self.rx) } + /// Split the UART in reader and writer parts, by reference. + /// + /// The returned halves borrow from `self`, so you can drop them and go back to using + /// the "un-split" `self`. This allows temporarily splitting the UART. + pub fn split_by_ref(&mut self) -> (&mut UarteTx<'d, T>, &mut UarteRx<'d, T>) { + (&mut self.tx, &mut self.rx) + } + /// Split the Uarte into the transmitter and receiver with idle support parts. /// /// This is useful to concurrently transmit and receive from independent tasks. From 1f17fdf84ee30f989a1a5bd8945a76a9f5edac4b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Feb 2024 21:51:43 +0100 Subject: [PATCH 528/760] nrf/buffered_uart: refactor so rx/tx halves are independent. --- .../src/atomic_ring_buffer.rs | 33 +- embassy-nrf/src/buffered_uarte.rs | 463 +++++++++--------- tests/nrf52840/src/bin/buffered_uart.rs | 2 +- tests/nrf52840/src/bin/buffered_uart_full.rs | 2 +- 4 files changed, 269 insertions(+), 231 deletions(-) diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs index b4f2cec28..34ceac852 100644 --- a/embassy-hal-internal/src/atomic_ring_buffer.rs +++ b/embassy-hal-internal/src/atomic_ring_buffer.rs @@ -1,6 +1,6 @@ //! Atomic reusable ringbuffer. -use core::slice; use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; +use core::{ptr, slice}; /// Atomic reusable ringbuffer /// @@ -73,6 +73,7 @@ impl RingBuffer { pub unsafe fn deinit(&self) { // Ordering: it's OK to use `Relaxed` because this is not called // concurrently with other methods. + self.buf.store(ptr::null_mut(), Ordering::Relaxed); self.len.store(0, Ordering::Relaxed); self.start.store(0, Ordering::Relaxed); self.end.store(0, Ordering::Relaxed); @@ -82,20 +83,46 @@ impl RingBuffer { /// /// # Safety /// - /// Only one reader can exist at a time. + /// - Only one reader can exist at a time. + /// - Ringbuffer must be initialized. pub unsafe fn reader(&self) -> Reader<'_> { Reader(self) } + /// Try creating a reader, fails if not initialized. + /// + /// # Safety + /// + /// Only one reader can exist at a time. + pub unsafe fn try_reader(&self) -> Option> { + if self.buf.load(Ordering::Relaxed).is_null() { + return None; + } + Some(Reader(self)) + } + /// Create a writer. /// /// # Safety /// - /// Only one writer can exist at a time. + /// - Only one writer can exist at a time. + /// - Ringbuffer must be initialized. pub unsafe fn writer(&self) -> Writer<'_> { Writer(self) } + /// Try creating a writer, fails if not initialized. + /// + /// # Safety + /// + /// Only one writer can exist at a time. + pub unsafe fn try_writer(&self) -> Option> { + if self.buf.load(Ordering::Relaxed).is_null() { + return None; + } + Some(Writer(self)) + } + /// Return length of buffer. pub fn len(&self) -> usize { self.len.load(Ordering::Relaxed) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index e0916f775..b1b639f10 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -22,13 +22,13 @@ use embassy_sync::waitqueue::AtomicWaker; pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; use crate::gpio::sealed::Pin; -use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; +use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; use crate::ppi::{ self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, }; use crate::timer::{Instance as TimerInstance, Timer}; -use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; +use crate::uarte::{apply_workaround_for_enable_anomaly, drop_tx_rx, Config, Instance as UarteInstance}; use crate::{interrupt, pac, Peripheral}; mod sealed { @@ -86,126 +86,128 @@ impl interrupt::typelevel::Handler for Interrupt let r = U::regs(); let s = U::buffered_state(); - let buf_len = s.rx_buf.len(); - let half_len = buf_len / 2; - let mut tx = unsafe { s.tx_buf.reader() }; - let mut rx = unsafe { s.rx_buf.writer() }; + if let Some(mut rx) = unsafe { s.rx_buf.try_writer() } { + let buf_len = s.rx_buf.len(); + let half_len = buf_len / 2; - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - let errs = r.errorsrc.read(); - r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) }); + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + let errs = r.errorsrc.read(); + r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) }); - if errs.overrun().bit() { - panic!("BufferedUarte overrun"); + if errs.overrun().bit() { + panic!("BufferedUarte overrun"); + } } - } - // Received some bytes, wake task. - if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 { - r.intenclr.write(|w| w.rxdrdy().clear()); - r.events_rxdrdy.reset(); - s.rx_waker.wake(); - } + // Received some bytes, wake task. + if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 { + r.intenclr.write(|w| w.rxdrdy().clear()); + r.events_rxdrdy.reset(); + s.rx_waker.wake(); + } - if r.events_endrx.read().bits() != 0 { - //trace!(" irq_rx: endrx"); - r.events_endrx.reset(); + if r.events_endrx.read().bits() != 0 { + //trace!(" irq_rx: endrx"); + r.events_endrx.reset(); - let val = s.rx_ended_count.load(Ordering::Relaxed); - s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); - } + let val = s.rx_ended_count.load(Ordering::Relaxed); + s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); + } - if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) { - //trace!(" irq_rx: rxstarted"); - let (ptr, len) = rx.push_buf(); - if len >= half_len { - r.events_rxstarted.reset(); + if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) { + //trace!(" irq_rx: rxstarted"); + let (ptr, len) = rx.push_buf(); + if len >= half_len { + r.events_rxstarted.reset(); - //trace!(" irq_rx: starting second {:?}", half_len); + //trace!(" irq_rx: starting second {:?}", half_len); - // Set up the DMA read - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); + // Set up the DMA read + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); - let chn = s.rx_ppi_ch.load(Ordering::Relaxed); + let chn = s.rx_ppi_ch.load(Ordering::Relaxed); - // Enable endrx -> startrx PPI channel. - // From this point on, if endrx happens, startrx is automatically fired. - ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) }); + // Enable endrx -> startrx PPI channel. + // From this point on, if endrx happens, startrx is automatically fired. + ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) }); - // It is possible that endrx happened BEFORE enabling the PPI. In this case - // the PPI channel doesn't trigger, and we'd hang. We have to detect this - // and manually start. + // It is possible that endrx happened BEFORE enabling the PPI. In this case + // the PPI channel doesn't trigger, and we'd hang. We have to detect this + // and manually start. - // check again in case endrx has happened between the last check and now. - if r.events_endrx.read().bits() != 0 { - //trace!(" irq_rx: endrx"); - r.events_endrx.reset(); + // check again in case endrx has happened between the last check and now. + if r.events_endrx.read().bits() != 0 { + //trace!(" irq_rx: endrx"); + r.events_endrx.reset(); - let val = s.rx_ended_count.load(Ordering::Relaxed); - s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); + let val = s.rx_ended_count.load(Ordering::Relaxed); + s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); + } + + let rx_ended = s.rx_ended_count.load(Ordering::Relaxed); + let rx_started = s.rx_started_count.load(Ordering::Relaxed); + + // If we started the same amount of transfers as ended, the last rxend has + // already occured. + let rxend_happened = rx_started == rx_ended; + + // Check if the PPI channel is still enabled. The PPI channel disables itself + // when it fires, so if it's still enabled it hasn't fired. + let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0; + + // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed. + // this condition also naturally matches if `!started`, needed to kickstart the DMA. + if rxend_happened && ppi_ch_enabled { + //trace!("manually starting."); + + // disable the ppi ch, it's of no use anymore. + ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) }); + + // manually start + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + } + + rx.push_done(half_len); + + s.rx_started_count.store(rx_started.wrapping_add(1), Ordering::Relaxed); + s.rx_started.store(true, Ordering::Relaxed); + } else { + //trace!(" irq_rx: rxstarted no buf"); + r.intenclr.write(|w| w.rxstarted().clear()); } - - let rx_ended = s.rx_ended_count.load(Ordering::Relaxed); - let rx_started = s.rx_started_count.load(Ordering::Relaxed); - - // If we started the same amount of transfers as ended, the last rxend has - // already occured. - let rxend_happened = rx_started == rx_ended; - - // Check if the PPI channel is still enabled. The PPI channel disables itself - // when it fires, so if it's still enabled it hasn't fired. - let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0; - - // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed. - // this condition also naturally matches if `!started`, needed to kickstart the DMA. - if rxend_happened && ppi_ch_enabled { - //trace!("manually starting."); - - // disable the ppi ch, it's of no use anymore. - ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) }); - - // manually start - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - } - - rx.push_done(half_len); - - s.rx_started_count.store(rx_started.wrapping_add(1), Ordering::Relaxed); - s.rx_started.store(true, Ordering::Relaxed); - } else { - //trace!(" irq_rx: rxstarted no buf"); - r.intenclr.write(|w| w.rxstarted().clear()); } } // ============================= - // TX end - if r.events_endtx.read().bits() != 0 { - r.events_endtx.reset(); + if let Some(mut tx) = unsafe { s.tx_buf.try_reader() } { + // TX end + if r.events_endtx.read().bits() != 0 { + r.events_endtx.reset(); - let n = s.tx_count.load(Ordering::Relaxed); - //trace!(" irq_tx: endtx {:?}", n); - tx.pop_done(n); - s.tx_waker.wake(); - s.tx_count.store(0, Ordering::Relaxed); - } + let n = s.tx_count.load(Ordering::Relaxed); + //trace!(" irq_tx: endtx {:?}", n); + tx.pop_done(n); + s.tx_waker.wake(); + s.tx_count.store(0, Ordering::Relaxed); + } - // If not TXing, start. - if s.tx_count.load(Ordering::Relaxed) == 0 { - let (ptr, len) = tx.pop_buf(); - if len != 0 { - //trace!(" irq_tx: starting {:?}", len); - s.tx_count.store(len, Ordering::Relaxed); + // If not TXing, start. + if s.tx_count.load(Ordering::Relaxed) == 0 { + let (ptr, len) = tx.pop_buf(); + if len != 0 { + //trace!(" irq_tx: starting {:?}", len); + s.tx_count.store(len, Ordering::Relaxed); - // Set up the DMA write - r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + // Set up the DMA write + r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); - // Start UARTE Transmit transaction - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + // Start UARTE Transmit transaction + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + } } } @@ -215,11 +217,8 @@ impl interrupt::typelevel::Handler for Interrupt /// Buffered UARTE driver. pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { - _peri: PeripheralRef<'d, U>, - timer: Timer<'d, T>, - _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, - _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, - _ppi_group: PpiGroup<'d, AnyGroup>, + tx: BufferedUarteTx<'d, U>, + rx: BufferedUarteRx<'d, U, T>, } impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} @@ -404,17 +403,21 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { U::Interrupt::pend(); unsafe { U::Interrupt::enable() }; - Self { - _peri: peri, - timer, - _ppi_ch1: ppi_ch1, - _ppi_ch2: ppi_ch2, - _ppi_group: ppi_group, - } - } + let s = U::state(); + s.tx_rx_refcount.store(2, Ordering::Relaxed); - fn pend_irq() { - U::Interrupt::pend() + Self { + tx: BufferedUarteTx { + _peri: unsafe { peri.clone_unchecked() }, + }, + rx: BufferedUarteRx { + _peri: peri, + timer, + _ppi_ch1: ppi_ch1, + _ppi_ch2: ppi_ch2, + _ppi_group: ppi_group, + }, + } } /// Adjust the baud rate to the provided value. @@ -426,19 +429,52 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// Split the UART in reader and writer parts. /// /// This allows reading and writing concurrently from independent tasks. - pub fn split(&mut self) -> (BufferedUarteRx<'_, U, T>, BufferedUarteTx<'_, U, T>) { - (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self }) + pub fn split(self) -> (BufferedUarteRx<'d, U, T>, BufferedUarteTx<'d, U>) { + (self.rx, self.tx) } - async fn inner_read(&self, buf: &mut [u8]) -> Result { - let data = self.inner_fill_buf().await?; - let n = data.len().min(buf.len()); - buf[..n].copy_from_slice(&data[..n]); - self.inner_consume(n); - Ok(n) + /// Split the UART in reader and writer parts, by reference. + /// + /// The returned halves borrow from `self`, so you can drop them and go back to using + /// the "un-split" `self`. This allows temporarily splitting the UART. + pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d, U, T>, &mut BufferedUarteTx<'d, U>) { + (&mut self.rx, &mut self.tx) } - async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result { + /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. + pub async fn read(&mut self, buf: &mut [u8]) -> Result { + self.rx.read(buf).await + } + + /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. + pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { + self.rx.fill_buf().await + } + + /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. + pub fn consume(&mut self, amt: usize) { + self.rx.consume(amt) + } + + /// Write a buffer into this writer, returning how many bytes were written. + pub async fn write(&mut self, buf: &[u8]) -> Result { + self.tx.write(buf).await + } + + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. + pub async fn flush(&mut self) -> Result<(), Error> { + self.tx.flush().await + } +} + +/// Reader part of the buffered UARTE driver. +pub struct BufferedUarteTx<'d, U: UarteInstance> { + _peri: PeripheralRef<'d, U>, +} + +impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { + /// Write a buffer into this writer, returning how many bytes were written. + pub async fn write(&mut self, buf: &[u8]) -> Result { poll_fn(move |cx| { //trace!("poll_write: {:?}", buf.len()); let s = U::buffered_state(); @@ -458,14 +494,15 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { //trace!("poll_write: queued {:?}", n); compiler_fence(Ordering::SeqCst); - Self::pend_irq(); + U::Interrupt::pend(); Poll::Ready(Ok(n)) }) .await } - async fn inner_flush<'a>(&'a self) -> Result<(), Error> { + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. + pub async fn flush(&mut self) -> Result<(), Error> { poll_fn(move |cx| { //trace!("poll_flush"); let s = U::buffered_state(); @@ -479,8 +516,51 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { }) .await } +} - async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> { +impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> { + fn drop(&mut self) { + let r = U::regs(); + + r.intenclr.write(|w| { + w.txdrdy().set_bit(); + w.txstarted().set_bit(); + w.txstopped().set_bit(); + w + }); + r.events_txstopped.reset(); + r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); + while r.events_txstopped.read().bits() == 0 {} + + let s = U::buffered_state(); + unsafe { s.tx_buf.deinit() } + + let s = U::state(); + drop_tx_rx(r, s); + } +} + +/// Reader part of the buffered UARTE driver. +pub struct BufferedUarteRx<'d, U: UarteInstance, T: TimerInstance> { + _peri: PeripheralRef<'d, U>, + timer: Timer<'d, T>, + _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, + _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, + _ppi_group: PpiGroup<'d, AnyGroup>, +} + +impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { + /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. + pub async fn read(&mut self, buf: &mut [u8]) -> Result { + let data = self.fill_buf().await?; + let n = data.len().min(buf.len()); + buf[..n].copy_from_slice(&data[..n]); + self.consume(n); + Ok(n) + } + + /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. + pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { poll_fn(move |cx| { compiler_fence(Ordering::SeqCst); //trace!("poll_read"); @@ -532,7 +612,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { .await } - fn inner_consume(&self, amt: usize) { + /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. + pub fn consume(&mut self, amt: usize) { if amt == 0 { return; } @@ -542,69 +623,31 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { rx.pop_done(amt); U::regs().intenset.write(|w| w.rxstarted().set()); } - - /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. - pub async fn read(&mut self, buf: &mut [u8]) -> Result { - self.inner_read(buf).await - } - - /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. - pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { - self.inner_fill_buf().await - } - - /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. - pub fn consume(&mut self, amt: usize) { - self.inner_consume(amt) - } - - /// Write a buffer into this writer, returning how many bytes were written. - pub async fn write(&mut self, buf: &[u8]) -> Result { - self.inner_write(buf).await - } - - /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. - pub async fn flush(&mut self) -> Result<(), Error> { - self.inner_flush().await - } } -/// Reader part of the buffered UARTE driver. -pub struct BufferedUarteTx<'d, U: UarteInstance, T: TimerInstance> { - inner: &'d BufferedUarte<'d, U, T>, -} +impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> { + fn drop(&mut self) { + self._ppi_group.disable_all(); -impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'d, U, T> { - /// Write a buffer into this writer, returning how many bytes were written. - pub async fn write(&mut self, buf: &[u8]) -> Result { - self.inner.inner_write(buf).await - } + let r = U::regs(); - /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. - pub async fn flush(&mut self) -> Result<(), Error> { - self.inner.inner_flush().await - } -} + self.timer.stop(); -/// Writer part of the buffered UARTE driver. -pub struct BufferedUarteRx<'d, U: UarteInstance, T: TimerInstance> { - inner: &'d BufferedUarte<'d, U, T>, -} + r.intenclr.write(|w| { + w.rxdrdy().set_bit(); + w.rxstarted().set_bit(); + w.rxto().set_bit(); + w + }); + r.events_rxto.reset(); + r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + while r.events_rxto.read().bits() == 0 {} -impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { - /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. - pub async fn read(&mut self, buf: &mut [u8]) -> Result { - self.inner.inner_read(buf).await - } + let s = U::buffered_state(); + unsafe { s.rx_buf.deinit() } - /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. - pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { - self.inner.inner_fill_buf().await - } - - /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. - pub fn consume(&mut self, amt: usize) { - self.inner.inner_consume(amt) + let s = U::state(); + drop_tx_rx(r, s); } } @@ -625,91 +668,59 @@ mod _embedded_io { type Error = Error; } - impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteTx<'d, U, T> { + impl<'d, U: UarteInstance> embedded_io_async::ErrorType for BufferedUarteTx<'d, U> { type Error = Error; } impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarte<'d, U, T> { async fn read(&mut self, buf: &mut [u8]) -> Result { - self.inner_read(buf).await + self.read(buf).await } } impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarteRx<'d, U, T> { async fn read(&mut self, buf: &mut [u8]) -> Result { - self.inner.inner_read(buf).await + self.read(buf).await } } impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { - self.inner_fill_buf().await + self.fill_buf().await } fn consume(&mut self, amt: usize) { - self.inner_consume(amt) + self.consume(amt) } } impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarteRx<'d, U, T> { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { - self.inner.inner_fill_buf().await + self.fill_buf().await } fn consume(&mut self, amt: usize) { - self.inner.inner_consume(amt) + self.consume(amt) } } impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarte<'d, U, T> { async fn write(&mut self, buf: &[u8]) -> Result { - self.inner_write(buf).await + self.write(buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { - self.inner_flush().await + self.flush().await } } - impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarteTx<'d, U, T> { + impl<'d: 'd, U: UarteInstance> embedded_io_async::Write for BufferedUarteTx<'d, U> { async fn write(&mut self, buf: &[u8]) -> Result { - self.inner.inner_write(buf).await + self.write(buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { - self.inner.inner_flush().await - } - } -} - -impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarte<'a, U, T> { - fn drop(&mut self) { - self._ppi_group.disable_all(); - - let r = U::regs(); - - self.timer.stop(); - - r.inten.reset(); - r.events_rxto.reset(); - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - r.events_txstopped.reset(); - r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); - - while r.events_txstopped.read().bits() == 0 {} - while r.events_rxto.read().bits() == 0 {} - - r.enable.write(|w| w.enable().disabled()); - - gpio::deconfigure_pin(r.psel.rxd.read().bits()); - gpio::deconfigure_pin(r.psel.txd.read().bits()); - gpio::deconfigure_pin(r.psel.rts.read().bits()); - gpio::deconfigure_pin(r.psel.cts.read().bits()); - - let s = U::buffered_state(); - unsafe { - s.rx_buf.deinit(); - s.tx_buf.deinit(); + self.flush().await } } } diff --git a/tests/nrf52840/src/bin/buffered_uart.rs b/tests/nrf52840/src/bin/buffered_uart.rs index 354d787b4..721751136 100644 --- a/tests/nrf52840/src/bin/buffered_uart.rs +++ b/tests/nrf52840/src/bin/buffered_uart.rs @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { let mut tx_buffer = [0u8; 1024]; let mut rx_buffer = [0u8; 1024]; - let mut u = BufferedUarte::new( + let u = BufferedUarte::new( p.UARTE0, p.TIMER0, p.PPI_CH0, diff --git a/tests/nrf52840/src/bin/buffered_uart_full.rs b/tests/nrf52840/src/bin/buffered_uart_full.rs index e59c75ba9..62edaed25 100644 --- a/tests/nrf52840/src/bin/buffered_uart_full.rs +++ b/tests/nrf52840/src/bin/buffered_uart_full.rs @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { let mut tx_buffer = [0u8; 1024]; let mut rx_buffer = [0u8; 1024]; - let mut u = BufferedUarte::new( + let u = BufferedUarte::new( p.UARTE0, p.TIMER0, p.PPI_CH0, From 4fbe18f82134567af4766d161e8385c7dd919a0b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Feb 2024 22:29:37 +0100 Subject: [PATCH 529/760] nrf/uart: share waker state between buffered and nonbuffered. --- embassy-nrf/src/buffered_uarte.rs | 19 +++++++++---------- embassy-nrf/src/uarte.rs | 18 +++++++++--------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index b1b639f10..18416483f 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -17,7 +17,6 @@ use core::task::Poll; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_hal_internal::{into_ref, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; // Re-export SVD variants to allow user to directly set values pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; @@ -35,11 +34,9 @@ mod sealed { use super::*; pub struct State { - pub tx_waker: AtomicWaker, pub tx_buf: RingBuffer, pub tx_count: AtomicUsize, - pub rx_waker: AtomicWaker, pub rx_buf: RingBuffer, pub rx_started: AtomicBool, pub rx_started_count: AtomicU8, @@ -61,11 +58,9 @@ pub(crate) use sealed::State; impl State { pub(crate) const fn new() -> Self { Self { - tx_waker: AtomicWaker::new(), tx_buf: RingBuffer::new(), tx_count: AtomicUsize::new(0), - rx_waker: AtomicWaker::new(), rx_buf: RingBuffer::new(), rx_started: AtomicBool::new(false), rx_started_count: AtomicU8::new(0), @@ -84,6 +79,7 @@ impl interrupt::typelevel::Handler for Interrupt unsafe fn on_interrupt() { //trace!("irq: start"); let r = U::regs(); + let ss = U::state(); let s = U::buffered_state(); if let Some(mut rx) = unsafe { s.rx_buf.try_writer() } { @@ -104,7 +100,7 @@ impl interrupt::typelevel::Handler for Interrupt if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 { r.intenclr.write(|w| w.rxdrdy().clear()); r.events_rxdrdy.reset(); - s.rx_waker.wake(); + ss.rx_waker.wake(); } if r.events_endrx.read().bits() != 0 { @@ -190,7 +186,7 @@ impl interrupt::typelevel::Handler for Interrupt let n = s.tx_count.load(Ordering::Relaxed); //trace!(" irq_tx: endtx {:?}", n); tx.pop_done(n); - s.tx_waker.wake(); + ss.tx_waker.wake(); s.tx_count.store(0, Ordering::Relaxed); } @@ -477,13 +473,14 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { pub async fn write(&mut self, buf: &[u8]) -> Result { poll_fn(move |cx| { //trace!("poll_write: {:?}", buf.len()); + let ss = U::state(); let s = U::buffered_state(); let mut tx = unsafe { s.tx_buf.writer() }; let tx_buf = tx.push_slice(); if tx_buf.is_empty() { //trace!("poll_write: pending"); - s.tx_waker.register(cx.waker()); + ss.tx_waker.register(cx.waker()); return Poll::Pending; } @@ -505,10 +502,11 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { pub async fn flush(&mut self) -> Result<(), Error> { poll_fn(move |cx| { //trace!("poll_flush"); + let ss = U::state(); let s = U::buffered_state(); if !s.tx_buf.is_empty() { //trace!("poll_flush: pending"); - s.tx_waker.register(cx.waker()); + ss.tx_waker.register(cx.waker()); return Poll::Pending; } @@ -567,6 +565,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { let r = U::regs(); let s = U::buffered_state(); + let ss = U::state(); // Read the RXDRDY counter. T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) }); @@ -590,7 +589,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { let len = s.rx_buf.len(); if start == end { //trace!(" empty"); - s.rx_waker.register(cx.waker()); + ss.rx_waker.register(cx.waker()); r.intenset.write(|w| w.rxdrdy().set_bit()); return Poll::Pending; } diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 90820acab..cd14c718a 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -115,7 +115,7 @@ impl interrupt::typelevel::Handler for InterruptHandl let endrx = r.events_endrx.read().bits(); let error = r.events_error.read().bits(); if endrx != 0 || error != 0 { - s.endrx_waker.wake(); + s.rx_waker.wake(); if endrx != 0 { r.intenclr.write(|w| w.endrx().clear()); } @@ -124,7 +124,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } } if r.events_endtx.read().bits() != 0 { - s.endtx_waker.wake(); + s.tx_waker.wake(); r.intenclr.write(|w| w.endtx().clear()); } } @@ -433,7 +433,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { r.tasks_starttx.write(|w| unsafe { w.bits(1) }); poll_fn(|cx| { - s.endtx_waker.register(cx.waker()); + s.tx_waker.register(cx.waker()); if r.events_endtx.read().bits() != 0 { return Poll::Ready(()); } @@ -680,7 +680,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { r.tasks_startrx.write(|w| unsafe { w.bits(1) }); let result = poll_fn(|cx| { - s.endrx_waker.register(cx.waker()); + s.rx_waker.register(cx.waker()); if let Err(e) = self.check_and_clear_errors() { r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); @@ -827,7 +827,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { r.tasks_startrx.write(|w| unsafe { w.bits(1) }); let result = poll_fn(|cx| { - s.endrx_waker.register(cx.waker()); + s.rx_waker.register(cx.waker()); if let Err(e) = self.rx.check_and_clear_errors() { r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); @@ -970,15 +970,15 @@ pub(crate) mod sealed { use super::*; pub struct State { - pub endrx_waker: AtomicWaker, - pub endtx_waker: AtomicWaker, + pub rx_waker: AtomicWaker, + pub tx_waker: AtomicWaker, pub tx_rx_refcount: AtomicU8, } impl State { pub const fn new() -> Self { Self { - endrx_waker: AtomicWaker::new(), - endtx_waker: AtomicWaker::new(), + rx_waker: AtomicWaker::new(), + tx_waker: AtomicWaker::new(), tx_rx_refcount: AtomicU8::new(0), } } From 2feed96c91e2bd3846452e87b575b3d57ae3cde8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Feb 2024 23:23:04 +0100 Subject: [PATCH 530/760] nrf/uart: Add support for rx-only or tx-only BufferedUart. --- embassy-nrf/src/buffered_uarte.rs | 361 +++++++++++++++++++++--------- embassy-nrf/src/uarte.rs | 2 +- 2 files changed, 255 insertions(+), 108 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 18416483f..b04c96e09 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -27,7 +27,7 @@ use crate::ppi::{ self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, }; use crate::timer::{Instance as TimerInstance, Timer}; -use crate::uarte::{apply_workaround_for_enable_anomaly, drop_tx_rx, Config, Instance as UarteInstance}; +use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance}; use crate::{interrupt, pac, Peripheral}; mod sealed { @@ -238,7 +238,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], ) -> Self { - into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group); + into_ref!(uarte, timer, rxd, txd, ppi_ch1, ppi_ch2, ppi_group); Self::new_inner( uarte, timer, @@ -275,7 +275,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], ) -> Self { - into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group); + into_ref!(uarte, timer, rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group); Self::new_inner( uarte, timer, @@ -293,8 +293,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { } fn new_inner( - peri: impl Peripheral

+ 'd, - timer: impl Peripheral

+ 'd, + peri: PeripheralRef<'d, U>, + timer: PeripheralRef<'d, T>, ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, ppi_group: PeripheralRef<'d, AnyGroup>, @@ -306,114 +306,17 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], ) -> Self { - into_ref!(peri, timer); + configure(U::regs(), config, cts.is_some()); - assert!(rx_buffer.len() % 2 == 0); - - let r = U::regs(); - - let hwfc = cts.is_some(); - - rxd.conf().write(|w| w.input().connect().drive().h0h1()); - r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); - - txd.set_high(); - txd.conf().write(|w| w.dir().output().drive().h0h1()); - r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); - - if let Some(pin) = &cts { - pin.conf().write(|w| w.input().connect().drive().h0h1()); - } - r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); - - if let Some(pin) = &rts { - pin.set_high(); - pin.conf().write(|w| w.dir().output().drive().h0h1()); - } - r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); - - // Initialize state - let s = U::buffered_state(); - s.tx_count.store(0, Ordering::Relaxed); - s.rx_started_count.store(0, Ordering::Relaxed); - s.rx_ended_count.store(0, Ordering::Relaxed); - s.rx_started.store(false, Ordering::Relaxed); - let len = tx_buffer.len(); - unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; - let len = rx_buffer.len(); - unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; - - // Configure - r.config.write(|w| { - w.hwfc().bit(hwfc); - w.parity().variant(config.parity); - w - }); - r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); - - // clear errors - let errors = r.errorsrc.read().bits(); - r.errorsrc.write(|w| unsafe { w.bits(errors) }); - - r.events_rxstarted.reset(); - r.events_txstarted.reset(); - r.events_error.reset(); - r.events_endrx.reset(); - r.events_endtx.reset(); - - // Enable interrupts - r.intenclr.write(|w| unsafe { w.bits(!0) }); - r.intenset.write(|w| { - w.endtx().set(); - w.rxstarted().set(); - w.error().set(); - w.endrx().set(); - w - }); - - // Enable UARTE instance - apply_workaround_for_enable_anomaly(r); - r.enable.write(|w| w.enable().enabled()); - - // Configure byte counter. - let timer = Timer::new_counter(timer); - timer.cc(1).write(rx_buffer.len() as u32 * 2); - timer.cc(1).short_compare_clear(); - timer.clear(); - timer.start(); - - let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count()); - ppi_ch1.enable(); - - s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); - let mut ppi_group = PpiGroup::new(ppi_group); - let mut ppi_ch2 = Ppi::new_one_to_two( - ppi_ch2, - Event::from_reg(&r.events_endrx), - Task::from_reg(&r.tasks_startrx), - ppi_group.task_disable_all(), - ); - ppi_ch2.disable(); - ppi_group.add_channel(&ppi_ch2); + let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer); + let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); U::Interrupt::pend(); unsafe { U::Interrupt::enable() }; - let s = U::state(); - s.tx_rx_refcount.store(2, Ordering::Relaxed); + U::state().tx_rx_refcount.store(2, Ordering::Relaxed); - Self { - tx: BufferedUarteTx { - _peri: unsafe { peri.clone_unchecked() }, - }, - rx: BufferedUarteRx { - _peri: peri, - timer, - _ppi_ch1: ppi_ch1, - _ppi_ch2: ppi_ch2, - _ppi_group: ppi_group, - }, - } + Self { tx, rx } } /// Adjust the baud rate to the provided value. @@ -469,6 +372,88 @@ pub struct BufferedUarteTx<'d, U: UarteInstance> { } impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { + /// Create a new BufferedUarteTx without hardware flow control. + pub fn new( + uarte: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + txd: impl Peripheral

+ 'd, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + into_ref!(uarte, txd); + Self::new_inner(uarte, txd.map_into(), None, config, tx_buffer) + } + + /// Create a new BufferedUarte with hardware flow control (RTS/CTS) + /// + /// # Panics + /// + /// Panics if `rx_buffer.len()` is odd. + pub fn new_with_cts( + uarte: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + txd: impl Peripheral

+ 'd, + cts: impl Peripheral

+ 'd, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + into_ref!(uarte, txd, cts); + Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config, tx_buffer) + } + + fn new_inner( + peri: PeripheralRef<'d, U>, + txd: PeripheralRef<'d, AnyPin>, + cts: Option>, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + configure(U::regs(), config, cts.is_some()); + + let this = Self::new_innerer(peri, txd, cts, tx_buffer); + + U::Interrupt::pend(); + unsafe { U::Interrupt::enable() }; + + U::state().tx_rx_refcount.store(1, Ordering::Relaxed); + + this + } + + fn new_innerer( + peri: PeripheralRef<'d, U>, + txd: PeripheralRef<'d, AnyPin>, + cts: Option>, + tx_buffer: &'d mut [u8], + ) -> Self { + let r = U::regs(); + + txd.set_high(); + txd.conf().write(|w| w.dir().output().drive().h0h1()); + r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); + + if let Some(pin) = &cts { + pin.conf().write(|w| w.input().connect().drive().h0h1()); + } + r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); + + // Initialize state + let s = U::buffered_state(); + s.tx_count.store(0, Ordering::Relaxed); + let len = tx_buffer.len(); + unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; + + r.events_txstarted.reset(); + + // Enable interrupts + r.intenset.write(|w| { + w.endtx().set(); + w + }); + + Self { _peri: peri } + } + /// Write a buffer into this writer, returning how many bytes were written. pub async fn write(&mut self, buf: &[u8]) -> Result { poll_fn(move |cx| { @@ -548,6 +533,168 @@ pub struct BufferedUarteRx<'d, U: UarteInstance, T: TimerInstance> { } impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { + /// Create a new BufferedUarte without hardware flow control. + /// + /// # Panics + /// + /// Panics if `rx_buffer.len()` is odd. + pub fn new( + uarte: impl Peripheral

+ 'd, + timer: impl Peripheral

+ 'd, + ppi_ch1: impl Peripheral

+ 'd, + ppi_ch2: impl Peripheral

+ 'd, + ppi_group: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + rxd: impl Peripheral

+ 'd, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + into_ref!(uarte, timer, rxd, ppi_ch1, ppi_ch2, ppi_group); + Self::new_inner( + uarte, + timer, + ppi_ch1.map_into(), + ppi_ch2.map_into(), + ppi_group.map_into(), + rxd.map_into(), + None, + config, + rx_buffer, + ) + } + + /// Create a new BufferedUarte with hardware flow control (RTS/CTS) + /// + /// # Panics + /// + /// Panics if `rx_buffer.len()` is odd. + pub fn new_with_rts( + uarte: impl Peripheral

+ 'd, + timer: impl Peripheral

+ 'd, + ppi_ch1: impl Peripheral

+ 'd, + ppi_ch2: impl Peripheral

+ 'd, + ppi_group: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + rxd: impl Peripheral

+ 'd, + rts: impl Peripheral

+ 'd, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + into_ref!(uarte, timer, rxd, rts, ppi_ch1, ppi_ch2, ppi_group); + Self::new_inner( + uarte, + timer, + ppi_ch1.map_into(), + ppi_ch2.map_into(), + ppi_group.map_into(), + rxd.map_into(), + Some(rts.map_into()), + config, + rx_buffer, + ) + } + + fn new_inner( + peri: PeripheralRef<'d, U>, + timer: PeripheralRef<'d, T>, + ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, + ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, + ppi_group: PeripheralRef<'d, AnyGroup>, + rxd: PeripheralRef<'d, AnyPin>, + rts: Option>, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + configure(U::regs(), config, rts.is_some()); + + let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); + + U::Interrupt::pend(); + unsafe { U::Interrupt::enable() }; + + U::state().tx_rx_refcount.store(1, Ordering::Relaxed); + + this + } + + fn new_innerer( + peri: PeripheralRef<'d, U>, + timer: PeripheralRef<'d, T>, + ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, + ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, + ppi_group: PeripheralRef<'d, AnyGroup>, + rxd: PeripheralRef<'d, AnyPin>, + rts: Option>, + rx_buffer: &'d mut [u8], + ) -> Self { + assert!(rx_buffer.len() % 2 == 0); + + let r = U::regs(); + + rxd.conf().write(|w| w.input().connect().drive().h0h1()); + r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); + + if let Some(pin) = &rts { + pin.set_high(); + pin.conf().write(|w| w.dir().output().drive().h0h1()); + } + r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); + + // Initialize state + let s = U::buffered_state(); + s.rx_started_count.store(0, Ordering::Relaxed); + s.rx_ended_count.store(0, Ordering::Relaxed); + s.rx_started.store(false, Ordering::Relaxed); + let len = rx_buffer.len(); + unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; + + // clear errors + let errors = r.errorsrc.read().bits(); + r.errorsrc.write(|w| unsafe { w.bits(errors) }); + + r.events_rxstarted.reset(); + r.events_error.reset(); + r.events_endrx.reset(); + + // Enable interrupts + r.intenset.write(|w| { + w.endtx().set(); + w.rxstarted().set(); + w.error().set(); + w.endrx().set(); + w + }); + + // Configure byte counter. + let timer = Timer::new_counter(timer); + timer.cc(1).write(rx_buffer.len() as u32 * 2); + timer.cc(1).short_compare_clear(); + timer.clear(); + timer.start(); + + let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count()); + ppi_ch1.enable(); + + s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); + let mut ppi_group = PpiGroup::new(ppi_group); + let mut ppi_ch2 = Ppi::new_one_to_two( + ppi_ch2, + Event::from_reg(&r.events_endrx), + Task::from_reg(&r.tasks_startrx), + ppi_group.task_disable_all(), + ); + ppi_ch2.disable(); + ppi_group.add_channel(&ppi_ch2); + + Self { + _peri: peri, + timer, + _ppi_ch1: ppi_ch1, + _ppi_ch2: ppi_ch2, + _ppi_group: ppi_group, + } + } + /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. pub async fn read(&mut self, buf: &mut [u8]) -> Result { let data = self.fill_buf().await?; diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index cd14c718a..7fd34453a 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -299,7 +299,7 @@ impl<'d, T: Instance> Uarte<'d, T> { } } -fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) { +pub(crate) fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) { r.config.write(|w| { w.hwfc().bit(hardware_flow_control); w.parity().variant(config.parity); From 036f703a4a42ae67d2b0fdc6b5268ac04d5066f7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Feb 2024 23:38:51 +0100 Subject: [PATCH 531/760] nrf/uart: add buffereduart drop, rxonly, txonly tests. --- tests/nrf52840/src/bin/buffered_uart.rs | 87 ++++++++++--------- .../nrf52840/src/bin/buffered_uart_halves.rs | 82 +++++++++++++++++ 2 files changed, 127 insertions(+), 42 deletions(-) create mode 100644 tests/nrf52840/src/bin/buffered_uart_halves.rs diff --git a/tests/nrf52840/src/bin/buffered_uart.rs b/tests/nrf52840/src/bin/buffered_uart.rs index 721751136..a01d66d85 100644 --- a/tests/nrf52840/src/bin/buffered_uart.rs +++ b/tests/nrf52840/src/bin/buffered_uart.rs @@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_nrf::init(Default::default()); + let mut p = embassy_nrf::init(Default::default()); let mut config = uarte::Config::default(); config.parity = uarte::Parity::EXCLUDED; config.baudrate = uarte::Baudrate::BAUD1M; @@ -23,55 +23,58 @@ async fn main(_spawner: Spawner) { let mut tx_buffer = [0u8; 1024]; let mut rx_buffer = [0u8; 1024]; - let u = BufferedUarte::new( - p.UARTE0, - p.TIMER0, - p.PPI_CH0, - p.PPI_CH1, - p.PPI_GROUP0, - Irqs, - p.P1_03, - p.P1_02, - config.clone(), - &mut rx_buffer, - &mut tx_buffer, - ); + // test teardown + recreate of the buffereduarte works fine. + for _ in 0..2 { + let u = BufferedUarte::new( + &mut p.UARTE0, + &mut p.TIMER0, + &mut p.PPI_CH0, + &mut p.PPI_CH1, + &mut p.PPI_GROUP0, + Irqs, + &mut p.P1_03, + &mut p.P1_02, + config.clone(), + &mut rx_buffer, + &mut tx_buffer, + ); - info!("uarte initialized!"); + info!("uarte initialized!"); - let (mut rx, mut tx) = u.split(); + let (mut rx, mut tx) = u.split(); - const COUNT: usize = 40_000; + const COUNT: usize = 40_000; - let tx_fut = async { - let mut tx_buf = [0; 215]; - let mut i = 0; - while i < COUNT { - let n = tx_buf.len().min(COUNT - i); - let tx_buf = &mut tx_buf[..n]; - for (j, b) in tx_buf.iter_mut().enumerate() { - *b = (i + j) as u8; + let tx_fut = async { + let mut tx_buf = [0; 215]; + let mut i = 0; + while i < COUNT { + let n = tx_buf.len().min(COUNT - i); + let tx_buf = &mut tx_buf[..n]; + for (j, b) in tx_buf.iter_mut().enumerate() { + *b = (i + j) as u8; + } + let n = unwrap!(tx.write(tx_buf).await); + i += n; } - let n = unwrap!(tx.write(tx_buf).await); - i += n; - } - }; - let rx_fut = async { - let mut i = 0; - while i < COUNT { - let buf = unwrap!(rx.fill_buf().await); + }; + let rx_fut = async { + let mut i = 0; + while i < COUNT { + let buf = unwrap!(rx.fill_buf().await); - for &b in buf { - assert_eq!(b, i as u8); - i = i + 1; + for &b in buf { + assert_eq!(b, i as u8); + i = i + 1; + } + + let n = buf.len(); + rx.consume(n); } + }; - let n = buf.len(); - rx.consume(n); - } - }; - - join(rx_fut, tx_fut).await; + join(rx_fut, tx_fut).await; + } info!("Test OK"); cortex_m::asm::bkpt(); diff --git a/tests/nrf52840/src/bin/buffered_uart_halves.rs b/tests/nrf52840/src/bin/buffered_uart_halves.rs new file mode 100644 index 000000000..54a9fef5b --- /dev/null +++ b/tests/nrf52840/src/bin/buffered_uart_halves.rs @@ -0,0 +1,82 @@ +#![no_std] +#![no_main] +teleprobe_meta::target!(b"nrf52840-dk"); + +use defmt::{assert_eq, *}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_nrf::buffered_uarte::{self, BufferedUarteRx, BufferedUarteTx}; +use embassy_nrf::{bind_interrupts, peripherals, uarte}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + UARTE0_UART0 => buffered_uarte::InterruptHandler; + UARTE1 => buffered_uarte::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut p = embassy_nrf::init(Default::default()); + let mut config = uarte::Config::default(); + config.parity = uarte::Parity::EXCLUDED; + config.baudrate = uarte::Baudrate::BAUD1M; + + let mut tx_buffer = [0u8; 1024]; + let mut rx_buffer = [0u8; 1024]; + + // test teardown + recreate of the buffereduarte works fine. + for _ in 0..2 { + const COUNT: usize = 40_000; + + let mut tx = BufferedUarteTx::new(&mut p.UARTE1, Irqs, &mut p.P1_02, config.clone(), &mut tx_buffer); + + let mut rx = BufferedUarteRx::new( + &mut p.UARTE0, + &mut p.TIMER0, + &mut p.PPI_CH0, + &mut p.PPI_CH1, + &mut p.PPI_GROUP0, + Irqs, + &mut p.P1_03, + config.clone(), + &mut rx_buffer, + ); + + let tx_fut = async { + info!("tx initialized!"); + + let mut tx_buf = [0; 215]; + let mut i = 0; + while i < COUNT { + let n = tx_buf.len().min(COUNT - i); + let tx_buf = &mut tx_buf[..n]; + for (j, b) in tx_buf.iter_mut().enumerate() { + *b = (i + j) as u8; + } + let n = unwrap!(tx.write(tx_buf).await); + i += n; + } + }; + let rx_fut = async { + info!("rx initialized!"); + + let mut i = 0; + while i < COUNT { + let buf = unwrap!(rx.fill_buf().await); + + for &b in buf { + assert_eq!(b, i as u8); + i = i + 1; + } + + let n = buf.len(); + rx.consume(n); + } + }; + + join(rx_fut, tx_fut).await; + } + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From 6a977d2ae937c835401c46aad9f5cbe79962266f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 22 Feb 2024 00:07:09 +0100 Subject: [PATCH 532/760] nrf/uarte: prevent accidentally driving tx pin on rxonly uart if it was left in PSEL. --- embassy-nrf/src/uarte.rs | 60 +++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 7fd34453a..cbd5dccbc 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -159,7 +159,7 @@ impl<'d, T: Instance> Uarte<'d, T> { txd: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(rxd, txd); + into_ref!(uarte, rxd, txd); Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config) } @@ -173,7 +173,7 @@ impl<'d, T: Instance> Uarte<'d, T> { rts: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(rxd, txd, cts, rts); + into_ref!(uarte, rxd, txd, cts, rts); Self::new_inner( uarte, rxd.map_into(), @@ -185,17 +185,22 @@ impl<'d, T: Instance> Uarte<'d, T> { } fn new_inner( - uarte: impl Peripheral

+ 'd, + uarte: PeripheralRef<'d, T>, rxd: PeripheralRef<'d, AnyPin>, txd: PeripheralRef<'d, AnyPin>, cts: Option>, rts: Option>, config: Config, ) -> Self { - into_ref!(uarte); - let r = T::regs(); + let hardware_flow_control = match (rts.is_some(), cts.is_some()) { + (false, false) => false, + (true, true) => true, + _ => panic!("RTS and CTS pins must be either both set or none set."), + }; + configure(r, config, hardware_flow_control); + rxd.conf().write(|w| w.input().connect().drive().h0h1()); r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); @@ -217,13 +222,6 @@ impl<'d, T: Instance> Uarte<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - let hardware_flow_control = match (rts.is_some(), cts.is_some()) { - (false, false) => false, - (true, true) => true, - _ => panic!("RTS and CTS pins must be either both set or none set."), - }; - configure(r, config, hardware_flow_control); - let s = T::state(); s.tx_rx_refcount.store(2, Ordering::Relaxed); @@ -315,6 +313,12 @@ pub(crate) fn configure(r: &RegisterBlock, config: Config, hardware_flow_control r.events_rxstarted.reset(); r.events_txstarted.reset(); + // reset all pins + r.psel.txd.write(|w| w.connect().disconnected()); + r.psel.rxd.write(|w| w.connect().disconnected()); + r.psel.cts.write(|w| w.connect().disconnected()); + r.psel.rts.write(|w| w.connect().disconnected()); + // Enable apply_workaround_for_enable_anomaly(r); r.enable.write(|w| w.enable().enabled()); @@ -328,7 +332,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { txd: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(txd); + into_ref!(uarte, txd); Self::new_inner(uarte, txd.map_into(), None, config) } @@ -340,20 +344,20 @@ impl<'d, T: Instance> UarteTx<'d, T> { cts: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(txd, cts); + into_ref!(uarte, txd, cts); Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config) } fn new_inner( - uarte: impl Peripheral

+ 'd, + uarte: PeripheralRef<'d, T>, txd: PeripheralRef<'d, AnyPin>, cts: Option>, config: Config, ) -> Self { - into_ref!(uarte); - let r = T::regs(); + configure(r, config, cts.is_some()); + txd.set_high(); txd.conf().write(|w| w.dir().output().drive().s0s1()); r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); @@ -363,12 +367,6 @@ impl<'d, T: Instance> UarteTx<'d, T> { } r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); - r.psel.rxd.write(|w| w.connect().disconnected()); - r.psel.rts.write(|w| w.connect().disconnected()); - - let hardware_flow_control = cts.is_some(); - configure(r, config, hardware_flow_control); - T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -524,7 +522,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { rxd: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(rxd); + into_ref!(uarte, rxd); Self::new_inner(uarte, rxd.map_into(), None, config) } @@ -536,7 +534,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { rts: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(rxd, rts); + into_ref!(uarte, rxd, rts); Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) } @@ -549,15 +547,15 @@ impl<'d, T: Instance> UarteRx<'d, T> { } fn new_inner( - uarte: impl Peripheral

+ 'd, + uarte: PeripheralRef<'d, T>, rxd: PeripheralRef<'d, AnyPin>, rts: Option>, config: Config, ) -> Self { - into_ref!(uarte); - let r = T::regs(); + configure(r, config, rts.is_some()); + rxd.conf().write(|w| w.input().connect().drive().h0h1()); r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); @@ -567,15 +565,9 @@ impl<'d, T: Instance> UarteRx<'d, T> { } r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); - r.psel.txd.write(|w| w.connect().disconnected()); - r.psel.cts.write(|w| w.connect().disconnected()); - T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - let hardware_flow_control = rts.is_some(); - configure(r, config, hardware_flow_control); - let s = T::state(); s.tx_rx_refcount.store(1, Ordering::Relaxed); From 0c6d3ea05116c2798529ae68136f0e29f04f92e1 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 22 Feb 2024 06:05:51 -0500 Subject: [PATCH 533/760] Add SetConfig impl to rp2040 i2c Also expand test to cover 1kHz, 100kHz, 400kHz, and 1MHz speeds. --- embassy-rp/src/i2c.rs | 86 +++++++++++++++++++++++------------- tests/rp/Cargo.toml | 1 + tests/rp/src/bin/i2c.rs | 96 +++++++++++++++++++++++++---------------- 3 files changed, 115 insertions(+), 68 deletions(-) diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 74d015792..85636f5fe 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -43,6 +43,18 @@ pub enum Error { AddressReserved(u16), } +/// I2C Config error +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ConfigError { + /// Max i2c speed is 1MHz + FrequencyTooHigh, + /// The sys clock is too slow to support given frequency + ClockTooSlow, + /// The sys clock is too fast to support given frequency + ClockTooFast, +} + /// I2C config. #[non_exhaustive] #[derive(Copy, Clone)] @@ -365,37 +377,32 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { ) -> Self { into_ref!(_peri); - assert!(config.frequency <= 1_000_000); - assert!(config.frequency > 0); - - let p = T::regs(); - let reset = T::reset(); crate::reset::reset(reset); crate::reset::unreset_wait(reset); - p.ic_enable().write(|w| w.set_enable(false)); - - // Select controller mode & speed - p.ic_con().modify(|w| { - // Always use "fast" mode (<= 400 kHz, works fine for standard - // mode too) - w.set_speed(i2c::vals::Speed::FAST); - w.set_master_mode(true); - w.set_ic_slave_disable(true); - w.set_ic_restart_en(true); - w.set_tx_empty_ctrl(true); - }); - - // Set FIFO watermarks to 1 to make things simpler. This is encoded - // by a register value of 0. - p.ic_tx_tl().write(|w| w.set_tx_tl(0)); - p.ic_rx_tl().write(|w| w.set_rx_tl(0)); - // Configure SCL & SDA pins set_up_i2c_pin(&scl); set_up_i2c_pin(&sda); + let mut me = Self { phantom: PhantomData }; + + if let Err(e) = me.set_config_inner(&config) { + panic!("Error configuring i2c: {}", e); + } + + me + } + + fn set_config_inner(&mut self, config: &Config) -> Result<(), ConfigError> { + if config.frequency > 1_000_000 { + return Err(ConfigError::FrequencyTooHigh); + } + + let p = T::regs(); + + p.ic_enable().write(|w| w.set_enable(false)); + // Configure baudrate // There are some subtleties to I2C timing which we are completely @@ -407,11 +414,14 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low let hcnt = period - lcnt; // and 2/5 (40%) of the period high + warn!("cb:{} h:{:x} l:{:x}", clk_base, hcnt, lcnt); // Check for out-of-range divisors: - assert!(hcnt <= 0xffff); - assert!(lcnt <= 0xffff); - assert!(hcnt >= 8); - assert!(lcnt >= 8); + if hcnt > 0xffff || lcnt > 0xffff { + return Err(ConfigError::ClockTooFast); + } + if hcnt < 8 || lcnt < 8 { + return Err(ConfigError::ClockTooSlow); + } // Per I2C-bus specification a device in standard or fast mode must // internally provide a hold time of at least 300ns for the SDA @@ -424,14 +434,20 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { ((clk_base * 3) / 10_000_000) + 1 } else { // fast mode plus requires a clk_base > 32MHz - assert!(clk_base >= 32_000_000); + if clk_base <= 32_000_000 { + return Err(ConfigError::ClockTooSlow); + } // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't // fit in uint. Add 1 to avoid division truncation. ((clk_base * 3) / 25_000_000) + 1 }; - assert!(sda_tx_hold_count <= lcnt - 2); + /* + if sda_tx_hold_count <= lcnt - 2 { + return Err(ConfigError::HoldCountOutOfRange); + } + */ p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); @@ -440,10 +456,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { p.ic_sda_hold() .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); - // Enable I2C block p.ic_enable().write(|w| w.set_enable(true)); - Self { phantom: PhantomData } + Ok(()) } fn setup(addr: u16) -> Result<(), Error> { @@ -757,6 +772,15 @@ where } } +impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> { + type Config = Config; + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.set_config_inner(config) + } +} + /// Check if address is reserved. pub fn i2c_reserved_addr(addr: u16) -> bool { ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 46e1e9a5f..e67f2117d 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -14,6 +14,7 @@ embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } +embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal/"} cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } perf-client = { path = "../perf-client" } diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index a0aed1a42..153b37999 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs @@ -3,7 +3,10 @@ teleprobe_meta::target!(b"rpi-pico"); use defmt::{assert_eq, info, panic, unwrap}; -use embassy_executor::Executor; +use embassy_embedded_hal::SetConfig; +use embassy_executor::{Executor, Spawner}; +use embassy_rp::clocks::{PllConfig, XoscConfig}; +use embassy_rp::config::Config as rpConfig; use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_rp::peripherals::{I2C0, I2C1}; use embassy_rp::{bind_interrupts, i2c, i2c_slave}; @@ -13,7 +16,6 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _}; static mut CORE1_STACK: Stack<1024> = Stack::new(); -static EXECUTOR0: StaticCell = StaticCell::new(); static EXECUTOR1: StaticCell = StaticCell::new(); use crate::i2c::AbortReason; @@ -44,10 +46,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { Ok(x) => match x { i2c_slave::ReadStatus::Done => break, i2c_slave::ReadStatus::NeedMoreBytes => count += 1, - i2c_slave::ReadStatus::LeftoverBytes(x) => { - info!("tried to write {} extra bytes", x); - break; - } + i2c_slave::ReadStatus::LeftoverBytes(x) => panic!("tried to write {} extra bytes", x), }, Err(e) => match e { embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), @@ -92,6 +91,8 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { resp_buff[i] = i as u8; } dev.respond_to_read(&resp_buff).await.unwrap(); + // reset count for next round of tests + count = 0xD0; } x => panic!("Invalid Write Read {:x}", x), } @@ -104,8 +105,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { } } -#[embassy_executor::task] -async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) { +async fn controller_task(con: &mut i2c::I2c<'static, I2C0, i2c::Async>) { info!("Device start"); { @@ -179,33 +179,55 @@ async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) { info!("large write_read - OK") } - info!("Test OK"); - cortex_m::asm::bkpt(); -} - -#[cortex_m_rt::entry] -fn main() -> ! { - let p = embassy_rp::init(Default::default()); - info!("Hello World!"); - - let d_sda = p.PIN_19; - let d_scl = p.PIN_18; - let mut config = i2c_slave::Config::default(); - config.addr = DEV_ADDR as u16; - let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); - - spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { - let executor1 = EXECUTOR1.init(Executor::new()); - executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); - }); - - let executor0 = EXECUTOR0.init(Executor::new()); - - let c_sda = p.PIN_21; - let c_scl = p.PIN_20; - let mut config = i2c::Config::default(); - config.frequency = 5_000; - let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); - - executor0.run(|spawner| unwrap!(spawner.spawn(controller_task(controller)))); + #[embassy_executor::main] + async fn main(_core0_spawner: Spawner) { + let mut config = rpConfig::default(); + // Configure clk_sys to 48MHz to support 1kHz scl. + // In theory it can go lower, but we won't bother to test below 1kHz. + config.clocks.xosc = Some(XoscConfig { + hz: 12_000_000, + delay_multiplier: 128, + sys_pll: Some(PllConfig { + refdiv: 1, + fbdiv: 120, + post_div1: 6, + post_div2: 5, + }), + usb_pll: Some(PllConfig { + refdiv: 1, + fbdiv: 120, + post_div1: 6, + post_div2: 5, + }), + }); + + let p = embassy_rp::init(config); + info!("Hello World!"); + + let d_sda = p.PIN_19; + let d_scl = p.PIN_18; + let mut config = i2c_slave::Config::default(); + config.addr = DEV_ADDR as u16; + let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); + + spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); + }); + + let c_sda = p.PIN_21; + let c_scl = p.PIN_20; + let mut controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, Default::default()); + + for freq in [1000, 100_000, 400_000, 1_000_000] { + info!("testing at {}hz", freq); + let mut config = i2c::Config::default(); + config.frequency = freq; + controller.set_config(&config).unwrap(); + controller_task(&mut controller).await; + } + + info!("Test OK"); + cortex_m::asm::bkpt(); + } } From 5ddee8586a3d98b4996278fefc1ef047f1367280 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 22 Feb 2024 06:12:41 -0500 Subject: [PATCH 534/760] rp2040 i2c_slave improvements Fix race condition that appears on fast repeated transfers. Add public reset function. Because application code can stall the bus, we need to give application code a way to fix itself. --- embassy-rp/src/i2c_slave.rs | 117 ++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 979686627..caebb0257 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -83,6 +83,7 @@ impl Default for Config { pub struct I2cSlave<'d, T: Instance> { phantom: PhantomData<&'d mut T>, pending_byte: Option, + config: Config, } impl<'d, T: Instance> I2cSlave<'d, T> { @@ -99,6 +100,25 @@ impl<'d, T: Instance> I2cSlave<'d, T> { assert!(!i2c_reserved_addr(config.addr)); assert!(config.addr != 0); + // Configure SCL & SDA pins + set_up_i2c_pin(&scl); + set_up_i2c_pin(&sda); + + let mut ret = Self { + phantom: PhantomData, + pending_byte: None, + config, + }; + + ret.reset(); + + ret + } + + /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus. + /// You can recover the bus by calling this function, but doing so will almost certainly cause + /// an i/o error in the master. + pub fn reset(&mut self) { let p = T::regs(); let reset = T::reset(); @@ -107,7 +127,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { p.ic_enable().write(|w| w.set_enable(false)); - p.ic_sar().write(|w| w.set_ic_sar(config.addr)); + p.ic_sar().write(|w| w.set_ic_sar(self.config.addr)); p.ic_con().modify(|w| { w.set_master_mode(false); w.set_ic_slave_disable(false); @@ -121,10 +141,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> { // Generate stop interrupts for general calls // This also causes stop interrupts for other devices on the bus but those will not be // propagated up to the application. - w.set_stop_det_ifaddressed(!config.general_call); + w.set_stop_det_ifaddressed(!self.config.general_call); }); p.ic_ack_general_call() - .write(|w| w.set_ack_gen_call(config.general_call)); + .write(|w| w.set_ack_gen_call(self.config.general_call)); // Set FIFO watermarks to 1 to make things simpler. This is encoded // by a register value of 0. Rx watermark should never change, but Tx watermark will be @@ -132,10 +152,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { p.ic_tx_tl().write(|w| w.set_tx_tl(0)); p.ic_rx_tl().write(|w| w.set_rx_tl(0)); - // Configure SCL & SDA pins - set_up_i2c_pin(&scl); - set_up_i2c_pin(&sda); - // Clear interrupts p.ic_clr_intr().read(); @@ -146,11 +162,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - - Self { - phantom: PhantomData, - pending_byte: None, - } } /// Calls `f` to check if we are ready or not. @@ -178,15 +189,13 @@ impl<'d, T: Instance> I2cSlave<'d, T> { fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) { let p = T::regs(); - for b in &mut buffer[*offset..] { - if let Some(pending) = self.pending_byte.take() { - *b = pending; - *offset += 1; - continue; - } + if let Some(pending) = self.pending_byte.take() { + buffer[*offset] = pending; + *offset += 1; + } - let status = p.ic_status().read(); - if !status.rfne() { + for b in &mut buffer[*offset..] { + if !p.ic_status().read().rfne() { break; } @@ -207,14 +216,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { } } - #[inline(always)] - fn write_to_fifo(&mut self, buffer: &[u8]) { - let p = T::regs(); - for byte in buffer { - p.ic_data_cmd().write(|w| w.set_dat(*byte)); - } - } - /// Wait asynchronously for commands from an I2C master. /// `buffer` is provided in case master does a 'write', 'write read', or 'general call' and is unused for 'read'. pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { @@ -227,8 +228,9 @@ impl<'d, T: Instance> I2cSlave<'d, T> { self.wait_on( |me| { let stat = p.ic_raw_intr_stat().read(); + trace!("ls:{:013b} len:{}", stat.0, len); - if p.ic_rxflr().read().rxflr() > 0 { + if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() { me.drain_fifo(buffer, &mut len); // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise p.ic_rx_tl().write(|w| w.set_rx_tl(11)); @@ -241,6 +243,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> { return Poll::Ready(Err(Error::PartialWrite(buffer.len()))); } } + trace!("len:{}, pend:{}", len, me.pending_byte); + if me.pending_byte.is_some() { + warn!("pending") + } if stat.restart_det() && stat.rd_req() { p.ic_clr_restart_det().read(); @@ -257,12 +263,17 @@ impl<'d, T: Instance> I2cSlave<'d, T> { p.ic_clr_restart_det().read(); p.ic_clr_gen_call().read(); Poll::Ready(Ok(Command::Read)) + } else if stat.stop_det() { + // clear stuck stop bit + // This can happen if the SDA/SCL pullups are enabled after calling this func + p.ic_clr_stop_det().read(); + Poll::Pending } else { Poll::Pending } }, |_me| { - p.ic_intr_mask().modify(|w| { + p.ic_intr_mask().write(|w| { w.set_m_stop_det(true); w.set_m_restart_det(true); w.set_m_gen_call(true); @@ -286,27 +297,30 @@ impl<'d, T: Instance> I2cSlave<'d, T> { self.wait_on( |me| { - if let Err(abort_reason) = me.read_and_clear_abort_reason() { - if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { - p.ic_clr_intr().read(); - return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); - } else { - return Poll::Ready(Err(abort_reason)); + let stat = p.ic_raw_intr_stat().read(); + trace!("rs:{:013b}", stat.0); + + if stat.tx_abrt() { + if let Err(abort_reason) = me.read_and_clear_abort_reason() { + if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { + p.ic_clr_intr().read(); + return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); + } else { + return Poll::Ready(Err(abort_reason)); + } } } if let Some(chunk) = chunks.next() { - me.write_to_fifo(chunk); - - p.ic_clr_rd_req().read(); + for byte in chunk { + p.ic_clr_rd_req().read(); + p.ic_data_cmd().write(|w| w.set_dat(*byte)); + } Poll::Pending } else { - let stat = p.ic_raw_intr_stat().read(); - - if stat.rx_done() && stat.stop_det() { + if stat.rx_done() { p.ic_clr_rx_done().read(); - p.ic_clr_stop_det().read(); Poll::Ready(Ok(ReadStatus::Done)) } else if stat.rd_req() && stat.tx_empty() { Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) @@ -316,11 +330,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> { } }, |_me| { - p.ic_intr_mask().modify(|w| { - w.set_m_stop_det(true); - w.set_m_rx_done(true); + p.ic_intr_mask().write(|w| { w.set_m_tx_empty(true); w.set_m_tx_abrt(true); + w.set_m_rx_done(true); }) }, ) @@ -329,9 +342,14 @@ impl<'d, T: Instance> I2cSlave<'d, T> { /// Respond to reads with the fill byte until the controller stops asking pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { + // Send fill bytes a full fifo at a time, to reduce interrupt noise. + // This does mean we'll almost certainly abort the write, but since these are fill bytes, + // we don't care. + let buff = [fill; FIFO_SIZE as usize]; loop { - match self.respond_to_read(&[fill]).await { + match self.respond_to_read(&buff).await { Ok(ReadStatus::NeedMoreBytes) => (), + Ok(ReadStatus::LeftoverBytes(_)) => break Ok(()), Ok(_) => break Ok(()), Err(e) => break Err(e), } @@ -353,10 +371,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { #[inline(always)] fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { let p = T::regs(); - let mut abort_reason = p.ic_tx_abrt_source().read(); - - // Mask off master_dis - abort_reason.set_abrt_master_dis(false); + let abort_reason = p.ic_tx_abrt_source().read(); if abort_reason.0 != 0 { // Note clearing the abort flag also clears the reason, and this From 89986fe967da4b1f94c57a11e57928b574536c92 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 22 Feb 2024 06:21:40 -0500 Subject: [PATCH 535/760] Fixup display -> debug --- embassy-rp/src/i2c.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 85636f5fe..3b74d8501 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -388,7 +388,7 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { let mut me = Self { phantom: PhantomData }; if let Err(e) = me.set_config_inner(&config) { - panic!("Error configuring i2c: {}", e); + panic!("Error configuring i2c: {:?}", e); } me From 25bff1d0b946a59d099aec88917759340124c931 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 22 Feb 2024 06:34:58 -0500 Subject: [PATCH 536/760] Fixup comments from James --- embassy-rp/src/i2c.rs | 8 +++----- embassy-rp/src/i2c_slave.rs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 3b74d8501..ac0eac96d 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -414,7 +414,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low let hcnt = period - lcnt; // and 2/5 (40%) of the period high - warn!("cb:{} h:{:x} l:{:x}", clk_base, hcnt, lcnt); // Check for out-of-range divisors: if hcnt > 0xffff || lcnt > 0xffff { return Err(ConfigError::ClockTooFast); @@ -443,11 +442,10 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { // fit in uint. Add 1 to avoid division truncation. ((clk_base * 3) / 25_000_000) + 1 }; - /* - if sda_tx_hold_count <= lcnt - 2 { - return Err(ConfigError::HoldCountOutOfRange); + + if sda_tx_hold_count > lcnt - 2 { + return Err(ConfigError::ClockTooSlow); } - */ p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index caebb0257..e1441947f 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -331,9 +331,9 @@ impl<'d, T: Instance> I2cSlave<'d, T> { }, |_me| { p.ic_intr_mask().write(|w| { + w.set_m_rx_done(true); w.set_m_tx_empty(true); w.set_m_tx_abrt(true); - w.set_m_rx_done(true); }) }, ) From f1bf9319202635ddf1d271bb4d0480afffffbe38 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 22 Feb 2024 06:40:39 -0500 Subject: [PATCH 537/760] fixup another display -> debug --- embassy-rp/src/i2c_slave.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index e1441947f..97ca17295 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -243,7 +243,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { return Poll::Ready(Err(Error::PartialWrite(buffer.len()))); } } - trace!("len:{}, pend:{}", len, me.pending_byte); + trace!("len:{}, pend:{:?}", len, me.pending_byte); if me.pending_byte.is_some() { warn!("pending") } From 5d2ccc8fa78af78d905c2593306d80f0f621f3bb Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Thu, 22 Feb 2024 13:14:39 +0000 Subject: [PATCH 538/760] adc: basic H5 support --- embassy-stm32/src/adc/mod.rs | 6 +- embassy-stm32/src/adc/resolution.rs | 8 +- embassy-stm32/src/adc/sample_time.rs | 2 +- embassy-stm32/src/adc/v3.rs | 123 ++++++++++++++++++--------- 4 files changed, 93 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 51b4b5fcc..b273c6394 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -10,7 +10,7 @@ #[cfg_attr(adc_v1, path = "v1.rs")] #[cfg_attr(adc_l0, path = "v1.rs")] #[cfg_attr(adc_v2, path = "v2.rs")] -#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] +#[cfg_attr(any(adc_v3, adc_g0, adc_h5), path = "v3.rs")] #[cfg_attr(adc_v4, path = "v4.rs")] mod _version; @@ -79,10 +79,10 @@ pub(crate) mod sealed { } /// 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)))] +#[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)))] pub trait Instance: sealed::Instance + crate::Peripheral

{} /// ADC instance. -#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] +#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5))] pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} /// ADC pin. diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 0e6c45c65..37788cd77 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -1,6 +1,6 @@ /// ADC resolution #[allow(missing_docs)] -#[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] +#[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Resolution { @@ -25,7 +25,7 @@ pub enum Resolution { impl Default for Resolution { fn default() -> Self { - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] { Self::TwelveBit } @@ -46,7 +46,7 @@ impl From for crate::pac::adc::vals::Res { Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, } } @@ -65,7 +65,7 @@ impl Resolution { Resolution::TwelveBit => (1 << 12) - 1, Resolution::TenBit => (1 << 10) - 1, Resolution::EightBit => (1 << 8) - 1, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] Resolution::SixBit => (1 << 6) - 1, } } diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index f4b22b462..19bc22938 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs @@ -67,7 +67,7 @@ impl_sample_time!( ) ); -#[cfg(adc_v3)] +#[cfg(any(adc_v3, adc_h5))] impl_sample_time!( "2.5", Cycles2_5, diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 281a99f72..0c44e4400 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,3 +1,4 @@ +use cfg_if::cfg_if; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; @@ -13,10 +14,15 @@ pub struct VrefInt; impl AdcPin for VrefInt {} impl super::sealed::AdcPin for VrefInt { fn channel(&self) -> u8 { - #[cfg(not(adc_g0))] - let val = 0; - #[cfg(adc_g0)] - let val = 13; + cfg_if! { + if #[cfg(adc_g0)] { + let val = 13; + } else if #[cfg(adc_h5)] { + let val = 17; + } else { + let val = 0; + } + } val } } @@ -25,10 +31,15 @@ pub struct Temperature; impl AdcPin for Temperature {} impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { - #[cfg(not(adc_g0))] - let val = 17; - #[cfg(adc_g0)] - let val = 12; + cfg_if! { + if #[cfg(adc_g0)] { + let val = 12; + } else if #[cfg(adc_h5)] { + let val = 16; + } else { + let val = 17; + } + } val } } @@ -37,14 +48,31 @@ pub struct Vbat; impl AdcPin for Vbat {} impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { - #[cfg(not(adc_g0))] - let val = 18; - #[cfg(adc_g0)] - let val = 14; + cfg_if! { + if #[cfg(adc_g0)] { + let val = 14; + } else if #[cfg(adc_h5)] { + let val = 2; + } else { + let val = 18; + } + } val } } +cfg_if! { + if #[cfg(adc_h5)] { + pub struct VddCore; + impl AdcPin for VddCore {} + impl super::sealed::AdcPin for VddCore { + fn channel(&self) -> u8 { + 6 + } + } + } +} + impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { into_ref!(adc); @@ -98,27 +126,41 @@ impl<'d, T: Instance> Adc<'d, T> { } pub fn enable_temperature(&self) -> Temperature { - #[cfg(not(adc_g0))] - T::common_regs().ccr().modify(|reg| { - reg.set_ch17sel(true); - }); - #[cfg(adc_g0)] - T::regs().ccr().modify(|reg| { - reg.set_tsen(true); - }); + cfg_if! { + if #[cfg(adc_g0)] { + T::regs().ccr().modify(|reg| { + reg.set_tsen(true); + }); + } else if #[cfg(adc_h5)] { + T::common_regs().ccr().modify(|reg| { + reg.set_tsen(true); + }); + } else { + T::common_regs().ccr().modify(|reg| { + reg.set_ch17sel(true); + }); + } + } Temperature {} } pub fn enable_vbat(&self) -> Vbat { - #[cfg(not(adc_g0))] - T::common_regs().ccr().modify(|reg| { - reg.set_ch18sel(true); - }); - #[cfg(adc_g0)] - T::regs().ccr().modify(|reg| { - reg.set_vbaten(true); - }); + cfg_if! { + if #[cfg(adc_g0)] { + T::regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); + } else if #[cfg(adc_h5)] { + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); + } else { + T::common_regs().ccr().modify(|reg| { + reg.set_ch18sel(true); + }); + } + } Vbat {} } @@ -205,16 +247,21 @@ impl<'d, T: Instance> Adc<'d, T> { val } - #[cfg(adc_g0)] fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { - T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); - } - - #[cfg(not(adc_g0))] - fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { - let sample_time = sample_time.into(); - T::regs() - .smpr(ch as usize / 10) - .modify(|reg| reg.set_smp(ch as usize % 10, sample_time)); + cfg_if! { + if #[cfg(adc_g0)] { + T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); + } else if #[cfg(adc_h5)] { + match _ch { + 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), + _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), + } + } else { + let sample_time = sample_time.into(); + T::regs() + .smpr(ch as usize / 10) + .modify(|reg| reg.set_smp(ch as usize % 10, sample_time)); + } + } } } From 475dea0208954453f935ddb8713fcf9155d3bd22 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 23 Feb 2024 00:18:24 +0100 Subject: [PATCH 539/760] stm32/rcc: workaround nonsense RAM suicide errata on backup domain reset. --- embassy-stm32/src/rcc/bd.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index d20f58185..cb10a9a3f 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -201,11 +201,18 @@ impl LsConfig { bdcr().modify(|w| w.set_bdrst(true)); bdcr().modify(|w| w.set_bdrst(false)); } - #[cfg(any(stm32h5))] - { - bdcr().modify(|w| w.set_vswrst(true)); - bdcr().modify(|w| w.set_vswrst(false)); - } + // H5 has a terrible, terrible errata: 'SRAM2 is erased when the backup domain is reset' + // pending a more sane sane way to handle this, just don't reset BD for now. + // This means the RTCSEL write below will have no effect, only if it has already been written + // after last power-on. Since it's uncommon to dynamically change RTCSEL, this is better than + // letting half our RAM go magically *poof*. + // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset + // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset + //#[cfg(any(stm32h5))] + //{ + // bdcr().modify(|w| w.set_vswrst(true)); + // bdcr().modify(|w| w.set_vswrst(false)); + //} #[cfg(any(stm32c0))] { bdcr().modify(|w| w.set_rtcrst(true)); From 0665e0d452627b5fe3c0b52981c7f4ef380de83f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 23 Feb 2024 01:22:11 +0100 Subject: [PATCH 540/760] stm32/rcc: port U5 to new API, add all PLLs, all HSE modes. --- embassy-stm32/src/rcc/u5.rs | 637 +++++++++++-------------- examples/stm32u5/src/bin/usb_serial.rs | 27 +- tests/stm32/src/common.rs | 13 +- 3 files changed, 314 insertions(+), 363 deletions(-) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 20cc3112a..72613f0f3 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -1,134 +1,83 @@ -pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; -use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; +pub use crate::pac::pwr::vals::Vos as VoltageScale; +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, + Pllsrc as PllSource, Ppre as APBPrescaler, Sw as ClockSrc, +}; +use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; use crate::pac::{FLASH, PWR, RCC}; use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(16_000_000); -pub use crate::pac::pwr::vals::Vos as VoltageScale; - -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -pub enum ClockSrc { - /// Use an internal medium speed oscillator (MSIS) as the system clock. - MSI(Msirange), - /// Use the external high speed clock as the system clock. - /// - /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must - /// never exceed 50 MHz. - HSE(Hertz), - /// Use the 16 MHz internal high speed oscillator as the system clock. - HSI, - /// Use PLL1 as the system clock. - PLL1_R(PllConfig), +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) + Bypass, + /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) + BypassDigital, } -impl Default for ClockSrc { - fn default() -> Self { - // The default system clock source is MSIS @ 4 MHz, per RM0456 § 11.4.9 - ClockSrc::MSI(Msirange::RANGE_4MHZ) - } +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, } #[derive(Clone, Copy)] -pub struct PllConfig { +pub struct Pll { /// The clock source for the PLL. pub source: PllSource, - /// The PLL prescaler. + /// The PLL pre-divider. /// /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz. - pub m: Pllm, + pub prediv: PllPreDiv, /// The PLL multiplier. /// /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. - pub n: Plln, + pub mul: PllMul, /// The divider for the P output. /// /// The P output is one of several options /// that can be used to feed the SAI/MDF/ADF Clock mux's. - pub p: Plldiv, + pub divp: Option, /// The divider for the Q output. /// /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. - pub q: Plldiv, + pub divq: Option, /// The divider for the R output. /// /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default /// `Config { voltage_range }`. - pub r: Plldiv, -} - -impl PllConfig { - /// A configuration for HSI / 1 * 10 / 1 = 160 MHz - pub const fn hsi_160mhz() -> Self { - PllConfig { - source: PllSource::HSI, - m: Pllm::DIV1, - n: Plln::MUL10, - p: Plldiv::DIV3, - q: Plldiv::DIV2, - r: Plldiv::DIV1, - } - } - - /// A configuration for MSIS @ 48 MHz / 3 * 10 / 1 = 160 MHz - pub const fn msis_160mhz() -> Self { - PllConfig { - source: PllSource::MSIS(Msirange::RANGE_48MHZ), - m: Pllm::DIV3, - n: Plln::MUL10, - p: Plldiv::DIV3, - q: Plldiv::DIV2, - r: Plldiv::DIV1, - } - } -} - -#[derive(Clone, Copy)] -pub enum PllSource { - /// Use an internal medium speed oscillator as the PLL source. - MSIS(Msirange), - /// Use the external high speed clock as the system PLL source. - /// - /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must - /// never exceed 50 MHz. - HSE(Hertz), - /// Use the 16 MHz internal high speed oscillator as the PLL source. - HSI, -} - -impl Into for PllSource { - fn into(self) -> Pllsrc { - match self { - PllSource::MSIS(..) => Pllsrc::MSIS, - PllSource::HSE(..) => Pllsrc::HSE, - PllSource::HSI => Pllsrc::HSI, - } - } -} - -impl Into for ClockSrc { - fn into(self) -> Sw { - match self { - ClockSrc::MSI(..) => Sw::MSIS, - ClockSrc::HSE(..) => Sw::HSE, - ClockSrc::HSI => Sw::HSI, - ClockSrc::PLL1_R(..) => Sw::PLL1_R, - } - } + pub divr: Option, } pub struct Config { + // base clock sources + pub msi: Option, + pub hsi: bool, + pub hse: Option, + pub hsi48: Option, + + // pll + pub pll1: Option, + pub pll2: Option, + pub pll3: Option, + + // sysclk, buses. pub mux: ClockSrc, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, pub apb3_pre: APBPrescaler, - pub hsi48: Option, + /// The voltage range influences the maximum clock frequencies for different parts of the /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks /// exceeding 55 MHz require at least `RANGE2`. @@ -138,35 +87,35 @@ pub struct Config { pub ls: super::LsConfig, } -impl Config { - unsafe fn init_hsi(&self) -> Hertz { - RCC.cr().write(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - - HSI_FREQ - } - - unsafe fn init_hse(&self, frequency: Hertz) -> Hertz { - // Check frequency limits per RM456 § 11.4.10 - match self.voltage_range { - VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { - assert!(frequency.0 <= 50_000_000); - } - VoltageScale::RANGE4 => { - assert!(frequency.0 <= 25_000_000); - } +impl Default for Config { + fn default() -> Self { + Self { + msi: Some(Msirange::RANGE_4MHZ), + hse: None, + hsi: false, + hsi48: Some(Default::default()), + pll1: None, + pll2: None, + pll3: None, + mux: ClockSrc::MSIS, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb3_pre: APBPrescaler::DIV1, + voltage_range: VoltageScale::RANGE1, + ls: Default::default(), } - - // Enable HSE, and wait for it to stabilize - RCC.cr().write(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - - frequency } +} - unsafe fn init_msis(&self, range: Msirange) -> Hertz { +pub(crate) unsafe fn init(config: Config) { + // Set the requested power mode + PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); + while !PWR.vosr().read().vosrdy() {} + + let msi = config.msi.map(|range| { // Check MSI output per RM0456 § 11.4.10 - match self.voltage_range { + match config.voltage_range { VoltageScale::RANGE4 => { assert!(msirange_to_hertz(range).0 <= 24_000_000); } @@ -191,223 +140,98 @@ impl Config { }); while !RCC.cr().read().msisrdy() {} msirange_to_hertz(range) - } -} - -impl Default for Config { - fn default() -> Self { - Self { - mux: ClockSrc::default(), - ahb_pre: AHBPrescaler::DIV1, - apb1_pre: APBPrescaler::DIV1, - apb2_pre: APBPrescaler::DIV1, - apb3_pre: APBPrescaler::DIV1, - hsi48: Some(Default::default()), - voltage_range: VoltageScale::RANGE3, - ls: Default::default(), - } - } -} - -pub(crate) unsafe fn init(config: Config) { - // Ensure PWR peripheral clock is enabled - RCC.ahb3enr().modify(|w| { - w.set_pwren(true); }); - RCC.ahb3enr().read(); // synchronize - // Set the requested power mode - PWR.vosr().modify(|w| { - w.set_vos(config.voltage_range); + let hsi = config.hsi.then(|| { + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + HSI_FREQ }); - while !PWR.vosr().read().vosrdy() {} - let sys_clk = match config.mux { - ClockSrc::MSI(range) => config.init_msis(range), - ClockSrc::HSE(freq) => config.init_hse(freq), - ClockSrc::HSI => config.init_hsi(), - ClockSrc::PLL1_R(pll) => { - // Configure the PLL source - let source_clk = match pll.source { - PllSource::MSIS(range) => config.init_msis(range), - PllSource::HSE(hertz) => config.init_hse(hertz), - PllSource::HSI => config.init_hsi(), - }; - - // Calculate the reference clock, which is the source divided by m - let reference_clk = source_clk / pll.m; - - // Check limits per RM0456 § 11.4.6 - assert!(Hertz::mhz(4) <= reference_clk && reference_clk <= Hertz::mhz(16)); - - // Calculate the PLL1 VCO clock and PLL1 R output clock - let pll1_clk = reference_clk * pll.n; - let pll1r_clk = pll1_clk / pll.r; - - // Check system clock per RM0456 § 11.4.9 - assert!(pll1r_clk <= Hertz::mhz(160)); - - // Check PLL clocks per RM0456 § 11.4.10 - match config.voltage_range { - VoltageScale::RANGE1 => { - assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544)); - assert!(pll1r_clk <= Hertz::mhz(208)); - } - VoltageScale::RANGE2 => { - assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544)); - assert!(pll1r_clk <= Hertz::mhz(110)); - } - VoltageScale::RANGE3 => { - assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(330)); - assert!(pll1r_clk <= Hertz::mhz(55)); - } - VoltageScale::RANGE4 => { - panic!("PLL is unavailable in voltage range 4"); - } + let hse = config.hse.map(|hse| { + // Check frequency limits per RM456 § 11.4.10 + match config.voltage_range { + VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { + assert!(hse.freq.0 <= 50_000_000); } - - // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler - // value that results in an output between 4 and 16 MHz for the PWR EPOD boost - let mboost = if pll1r_clk >= Hertz::mhz(55) { - // source_clk can be up to 50 MHz, so there's just a few cases: - if source_clk > Hertz::mhz(32) { - // Divide by 4, giving EPOD 8-12.5 MHz - Pllmboost::DIV4 - } else if source_clk > Hertz::mhz(16) { - // Divide by 2, giving EPOD 8-16 MHz - Pllmboost::DIV2 - } else { - // Bypass, giving EPOD 4-16 MHz - Pllmboost::DIV1 - } - } else { - // Nothing to do - Pllmboost::DIV1 - }; - - // Disable the PLL, and wait for it to disable - RCC.cr().modify(|w| w.set_pllon(0, false)); - while RCC.cr().read().pllrdy(0) {} - - // Configure the PLL - RCC.pll1cfgr().write(|w| { - // Configure PLL1 source and prescaler - w.set_pllsrc(pll.source.into()); - w.set_pllm(pll.m); - - // Configure PLL1 input frequncy range - let input_range = if reference_clk <= Hertz::mhz(8) { - Pllrge::FREQ_4TO8MHZ - } else { - Pllrge::FREQ_8TO16MHZ - }; - w.set_pllrge(input_range); - - // Set the prescaler for PWR EPOD - w.set_pllmboost(mboost); - - // Enable PLL1_R output - w.set_pllren(true); - }); - - // Configure the PLL divisors - RCC.pll1divr().modify(|w| { - // Set the VCO multiplier - w.set_plln(pll.n); - w.set_pllp(pll.p); - w.set_pllq(pll.q); - // Set the R output divisor - w.set_pllr(pll.r); - }); - - // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? - if pll1r_clk >= Hertz::mhz(55) { - // Enable the booster - PWR.vosr().modify(|w| { - w.set_boosten(true); - }); - while !PWR.vosr().read().boostrdy() {} + VoltageScale::RANGE4 => { + assert!(hse.freq.0 <= 25_000_000); } - - // Enable the PLL - RCC.cr().modify(|w| w.set_pllon(0, true)); - while !RCC.cr().read().pllrdy(0) {} - - pll1r_clk } - }; + + // Enable HSE, and wait for it to stabilize + RCC.cr().write(|w| { + w.set_hseon(true); + w.set_hsebyp(hse.mode != HseMode::Oscillator); + w.set_hseext(match hse.mode { + HseMode::Oscillator | HseMode::Bypass => Hseext::ANALOG, + HseMode::BypassDigital => Hseext::DIGITAL, + }); + }); + while !RCC.cr().read().hserdy() {} + + hse.freq + }); let hsi48 = config.hsi48.map(super::init_hsi48); + let pll_input = PllInput { hse, hsi, msi }; + let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range); + let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); + let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range); + + let sys_clk = match config.mux { + ClockSrc::HSE => hse.unwrap(), + ClockSrc::HSI => hsi.unwrap(), + ClockSrc::MSIS => msi.unwrap(), + ClockSrc::PLL1_R => pll1.r.unwrap(), + }; + + // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? + if sys_clk >= Hertz::mhz(55) { + // Enable the booster + PWR.vosr().modify(|w| w.set_boosten(true)); + while !PWR.vosr().read().boostrdy() {} + } + // The clock source is ready // Calculate and set the flash wait states let wait_states = match config.voltage_range { // VOS 1 range VCORE 1.26V - 1.40V - VoltageScale::RANGE1 => { - if sys_clk.0 < 32_000_000 { - 0 - } else if sys_clk.0 < 64_000_000 { - 1 - } else if sys_clk.0 < 96_000_000 { - 2 - } else if sys_clk.0 < 128_000_000 { - 3 - } else { - 4 - } - } + VoltageScale::RANGE1 => match sys_clk.0 { + ..=32_000_000 => 0, + ..=64_000_000 => 1, + ..=96_000_000 => 2, + ..=128_000_000 => 3, + _ => 4, + }, // VOS 2 range VCORE 1.15V - 1.26V - VoltageScale::RANGE2 => { - if sys_clk.0 < 30_000_000 { - 0 - } else if sys_clk.0 < 60_000_000 { - 1 - } else if sys_clk.0 < 90_000_000 { - 2 - } else { - 3 - } - } + VoltageScale::RANGE2 => match sys_clk.0 { + ..=30_000_000 => 0, + ..=60_000_000 => 1, + ..=90_000_000 => 2, + _ => 3, + }, // VOS 3 range VCORE 1.05V - 1.15V - VoltageScale::RANGE3 => { - if sys_clk.0 < 24_000_000 { - 0 - } else if sys_clk.0 < 48_000_000 { - 1 - } else { - 2 - } - } + VoltageScale::RANGE3 => match sys_clk.0 { + ..=24_000_000 => 0, + ..=48_000_000 => 1, + _ => 2, + }, // VOS 4 range VCORE 0.95V - 1.05V - VoltageScale::RANGE4 => { - if sys_clk.0 < 12_000_000 { - 0 - } else { - 1 - } - } + VoltageScale::RANGE4 => match sys_clk.0 { + ..=12_000_000 => 0, + _ => 1, + }, }; FLASH.acr().modify(|w| { w.set_latency(wait_states); }); // Switch the system clock source - RCC.cfgr1().modify(|w| { - w.set_sw(config.mux.into()); - }); - - // RM0456 § 11.4.9 specifies maximum bus frequencies per voltage range, but the maximum bus - // frequency for each voltage range exactly matches the maximum permitted PLL output frequency. - // Given that: - // - // 1. Any bus frequency can never exceed the system clock frequency; - // 2. We checked the PLL output frequency if we're using it as a system clock; - // 3. The maximum HSE frequencies at each voltage range are lower than the bus limits, and - // we checked the HSE frequency if configured as a system clock; and - // 4. The maximum frequencies from the other clock sources are lower than the lowest bus - // frequency limit - // - // ...then we do not need to perform additional bus-related frequency checks. + RCC.cfgr1().modify(|w| w.set_sw(config.mux)); + while RCC.cfgr1().read().sws() != config.mux {} // Configure the bus prescalers RCC.cfgr2().modify(|w| { @@ -419,64 +243,52 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre3(config.apb3_pre); }); - let ahb_freq = sys_clk / config.ahb_pre; + let hclk = sys_clk / config.ahb_pre; - let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } + let hclk_max = match config.voltage_range { + VoltageScale::RANGE1 => Hertz::mhz(160), + VoltageScale::RANGE2 => Hertz::mhz(110), + VoltageScale::RANGE3 => Hertz::mhz(55), + VoltageScale::RANGE4 => Hertz::mhz(25), }; + assert!(hclk <= hclk_max); - let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } - }; - - let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } - }; + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); + let (pclk3, _) = super::util::calc_pclk(hclk, config.apb3_pre); let rtc = config.ls.init(); set_clocks!( sys: Some(sys_clk), - hclk1: Some(ahb_freq), - hclk2: Some(ahb_freq), - hclk3: Some(ahb_freq), - pclk1: Some(apb1_freq), - pclk2: Some(apb2_freq), - pclk3: Some(apb3_freq), - pclk1_tim: Some(apb1_tim_freq), - pclk2_tim: Some(apb2_tim_freq), + hclk1: Some(hclk), + hclk2: Some(hclk), + hclk3: Some(hclk), + pclk1: Some(pclk1), + pclk2: Some(pclk2), + pclk3: Some(pclk3), + pclk1_tim: Some(pclk1_tim), + pclk2_tim: Some(pclk2_tim), hsi48: hsi48, rtc: rtc, + hse: hse, + hsi: hsi, + pll1_p: pll1.p, + pll1_q: pll1.q, + pll1_r: pll1.r, + pll2_p: pll2.p, + pll2_q: pll2.q, + pll2_r: pll2.r, + pll3_p: pll3.p, + pll3_q: pll3.q, + pll3_r: pll3.r, // TODO - hse: None, - hsi: None, audioclk: None, hsi48_div_2: None, lse: None, lsi: None, msik: None, - pll1_p: None, - pll1_q: None, - pll1_r: None, - pll2_p: None, - pll2_q: None, - pll2_r: None, - pll3_p: None, - pll3_q: None, - pll3_r: None, iclk: None, ); } @@ -501,3 +313,126 @@ fn msirange_to_hertz(range: Msirange) -> Hertz { Msirange::RANGE_100KHZ => Hertz(100_000), } } + +pub(super) struct PllInput { + pub hsi: Option, + pub hse: Option, + pub msi: Option, +} + +#[allow(unused)] +#[derive(Default)] +pub(super) struct PllOutput { + pub p: Option, + pub q: Option, + pub r: Option, +} + +#[derive(PartialEq, Eq, Clone, Copy)] +enum PllInstance { + Pll1 = 0, + Pll2 = 1, + Pll3 = 2, +} + +fn pll_enable(instance: PllInstance, enabled: bool) { + RCC.cr().modify(|w| w.set_pllon(instance as _, enabled)); + while RCC.cr().read().pllrdy(instance as _) != enabled {} +} + +fn init_pll(instance: PllInstance, config: Option, input: &PllInput, voltage_range: VoltageScale) -> PllOutput { + // Disable PLL + pll_enable(instance, false); + + let Some(pll) = config else { return PllOutput::default() }; + + let src_freq = match pll.source { + PllSource::DISABLE => panic!("must not select PLL source as DISABLE"), + PllSource::HSE => unwrap!(input.hse), + PllSource::HSI => unwrap!(input.hsi), + PllSource::MSIS => unwrap!(input.msi), + }; + + // Calculate the reference clock, which is the source divided by m + let ref_freq = src_freq / pll.prediv; + // Check limits per RM0456 § 11.4.6 + assert!(Hertz::mhz(4) <= ref_freq && ref_freq <= Hertz::mhz(16)); + + // Check PLL clocks per RM0456 § 11.4.10 + let (vco_min, vco_max, out_max) = match voltage_range { + VoltageScale::RANGE1 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(208)), + VoltageScale::RANGE2 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(110)), + VoltageScale::RANGE3 => (Hertz::mhz(128), Hertz::mhz(330), Hertz::mhz(55)), + VoltageScale::RANGE4 => panic!("PLL is unavailable in voltage range 4"), + }; + + // Calculate the PLL VCO clock + let vco_freq = ref_freq * pll.mul; + assert!(vco_freq >= vco_min && vco_freq <= vco_max); + + // Calculate output clocks. + let p = pll.divp.map(|div| vco_freq / div); + let q = pll.divq.map(|div| vco_freq / div); + let r = pll.divr.map(|div| vco_freq / div); + for freq in [p, q, r] { + if let Some(freq) = freq { + assert!(freq <= out_max); + } + } + + let divr = match instance { + PllInstance::Pll1 => RCC.pll1divr(), + PllInstance::Pll2 => RCC.pll2divr(), + PllInstance::Pll3 => RCC.pll3divr(), + }; + divr.write(|w| { + w.set_plln(pll.mul); + w.set_pllp(pll.divp.unwrap_or(PllDiv::DIV1)); + w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1)); + w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1)); + }); + + let input_range = match ref_freq.0 { + ..=8_000_000 => Pllrge::FREQ_4TO8MHZ, + _ => Pllrge::FREQ_8TO16MHZ, + }; + + macro_rules! write_fields { + ($w:ident) => { + $w.set_pllpen(pll.divp.is_some()); + $w.set_pllqen(pll.divq.is_some()); + $w.set_pllren(pll.divr.is_some()); + $w.set_pllm(pll.prediv); + $w.set_pllsrc(pll.source); + $w.set_pllrge(input_range); + }; + } + + match instance { + PllInstance::Pll1 => RCC.pll1cfgr().write(|w| { + // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler + // value that results in an output between 4 and 16 MHz for the PWR EPOD boost + if r.unwrap() >= Hertz::mhz(55) { + // source_clk can be up to 50 MHz, so there's just a few cases: + let mboost = match src_freq.0 { + ..=16_000_000 => Pllmboost::DIV1, // Bypass, giving EPOD 4-16 MHz + ..=32_000_000 => Pllmboost::DIV2, // Divide by 2, giving EPOD 8-16 MHz + _ => Pllmboost::DIV4, // Divide by 4, giving EPOD 8-12.5 MHz + }; + w.set_pllmboost(mboost); + } + write_fields!(w); + }), + PllInstance::Pll2 => RCC.pll2cfgr().write(|w| { + write_fields!(w); + }), + PllInstance::Pll3 => RCC.pll3cfgr().write(|w| { + write_fields!(w); + }), + } + + // Enable PLL + pll_enable(instance, true); + + PllOutput { p, q, r } +} diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index dca34fd0e..99cdeacc9 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -4,7 +4,6 @@ use defmt::{panic, *}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; -use embassy_stm32::rcc::*; use embassy_stm32::usb_otg::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; @@ -22,22 +21,28 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut config = Config::default(); - config.rcc.mux = ClockSrc::PLL1_R(PllConfig { - source: PllSource::HSI, - m: Pllm::DIV2, - n: Plln::MUL10, - p: Plldiv::DIV1, - q: Plldiv::DIV1, - r: Plldiv::DIV1, - }); - config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, // 16 MHz + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL10, + divp: None, + divq: None, + divr: Some(PllDiv::DIV1), // 160 MHz + }); + config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.voltage_range = VoltageScale::RANGE1; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + } let p = embassy_stm32::init(config); // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb_otg::Config::default(); - config.vbus_detection = true; + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 50a7f9bae..1e6b1cce9 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -577,7 +577,18 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] { use embassy_stm32::rcc::*; - config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_48MHZ); + config.rcc.hsi = true; + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, // 16 MHz + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL10, + divp: None, + divq: None, + divr: Some(PllDiv::DIV1), // 160 MHz + }); + config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.voltage_range = VoltageScale::RANGE1; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB } #[cfg(feature = "stm32wba52cg")] From d24349f57ce7435e70fcf1cd9aac20d1740995d4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 23 Feb 2024 01:33:37 +0100 Subject: [PATCH 541/760] stm32/tests: run stm32u5a5zj from flash due to wrong RAM size in stm32-data. --- tests/stm32/Cargo.toml | 2 +- tests/stm32/build.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 5b28b5849..828a28e2c 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -26,7 +26,7 @@ stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash" stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] -stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] +stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index bc5589164..176adff62 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs @@ -16,6 +16,7 @@ fn main() -> Result<(), Box> { feature = "stm32l073rz", // wrong ram size in stm32-data feature = "stm32wl55jc", + feature = "stm32u5a5zj", // no VTOR, so interrupts can't work when running from RAM feature = "stm32f091rc", )) { From b091ffcb55840a1349c62f1e4218746d9d51b6c3 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 23 Feb 2024 01:59:24 +0100 Subject: [PATCH 542/760] [embassy-stm32] G4 RCC refactor amendments and additions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added assertions for a variety of clock frequencies, based on the reference manual and stm32g474 datasheet. The family and numbers are consistent enough that I’m assuming these numbers will work for the other chips. * Corrected value of pll1_q in set_clocks call, added pll1_r value --- embassy-stm32/src/rcc/g4.rs | 52 +++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 382ffbead..6ed266284 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -176,7 +176,7 @@ pub(crate) unsafe fn init(config: Config) { _ => unreachable!(), }; - // TODO: check PLL input, internal and output frequencies for validity + assert!(max::PLL_IN.contains(&src_freq)); // Disable PLL before configuration RCC.cr().modify(|w| w.set_pllon(false)); @@ -184,6 +184,8 @@ pub(crate) unsafe fn init(config: Config) { let internal_freq = src_freq / pll_config.prediv * pll_config.mul; + assert!(max::PLL_VCO.contains(&internal_freq)); + RCC.pllcfgr().write(|w| { w.set_plln(pll_config.mul); w.set_pllm(pll_config.prediv); @@ -195,7 +197,9 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllp(div_p); w.set_pllpen(true); }); - internal_freq / div_p + let freq = internal_freq / div_p; + assert!(max::PCLK.contains(&freq)); + freq }); let pll_q_freq = pll_config.divq.map(|div_q| { @@ -203,7 +207,9 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllq(div_q); w.set_pllqen(true); }); - internal_freq / div_q + let freq = internal_freq / div_q; + assert!(max::PCLK.contains(&freq)); + freq }); let pll_r_freq = pll_config.divr.map(|div_r| { @@ -211,7 +217,9 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllr(div_r); w.set_pllren(true); }); - internal_freq / div_r + let freq = internal_freq / div_r; + assert!(max::PCLK.contains(&freq)); + freq }); // Enable the PLL @@ -234,7 +242,7 @@ pub(crate) unsafe fn init(config: Config) { let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0; - assert!(freq <= 170_000_000); + assert!(max::SYSCLK.contains(&Hertz(freq))); (Hertz(freq), Sw::PLL1_R) } @@ -244,6 +252,8 @@ pub(crate) unsafe fn init(config: Config) { // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. let hclk = sys_clk / config.ahb_pre; + assert!(max::HCLK.contains(&hclk)); + // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) if config.boost { // RM0440 p235 @@ -346,32 +356,40 @@ pub(crate) unsafe fn init(config: Config) { adc: adc12_ck, adc34: adc345_ck, pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), - pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_p), + pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), + pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), hse: hse, rtc: rtc, ); } -// TODO: if necessary, make more of these, gated behind cfg attrs +/// Acceptable Frequency Ranges +/// Currently assuming voltage scaling range 1 boost mode. +/// Where not specified in the generic G4 reference manual (RM0440), values taken from the STM32G474 datasheet. +/// If acceptable ranges for other G4-family chips differ, make additional max modules gated behind cfg attrs. mod max { use core::ops::RangeInclusive; use crate::time::Hertz; - /// HSE 4-48MHz (RM0440 p280) + /// HSE Frequency Range (RM0440 p280) pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(48_000_000); - /// External Clock ?-48MHz (RM0440 p280) + /// External Clock Frequency Range (RM0440 p280) pub(crate) const HSE_BYP: RangeInclusive = Hertz(0)..=Hertz(48_000_000); - // SYSCLK ?-170MHz (RM0440 p282) - //pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); + /// SYSCLK Frequency Range (RM0440 p282) + pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); - // PLL Output frequency ?-170MHz (RM0440 p281) - //pub(crate) const PCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); + /// PLL Output Frequency Range (RM0440 p281, STM32G474 Datasheet p123, Table 46) + pub(crate) const PCLK: RangeInclusive = Hertz(8)..=Hertz(170_000_000); - // Left over from f.rs, remove if not necessary - //pub(crate) const HCLK: RangeInclusive = Hertz(12_500_000)..=Hertz(216_000_000); - //pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(2_100_000); - //pub(crate) const PLL_VCO: RangeInclusive = Hertz(100_000_000)..=Hertz(432_000_000); + /// HCLK (AHB) Clock Frequency Range (STM32G474 Datasheet) + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(170_000_000); + + /// PLL Source Frequency Range (STM32G474 Datasheet p123, Table 46) + pub(crate) const PLL_IN: RangeInclusive = Hertz(2_660_000)..=Hertz(16_000_000); + + /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46) + pub(crate) const PLL_VCO: RangeInclusive = Hertz(96_000_000)..=Hertz(344_000_000); } From a11e3146f8f5c00c770c6ef913bca676bbc9a685 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Thu, 22 Feb 2024 16:55:00 +0000 Subject: [PATCH 543/760] stm32: time_driver: allow use of TIM1 for driver --- embassy-stm32/Cargo.toml | 2 ++ embassy-stm32/src/time_driver.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d585d2cd6..0defde033 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -130,6 +130,8 @@ _time-driver = ["dep:embassy-time-driver", "time"] ## Use any time driver time-driver-any = ["_time-driver"] +## Use TIM1 as time driver +time-driver-tim1 = ["_time-driver"] ## Use TIM2 as time driver time-driver-tim2 = ["_time-driver"] ## Use TIM3 as time driver diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index a1f54307d..4129e4f30 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -38,7 +38,7 @@ cfg_if::cfg_if! { } } -#[cfg(time_drvier_tim1)] +#[cfg(time_driver_tim1)] type T = peripherals::TIM1; #[cfg(time_driver_tim2)] type T = peripherals::TIM2; From 44534abf32f556533c1183640e87bc2d45161d54 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Thu, 22 Feb 2024 17:26:44 +0000 Subject: [PATCH 544/760] stm32: sync available TIMs in Cargo.toml, build.rs --- embassy-stm32/Cargo.toml | 8 ++++++++ embassy-stm32/build.rs | 1 + 2 files changed, 9 insertions(+) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 0defde033..c4b3ece1a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -140,6 +140,8 @@ time-driver-tim3 = ["_time-driver"] time-driver-tim4 = ["_time-driver"] ## Use TIM5 as time driver time-driver-tim5 = ["_time-driver"] +## Use TIM8 as time driver +time-driver-tim8 = ["_time-driver"] ## Use TIM9 as time driver time-driver-tim9 = ["_time-driver"] ## Use TIM11 as time driver @@ -148,10 +150,16 @@ time-driver-tim11 = ["_time-driver"] time-driver-tim12 = ["_time-driver"] ## Use TIM15 as time driver time-driver-tim15 = ["_time-driver"] +## Use TIM20 as time driver +time-driver-tim20 = ["_time-driver"] ## Use TIM21 as time driver time-driver-tim21 = ["_time-driver"] ## Use TIM22 as time driver time-driver-tim22 = ["_time-driver"] +## Use TIM23 as time driver +time-driver-tim23 = ["_time-driver"] +## Use TIM24 as time driver +time-driver-tim24 = ["_time-driver"] #! ## Analog Switch Pins (Pxy_C) on STM32H7 series diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 068a74733..75a2055eb 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -189,6 +189,7 @@ fn main() { Some("tim5") => "TIM5", Some("tim8") => "TIM8", Some("tim9") => "TIM9", + Some("tim11") => "TIM11", Some("tim12") => "TIM12", Some("tim15") => "TIM15", Some("tim20") => "TIM20", From 86ccf0bc3e0a9908402405aebde6755df0e1b4f6 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Thu, 22 Feb 2024 17:42:08 +0000 Subject: [PATCH 545/760] stm32: remove TIM11 as time driver candidate (only 1 CC channel) --- embassy-stm32/Cargo.toml | 2 -- embassy-stm32/build.rs | 1 - embassy-stm32/src/time_driver.rs | 2 -- 3 files changed, 5 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index c4b3ece1a..abcc8ac4e 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -144,8 +144,6 @@ time-driver-tim5 = ["_time-driver"] time-driver-tim8 = ["_time-driver"] ## Use TIM9 as time driver time-driver-tim9 = ["_time-driver"] -## Use TIM11 as time driver -time-driver-tim11 = ["_time-driver"] ## Use TIM12 as time driver time-driver-tim12 = ["_time-driver"] ## Use TIM15 as time driver diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 75a2055eb..068a74733 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -189,7 +189,6 @@ fn main() { Some("tim5") => "TIM5", Some("tim8") => "TIM8", Some("tim9") => "TIM9", - Some("tim11") => "TIM11", Some("tim12") => "TIM12", Some("tim15") => "TIM15", Some("tim20") => "TIM20", diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 4129e4f30..8e4e606a4 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -52,8 +52,6 @@ type T = peripherals::TIM5; type T = peripherals::TIM8; #[cfg(time_driver_tim9)] type T = peripherals::TIM9; -#[cfg(time_driver_tim11)] -type T = peripherals::TIM11; #[cfg(time_driver_tim12)] type T = peripherals::TIM12; #[cfg(time_driver_tim15)] From ea89b0c4a0d752c67976aebf2ee264ddc8f77218 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 23 Feb 2024 18:45:07 -0600 Subject: [PATCH 546/760] oops --- embassy-executor-macros/src/macros/task.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 548fa4629..96c6267b2 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -107,7 +107,7 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); - unsafe { POOL._spawn_async_fn(move || ThisTask::construct(#(#full_args,)*)) } + unsafe { POOL._spawn_async_fn(move || <() as _EmbassyInternalTaskTrait>::construct(#(#full_args,)*)) } } }; #[cfg(not(feature = "nightly"))] From e67dfcb04f79aebed52a357b867d418e0ff476af Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 24 Feb 2024 02:38:31 +0100 Subject: [PATCH 547/760] stm32/dma: add AnyChannel, add support for BDMA on H7. --- embassy-stm32/build.rs | 181 ++-- embassy-stm32/src/dcmi.rs | 122 --- embassy-stm32/src/dma/bdma.rs | 740 ------------- embassy-stm32/src/dma/dma.rs | 1012 ------------------ embassy-stm32/src/dma/dma_bdma.rs | 913 ++++++++++++++++ embassy-stm32/src/dma/dmamux.rs | 34 +- embassy-stm32/src/dma/gpdma.rs | 170 ++- embassy-stm32/src/dma/mod.rs | 104 +- embassy-stm32/src/sai/mod.rs | 49 +- embassy-stm32/src/sdmmc/mod.rs | 15 +- embassy-stm32/src/usart/ringbuffered.rs | 20 +- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 2 +- 12 files changed, 1210 insertions(+), 2152 deletions(-) delete mode 100644 embassy-stm32/src/dma/bdma.rs delete mode 100644 embassy-stm32/src/dma/dma.rs create mode 100644 embassy-stm32/src/dma/dma_bdma.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 068a74733..4ecc97536 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -353,50 +353,6 @@ fn main() { g.extend(quote! { pub mod flash_regions { #flash_regions } }); - // ======== - // Generate DMA IRQs. - - let mut dma_irqs: BTreeMap<&str, Vec<(&str, &str, &str)>> = BTreeMap::new(); - - for p in METADATA.peripherals { - if let Some(r) = &p.registers { - if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" { - if p.name == "BDMA1" { - // BDMA1 in H7 doesn't use DMAMUX, which breaks - continue; - } - for irq in p.interrupts { - dma_irqs - .entry(irq.interrupt) - .or_default() - .push((r.kind, p.name, irq.signal)); - } - } - } - } - - let dma_irqs: TokenStream = dma_irqs - .iter() - .map(|(irq, channels)| { - let irq = format_ident!("{}", irq); - - let xdma = format_ident!("{}", channels[0].0); - let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch)); - - quote! { - #[cfg(feature = "rt")] - #[crate::interrupt] - unsafe fn #irq () { - #( - ::on_irq(); - )* - } - } - }) - .collect(); - - g.extend(dma_irqs); - // ======== // Extract the rcc registers let rcc_registers = METADATA @@ -664,7 +620,7 @@ fn main() { #[rustfmt::skip] let signals: HashMap<_, _> = [ - // (kind, signal) => trait + // (kind, signal) => trait (("usart", "TX"), quote!(crate::usart::TxPin)), (("usart", "RX"), quote!(crate::usart::RxPin)), (("usart", "CTS"), quote!(crate::usart::CtsPin)), @@ -897,7 +853,7 @@ fn main() { (("quadspi", "BK2_IO3"), quote!(crate::qspi::BK2D3Pin)), (("quadspi", "BK2_NCS"), quote!(crate::qspi::BK2NSSPin)), (("quadspi", "CLK"), quote!(crate::qspi::SckPin)), - ].into(); + ].into(); for p in METADATA.peripherals { if let Some(regs) = &p.registers { @@ -959,7 +915,7 @@ fn main() { }; if let Some(ch) = ch { g.extend(quote! { - impl_adc_pin!( #peri, #pin_name, #ch); + impl_adc_pin!( #peri, #pin_name, #ch); }) } } @@ -991,7 +947,7 @@ fn main() { let ch: u8 = pin.signal.strip_prefix("OUT").unwrap().parse().unwrap(); g.extend(quote! { - impl_dac_pin!( #peri, #pin_name, #ch); + impl_dac_pin!( #peri, #pin_name, #ch); }) } } @@ -1189,7 +1145,6 @@ fn main() { let mut interrupts_table: Vec> = Vec::new(); let mut peripherals_table: Vec> = Vec::new(); let mut pins_table: Vec> = Vec::new(); - let mut dma_channels_table: Vec> = Vec::new(); let mut adc_common_table: Vec> = Vec::new(); /* @@ -1283,51 +1238,108 @@ fn main() { } } - let mut dma_channel_count: usize = 0; - let mut bdma_channel_count: usize = 0; - let mut gpdma_channel_count: usize = 0; + let mut dmas = TokenStream::new(); + let has_dmamux = METADATA + .peripherals + .iter() + .flat_map(|p| &p.registers) + .any(|p| p.kind == "dmamux"); + + for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() { + // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. + if has_dmamux && ch.dmamux.is_none() { + continue; + } + + let name = format_ident!("{}", ch.name); + let idx = ch_idx as u8; + g.extend(quote!(dma_channel_impl!(#name, #idx);)); + + let dma = format_ident!("{}", ch.dma); + let ch_num = ch.channel as usize; - for ch in METADATA.dma_channels { - let mut row = Vec::new(); let dma_peri = METADATA.peripherals.iter().find(|p| p.name == ch.dma).unwrap(); let bi = dma_peri.registers.as_ref().unwrap(); - let num; - match bi.kind { - "dma" => { - num = dma_channel_count; - dma_channel_count += 1; - } - "bdma" => { - num = bdma_channel_count; - bdma_channel_count += 1; - } - "gpdma" => { - num = gpdma_channel_count; - gpdma_channel_count += 1; - } + let dma_info = match bi.kind { + "dma" => quote!(crate::dma::DmaInfo::Dma(crate::pac::#dma)), + "bdma" => quote!(crate::dma::DmaInfo::Bdma(crate::pac::#dma)), + "gpdma" => quote!(crate::pac::#dma), _ => panic!("bad dma channel kind {}", bi.kind), - } + }; - row.push(ch.name.to_string()); - row.push(ch.dma.to_string()); - row.push(bi.kind.to_string()); - row.push(ch.channel.to_string()); - row.push(num.to_string()); - if let Some(dmamux) = &ch.dmamux { - let dmamux_channel = ch.dmamux_channel.unwrap(); - row.push(format!("{{dmamux: {}, dmamux_channel: {}}}", dmamux, dmamux_channel)); - } else { - row.push("{}".to_string()); - } + let dmamux = match &ch.dmamux { + Some(dmamux) => { + let dmamux = format_ident!("{}", dmamux); + let num = ch.dmamux_channel.unwrap() as usize; - dma_channels_table.push(row); + g.extend(quote!(dmamux_channel_impl!(#name, #dmamux);)); + + quote! { + dmamux: crate::dma::DmamuxInfo { + mux: crate::pac::#dmamux, + num: #num, + }, + } + } + None => quote!(), + }; + + dmas.extend(quote! { + crate::dma::ChannelInfo { + dma: #dma_info, + num: #ch_num, + #dmamux + }, + }); } + // ======== + // Generate DMA IRQs. + + let mut dma_irqs: BTreeMap<&str, Vec> = BTreeMap::new(); + + for p in METADATA.peripherals { + if let Some(r) = &p.registers { + if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" { + for irq in p.interrupts { + let ch_name = format!("{}_{}", p.name, irq.signal); + let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap(); + + // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. + if has_dmamux && ch.dmamux.is_none() { + continue; + } + + dma_irqs.entry(irq.interrupt).or_default().push(ch_name); + } + } + } + } + + let dma_irqs: TokenStream = dma_irqs + .iter() + .map(|(irq, channels)| { + let irq = format_ident!("{}", irq); + + let channels = channels.iter().map(|c| format_ident!("{}", c)); + + quote! { + #[cfg(feature = "rt")] + #[crate::interrupt] + unsafe fn #irq () { + #( + ::on_irq(); + )* + } + } + }) + .collect(); + + g.extend(dma_irqs); + g.extend(quote! { - pub(crate) const DMA_CHANNEL_COUNT: usize = #dma_channel_count; - pub(crate) const BDMA_CHANNEL_COUNT: usize = #bdma_channel_count; - pub(crate) const GPDMA_CHANNEL_COUNT: usize = #gpdma_channel_count; + pub(crate) const DMA_CHANNELS: &[crate::dma::ChannelInfo] = &[#dmas]; }); for irq in METADATA.interrupts { @@ -1347,7 +1359,6 @@ fn main() { make_table(&mut m, "foreach_interrupt", &interrupts_table); make_table(&mut m, "foreach_peripheral", &peripherals_table); make_table(&mut m, "foreach_pin", &pins_table); - make_table(&mut m, "foreach_dma_channel", &dma_channels_table); make_table(&mut m, "foreach_adc", &adc_common_table); let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 4d02284b2..826b04a4b 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -394,19 +394,7 @@ where /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer. /// The implication is that the input buffer size must be exactly the size of the captured frame. - /// - /// Note that when `buffer.len() > 0xffff` the capture future requires some real-time guarantees to be upheld - /// (must be polled fast enough so the buffers get switched before data is overwritten). - /// It is therefore recommended that it is run on higher priority executor. pub async fn capture(&mut self, buffer: &mut [u32]) -> Result<(), Error> { - if buffer.len() <= 0xffff { - return self.capture_small(buffer).await; - } else { - return self.capture_giant(buffer).await; - } - } - - async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> { let r = self.inner.regs(); let src = r.dr().as_ptr() as *mut u32; let request = self.dma.request(); @@ -441,116 +429,6 @@ where result } - - #[cfg(not(dma))] - async fn capture_giant(&mut self, _buffer: &mut [u32]) -> Result<(), Error> { - panic!("capturing to buffers larger than 0xffff is only supported on DMA for now, not on BDMA or GPDMA."); - } - - #[cfg(dma)] - async fn capture_giant(&mut self, buffer: &mut [u32]) -> Result<(), Error> { - use crate::dma::TransferOptions; - - let data_len = buffer.len(); - let chunk_estimate = data_len / 0xffff; - - let mut chunks = chunk_estimate + 1; - while data_len % chunks != 0 { - chunks += 1; - } - - let chunk_size = data_len / chunks; - - let mut remaining_chunks = chunks - 2; - - let mut m0ar = buffer.as_mut_ptr(); - let mut m1ar = unsafe { buffer.as_mut_ptr().add(chunk_size) }; - - let channel = &mut self.dma; - let request = channel.request(); - - let r = self.inner.regs(); - let src = r.dr().as_ptr() as *mut u32; - - let mut transfer = unsafe { - crate::dma::DoubleBuffered::new_read( - &mut self.dma, - request, - src, - m0ar, - m1ar, - chunk_size, - TransferOptions::default(), - ) - }; - - let mut last_chunk_set_for_transfer = false; - let mut buffer0_last_accessible = false; - let dma_result = poll_fn(|cx| { - transfer.set_waker(cx.waker()); - - let buffer0_currently_accessible = transfer.is_buffer0_accessible(); - - // check if the accessible buffer changed since last poll - if buffer0_last_accessible == buffer0_currently_accessible { - return Poll::Pending; - } - buffer0_last_accessible = !buffer0_last_accessible; - - if remaining_chunks != 0 { - if remaining_chunks % 2 == 0 && buffer0_currently_accessible { - m0ar = unsafe { m0ar.add(2 * chunk_size) }; - unsafe { transfer.set_buffer0(m0ar) } - remaining_chunks -= 1; - } else if !buffer0_currently_accessible { - m1ar = unsafe { m1ar.add(2 * chunk_size) }; - unsafe { transfer.set_buffer1(m1ar) }; - remaining_chunks -= 1; - } - } else { - if buffer0_currently_accessible { - unsafe { transfer.set_buffer0(buffer.as_mut_ptr()) } - } else { - unsafe { transfer.set_buffer1(buffer.as_mut_ptr()) } - } - if last_chunk_set_for_transfer { - transfer.request_stop(); - return Poll::Ready(()); - } - last_chunk_set_for_transfer = true; - } - Poll::Pending - }); - - Self::clear_interrupt_flags(); - Self::enable_irqs(); - - let result = poll_fn(|cx| { - STATE.waker.register(cx.waker()); - - let ris = crate::pac::DCMI.ris().read(); - if ris.err_ris() { - crate::pac::DCMI.icr().write(|r| r.set_err_isc(true)); - Poll::Ready(Err(Error::PeripheralError)) - } else if ris.ovr_ris() { - crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true)); - Poll::Ready(Err(Error::Overrun)) - } else if ris.frame_ris() { - crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true)); - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - }); - - Self::toggle(true); - - let (_, result) = embassy_futures::join::join(dma_result, result).await; - - Self::toggle(false); - - result - } } mod sealed { diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs deleted file mode 100644 index 994bdb1e6..000000000 --- a/embassy-stm32/src/dma/bdma.rs +++ /dev/null @@ -1,740 +0,0 @@ -//! Basic Direct Memory Acccess (BDMA) - -use core::future::Future; -use core::pin::Pin; -use core::sync::atomic::{fence, AtomicUsize, Ordering}; -use core::task::{Context, Poll, Waker}; - -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; - -use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer}; -use super::word::{Word, WordSize}; -use super::Dir; -use crate::_generated::BDMA_CHANNEL_COUNT; -use crate::interrupt::typelevel::Interrupt; -use crate::interrupt::Priority; -use crate::pac; -use crate::pac::bdma::{regs, vals}; - -/// BDMA transfer options. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub struct TransferOptions { - /// Enable circular DMA - /// - /// Note: - /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task. - /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever. - pub circular: bool, - /// Enable half transfer interrupt - pub half_transfer_ir: bool, - /// Enable transfer complete interrupt - pub complete_transfer_ir: bool, -} - -impl Default for TransferOptions { - fn default() -> Self { - Self { - circular: false, - half_transfer_ir: false, - complete_transfer_ir: true, - } - } -} - -impl From for vals::Size { - fn from(raw: WordSize) -> Self { - match raw { - WordSize::OneByte => Self::BITS8, - WordSize::TwoBytes => Self::BITS16, - WordSize::FourBytes => Self::BITS32, - } - } -} - -impl From

for vals::Dir { - fn from(raw: Dir) -> Self { - match raw { - Dir::MemoryToPeripheral => Self::FROMMEMORY, - Dir::PeripheralToMemory => Self::FROMPERIPHERAL, - } - } -} - -struct State { - ch_wakers: [AtomicWaker; BDMA_CHANNEL_COUNT], - complete_count: [AtomicUsize; BDMA_CHANNEL_COUNT], -} - -impl State { - const fn new() -> Self { - const ZERO: AtomicUsize = AtomicUsize::new(0); - const AW: AtomicWaker = AtomicWaker::new(); - Self { - ch_wakers: [AW; BDMA_CHANNEL_COUNT], - complete_count: [ZERO; BDMA_CHANNEL_COUNT], - } - } -} - -static STATE: State = State::new(); - -/// safety: must be called only once -pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) { - foreach_interrupt! { - ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { - crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); - crate::interrupt::typelevel::$irq::enable(); - }; - } - crate::_generated::init_bdma(); -} - -foreach_dma_channel! { - ($channel_peri:ident, BDMA1, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => { - // BDMA1 in H7 doesn't use DMAMUX, which breaks - }; - ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => { - impl sealed::Channel for crate::peripherals::$channel_peri { - fn regs(&self) -> pac::bdma::Dma { - pac::$dma_peri - } - fn num(&self) -> usize { - $channel_num - } - fn index(&self) -> usize { - $index - } - fn on_irq() { - unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) } - } - } - - impl Channel for crate::peripherals::$channel_peri {} - }; -} - -/// Safety: Must be called with a matching set of parameters for a valid dma channel -pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index: usize) { - let isr = dma.isr().read(); - let cr = dma.ch(channel_num).cr(); - - if isr.teif(channel_num) { - panic!("DMA: error on BDMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num); - } - - if isr.htif(channel_num) && cr.read().htie() { - // Acknowledge half transfer complete interrupt - dma.ifcr().write(|w| w.set_htif(channel_num, true)); - } else if isr.tcif(channel_num) && cr.read().tcie() { - // Acknowledge transfer complete interrupt - dma.ifcr().write(|w| w.set_tcif(channel_num, true)); - #[cfg(not(armv6m))] - STATE.complete_count[index].fetch_add(1, Ordering::Release); - #[cfg(armv6m)] - critical_section::with(|_| { - let x = STATE.complete_count[index].load(Ordering::Relaxed); - STATE.complete_count[index].store(x + 1, Ordering::Release); - }) - } else { - return; - } - - STATE.ch_wakers[index].wake(); -} - -/// DMA request type alias. -#[cfg(any(bdma_v2, dmamux))] -pub type Request = u8; -/// DMA request type alias. -#[cfg(not(any(bdma_v2, dmamux)))] -pub type Request = (); - -/// DMA channel. -#[cfg(dmamux)] -pub trait Channel: sealed::Channel + Peripheral

+ 'static + super::dmamux::MuxChannel {} -/// DMA channel. -#[cfg(not(dmamux))] -pub trait Channel: sealed::Channel + Peripheral

+ 'static {} - -pub(crate) mod sealed { - use super::*; - - pub trait Channel { - fn regs(&self) -> pac::bdma::Dma; - fn num(&self) -> usize; - fn index(&self) -> usize; - fn on_irq(); - } -} - -/// DMA transfer. -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Transfer<'a, C: Channel> { - channel: PeripheralRef<'a, C>, -} - -impl<'a, C: Channel> Transfer<'a, C> { - /// Create a new read DMA transfer (peripheral to memory). - pub unsafe fn new_read( - channel: impl Peripheral

+ 'a, - request: Request, - peri_addr: *mut W, - buf: &'a mut [W], - options: TransferOptions, - ) -> Self { - Self::new_read_raw(channel, request, peri_addr, buf, options) - } - - /// Create a new read DMA transfer (peripheral to memory), using raw pointers. - pub unsafe fn new_read_raw( - channel: impl Peripheral

+ 'a, - request: Request, - peri_addr: *mut W, - buf: *mut [W], - options: TransferOptions, - ) -> Self { - into_ref!(channel); - - let (ptr, len) = super::slice_ptr_parts_mut(buf); - assert!(len > 0 && len <= 0xFFFF); - - Self::new_inner( - channel, - request, - Dir::PeripheralToMemory, - peri_addr as *const u32, - ptr as *mut u32, - len, - true, - W::size(), - options, - ) - } - - /// Create a new write DMA transfer (memory to peripheral). - pub unsafe fn new_write( - channel: impl Peripheral

+ 'a, - request: Request, - buf: &'a [W], - peri_addr: *mut W, - options: TransferOptions, - ) -> Self { - Self::new_write_raw(channel, request, buf, peri_addr, options) - } - - /// Create a new write DMA transfer (memory to peripheral), using raw pointers. - pub unsafe fn new_write_raw( - channel: impl Peripheral

+ 'a, - request: Request, - buf: *const [W], - peri_addr: *mut W, - options: TransferOptions, - ) -> Self { - into_ref!(channel); - - let (ptr, len) = super::slice_ptr_parts(buf); - assert!(len > 0 && len <= 0xFFFF); - - Self::new_inner( - channel, - request, - Dir::MemoryToPeripheral, - peri_addr as *const u32, - ptr as *mut u32, - len, - true, - W::size(), - options, - ) - } - - /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. - pub unsafe fn new_write_repeated( - channel: impl Peripheral

+ 'a, - request: Request, - repeated: &'a W, - count: usize, - peri_addr: *mut W, - options: TransferOptions, - ) -> Self { - into_ref!(channel); - - Self::new_inner( - channel, - request, - Dir::MemoryToPeripheral, - peri_addr as *const u32, - repeated as *const W as *mut u32, - count, - false, - W::size(), - options, - ) - } - - unsafe fn new_inner( - channel: PeripheralRef<'a, C>, - _request: Request, - dir: Dir, - peri_addr: *const u32, - mem_addr: *mut u32, - mem_len: usize, - incr_mem: bool, - data_size: WordSize, - options: TransferOptions, - ) -> Self { - let ch = channel.regs().ch(channel.num()); - - // "Preceding reads and writes cannot be moved past subsequent writes." - fence(Ordering::SeqCst); - - #[cfg(bdma_v2)] - critical_section::with(|_| channel.regs().cselr().modify(|w| w.set_cs(channel.num(), _request))); - - let mut this = Self { channel }; - this.clear_irqs(); - STATE.complete_count[this.channel.index()].store(0, Ordering::Release); - - #[cfg(dmamux)] - super::dmamux::configure_dmamux(&*this.channel, _request); - - ch.par().write_value(peri_addr as u32); - ch.mar().write_value(mem_addr as u32); - ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); - ch.cr().write(|w| { - w.set_psize(data_size.into()); - w.set_msize(data_size.into()); - w.set_minc(incr_mem); - w.set_dir(dir.into()); - w.set_teie(true); - w.set_tcie(options.complete_transfer_ir); - w.set_htie(options.half_transfer_ir); - w.set_circ(options.circular); - if options.circular { - debug!("Setting circular mode"); - } - w.set_pl(vals::Pl::VERYHIGH); - w.set_en(true); - }); - - this - } - - fn clear_irqs(&mut self) { - self.channel.regs().ifcr().write(|w| { - w.set_tcif(self.channel.num(), true); - w.set_teif(self.channel.num(), true); - }); - } - - /// Request the transfer to stop. - /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - let ch = self.channel.regs().ch(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - ch.cr().write(|w| { - w.set_teie(true); - w.set_tcie(true); - }); - } - - /// Return whether this transfer is still running. - /// - /// If this returns `false`, it can be because either the transfer finished, or - /// it was requested to stop early with [`request_stop`](Self::request_stop). - pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().ch(self.channel.num()); - let en = ch.cr().read().en(); - let circular = ch.cr().read().circ(); - let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; - en && (circular || !tcif) - } - - /// Get the total remaining transfers for the channel. - /// - /// This will be zero for transfers that completed instead of being canceled with [`request_stop`](Self::request_stop). - pub fn get_remaining_transfers(&self) -> u16 { - let ch = self.channel.regs().ch(self.channel.num()); - ch.ndtr().read().ndt() - } - - /// Blocking wait until the transfer finishes. - pub fn blocking_wait(mut self) { - while self.is_running() {} - self.request_stop(); - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - - core::mem::forget(self); - } -} - -impl<'a, C: Channel> Drop for Transfer<'a, C> { - fn drop(&mut self) { - self.request_stop(); - while self.is_running() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - } -} - -impl<'a, C: Channel> Unpin for Transfer<'a, C> {} -impl<'a, C: Channel> Future for Transfer<'a, C> { - type Output = (); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - STATE.ch_wakers[self.channel.index()].register(cx.waker()); - - if self.is_running() { - Poll::Pending - } else { - Poll::Ready(()) - } - } -} - -// ============================== - -struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>); - -impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { - fn get_remaining_transfers(&self) -> usize { - let ch = self.0.regs().ch(self.0.num()); - ch.ndtr().read().ndt() as usize - } - - fn get_complete_count(&self) -> usize { - STATE.complete_count[self.0.index()].load(Ordering::Acquire) - } - - fn reset_complete_count(&mut self) -> usize { - #[cfg(not(armv6m))] - return STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel); - #[cfg(armv6m)] - return critical_section::with(|_| { - let x = STATE.complete_count[self.0.index()].load(Ordering::Acquire); - STATE.complete_count[self.0.index()].store(0, Ordering::Release); - x - }); - } - - fn set_waker(&mut self, waker: &Waker) { - STATE.ch_wakers[self.0.index()].register(waker); - } -} - -/// Ringbuffer for reading data using DMA circular mode. -pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { - cr: regs::Cr, - channel: PeripheralRef<'a, C>, - ringbuf: ReadableDmaRingBuffer<'a, W>, -} - -impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { - /// Create a new ring buffer. - pub unsafe fn new( - channel: impl Peripheral

+ 'a, - _request: Request, - peri_addr: *mut W, - buffer: &'a mut [W], - _options: TransferOptions, - ) -> Self { - into_ref!(channel); - - let len = buffer.len(); - assert!(len > 0 && len <= 0xFFFF); - - let dir = Dir::PeripheralToMemory; - let data_size = W::size(); - - let channel_number = channel.num(); - let dma = channel.regs(); - - // "Preceding reads and writes cannot be moved past subsequent writes." - fence(Ordering::SeqCst); - - #[cfg(bdma_v2)] - critical_section::with(|_| channel.regs().cselr().modify(|w| w.set_cs(channel.num(), _request))); - - let mut w = regs::Cr(0); - w.set_psize(data_size.into()); - w.set_msize(data_size.into()); - w.set_minc(true); - w.set_dir(dir.into()); - w.set_teie(true); - w.set_htie(true); - w.set_tcie(true); - w.set_circ(true); - w.set_pl(vals::Pl::VERYHIGH); - w.set_en(true); - - let buffer_ptr = buffer.as_mut_ptr(); - let mut this = Self { - channel, - cr: w, - ringbuf: ReadableDmaRingBuffer::new(buffer), - }; - this.clear_irqs(); - - #[cfg(dmamux)] - super::dmamux::configure_dmamux(&*this.channel, _request); - - let ch = dma.ch(channel_number); - ch.par().write_value(peri_addr as u32); - ch.mar().write_value(buffer_ptr as u32); - ch.ndtr().write(|w| w.set_ndt(len as u16)); - - this - } - - /// Start the ring buffer operation. - /// - /// You must call this after creating it for it to work. - pub fn start(&mut self) { - let ch = self.channel.regs().ch(self.channel.num()); - ch.cr().write_value(self.cr) - } - - /// Clear all data in the ring buffer. - pub fn clear(&mut self) { - self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); - } - - /// Read elements from the ring buffer - /// Return a tuple of the length read and the length remaining in the buffer - /// If not all of the elements were read, then there will be some elements in the buffer remaining - /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. - pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { - self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) - } - - /// Read an exact number of elements from the ringbuffer. - /// - /// Returns the remaining number of elements available for immediate reading. - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. - /// - /// Async/Wake Behavior: - /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, - /// and when it wraps around. This means that when called with a buffer of length 'M', when this - /// ring buffer was created with a buffer of size 'N': - /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. - /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. - pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result { - self.ringbuf - .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) - .await - } - - /// The capacity of the ringbuffer. - pub const fn capacity(&self) -> usize { - self.ringbuf.cap() - } - - /// Set a waker to be woken when at least one byte is received. - pub fn set_waker(&mut self, waker: &Waker) { - DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); - } - - fn clear_irqs(&mut self) { - let dma = self.channel.regs(); - dma.ifcr().write(|w| { - w.set_htif(self.channel.num(), true); - w.set_tcif(self.channel.num(), true); - w.set_teif(self.channel.num(), true); - }); - } - - /// Request DMA to stop. - /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - let ch = self.channel.regs().ch(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - // If the channel is enabled and transfer is not completed, we need to perform - // two separate write access to the CR register to disable the channel. - ch.cr().write(|w| { - w.set_teie(true); - w.set_htie(true); - w.set_tcie(true); - }); - } - - /// Return whether DMA is still running. - /// - /// If this returns `false`, it can be because either the transfer finished, or - /// it was requested to stop early with [`request_stop`](Self::request_stop). - pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().ch(self.channel.num()); - ch.cr().read().en() - } -} - -impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { - fn drop(&mut self) { - self.request_stop(); - while self.is_running() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - } -} - -/// Ringbuffer for writing data using DMA circular mode. -pub struct WritableRingBuffer<'a, C: Channel, W: Word> { - cr: regs::Cr, - channel: PeripheralRef<'a, C>, - ringbuf: WritableDmaRingBuffer<'a, W>, -} - -impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { - /// Create a new ring buffer. - pub unsafe fn new( - channel: impl Peripheral

+ 'a, - _request: Request, - peri_addr: *mut W, - buffer: &'a mut [W], - _options: TransferOptions, - ) -> Self { - into_ref!(channel); - - let len = buffer.len(); - assert!(len > 0 && len <= 0xFFFF); - - let dir = Dir::MemoryToPeripheral; - let data_size = W::size(); - - let channel_number = channel.num(); - let dma = channel.regs(); - - // "Preceding reads and writes cannot be moved past subsequent writes." - fence(Ordering::SeqCst); - - #[cfg(bdma_v2)] - critical_section::with(|_| channel.regs().cselr().modify(|w| w.set_cs(channel.num(), _request))); - - let mut w = regs::Cr(0); - w.set_psize(data_size.into()); - w.set_msize(data_size.into()); - w.set_minc(true); - w.set_dir(dir.into()); - w.set_teie(true); - w.set_htie(true); - w.set_tcie(true); - w.set_circ(true); - w.set_pl(vals::Pl::VERYHIGH); - w.set_en(true); - - let buffer_ptr = buffer.as_mut_ptr(); - let mut this = Self { - channel, - cr: w, - ringbuf: WritableDmaRingBuffer::new(buffer), - }; - this.clear_irqs(); - - #[cfg(dmamux)] - super::dmamux::configure_dmamux(&*this.channel, _request); - - let ch = dma.ch(channel_number); - ch.par().write_value(peri_addr as u32); - ch.mar().write_value(buffer_ptr as u32); - ch.ndtr().write(|w| w.set_ndt(len as u16)); - - this - } - - /// Start the ring buffer operation. - /// - /// You must call this after creating it for it to work. - pub fn start(&mut self) { - let ch = self.channel.regs().ch(self.channel.num()); - ch.cr().write_value(self.cr) - } - - /// Clear all data in the ring buffer. - pub fn clear(&mut self) { - self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); - } - - /// Write elements directly to the raw buffer. - /// This can be used to fill the buffer before starting the DMA transfer. - #[allow(dead_code)] - pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { - self.ringbuf.write_immediate(buf) - } - - /// Write elements to the ring buffer - /// Return a tuple of the length written and the length remaining in the buffer - pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { - self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) - } - - /// Write an exact number of elements to the ringbuffer. - pub async fn write_exact(&mut self, buffer: &[W]) -> Result { - self.ringbuf - .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) - .await - } - - /// The capacity of the ringbuffer. - pub const fn capacity(&self) -> usize { - self.ringbuf.cap() - } - - /// Set a waker to be woken when at least one byte is sent. - pub fn set_waker(&mut self, waker: &Waker) { - DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); - } - - fn clear_irqs(&mut self) { - let dma = self.channel.regs(); - dma.ifcr().write(|w| { - w.set_htif(self.channel.num(), true); - w.set_tcif(self.channel.num(), true); - w.set_teif(self.channel.num(), true); - }); - } - - /// Request DMA to stop. - /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - let ch = self.channel.regs().ch(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - // If the channel is enabled and transfer is not completed, we need to perform - // two separate write access to the CR register to disable the channel. - ch.cr().write(|w| { - w.set_teie(true); - w.set_htie(true); - w.set_tcie(true); - }); - } - - /// Return whether DMA is still running. - /// - /// If this returns `false`, it can be because either the transfer finished, or - /// it was requested to stop early with [`request_stop`](Self::request_stop). - pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().ch(self.channel.num()); - ch.cr().read().en() - } -} - -impl<'a, C: Channel, W: Word> Drop for WritableRingBuffer<'a, C, W> { - fn drop(&mut self) { - self.request_stop(); - while self.is_running() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - } -} diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs deleted file mode 100644 index e762b1bde..000000000 --- a/embassy-stm32/src/dma/dma.rs +++ /dev/null @@ -1,1012 +0,0 @@ -use core::future::Future; -use core::marker::PhantomData; -use core::pin::Pin; -use core::sync::atomic::{fence, AtomicUsize, Ordering}; -use core::task::{Context, Poll, Waker}; - -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; - -use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer}; -use super::word::{Word, WordSize}; -use super::Dir; -use crate::_generated::DMA_CHANNEL_COUNT; -use crate::interrupt::typelevel::Interrupt; -use crate::interrupt::Priority; -use crate::pac::dma::{regs, vals}; -use crate::{interrupt, pac}; - -/// DMA transfer options. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub struct TransferOptions { - /// Peripheral burst transfer configuration - pub pburst: Burst, - /// Memory burst transfer configuration - pub mburst: Burst, - /// Flow control configuration - pub flow_ctrl: FlowControl, - /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. - pub fifo_threshold: Option, - /// Enable circular DMA - /// - /// Note: - /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task. - /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever. - pub circular: bool, - /// Enable half transfer interrupt - pub half_transfer_ir: bool, - /// Enable transfer complete interrupt - pub complete_transfer_ir: bool, -} - -impl Default for TransferOptions { - fn default() -> Self { - Self { - pburst: Burst::Single, - mburst: Burst::Single, - flow_ctrl: FlowControl::Dma, - fifo_threshold: None, - circular: false, - half_transfer_ir: false, - complete_transfer_ir: true, - } - } -} - -impl From for vals::Size { - fn from(raw: WordSize) -> Self { - match raw { - WordSize::OneByte => Self::BITS8, - WordSize::TwoBytes => Self::BITS16, - WordSize::FourBytes => Self::BITS32, - } - } -} - -impl From

for vals::Dir { - fn from(raw: Dir) -> Self { - match raw { - Dir::MemoryToPeripheral => Self::MEMORYTOPERIPHERAL, - Dir::PeripheralToMemory => Self::PERIPHERALTOMEMORY, - } - } -} - -/// DMA transfer burst setting. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Burst { - /// Single transfer - Single, - /// Incremental burst of 4 beats - Incr4, - /// Incremental burst of 8 beats - Incr8, - /// Incremental burst of 16 beats - Incr16, -} - -impl From for vals::Burst { - fn from(burst: Burst) -> Self { - match burst { - Burst::Single => vals::Burst::SINGLE, - Burst::Incr4 => vals::Burst::INCR4, - Burst::Incr8 => vals::Burst::INCR8, - Burst::Incr16 => vals::Burst::INCR16, - } - } -} - -/// DMA flow control setting. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum FlowControl { - /// Flow control by DMA - Dma, - /// Flow control by peripheral - Peripheral, -} - -impl From for vals::Pfctrl { - fn from(flow: FlowControl) -> Self { - match flow { - FlowControl::Dma => vals::Pfctrl::DMA, - FlowControl::Peripheral => vals::Pfctrl::PERIPHERAL, - } - } -} - -/// DMA FIFO threshold. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum FifoThreshold { - /// 1/4 full FIFO - Quarter, - /// 1/2 full FIFO - Half, - /// 3/4 full FIFO - ThreeQuarters, - /// Full FIFO - Full, -} - -impl From for vals::Fth { - fn from(value: FifoThreshold) -> Self { - match value { - FifoThreshold::Quarter => vals::Fth::QUARTER, - FifoThreshold::Half => vals::Fth::HALF, - FifoThreshold::ThreeQuarters => vals::Fth::THREEQUARTERS, - FifoThreshold::Full => vals::Fth::FULL, - } - } -} - -struct State { - ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT], - complete_count: [AtomicUsize; DMA_CHANNEL_COUNT], -} - -impl State { - const fn new() -> Self { - const ZERO: AtomicUsize = AtomicUsize::new(0); - const AW: AtomicWaker = AtomicWaker::new(); - Self { - ch_wakers: [AW; DMA_CHANNEL_COUNT], - complete_count: [ZERO; DMA_CHANNEL_COUNT], - } - } -} - -static STATE: State = State::new(); - -/// safety: must be called only once -pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) { - foreach_interrupt! { - ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { - interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); - interrupt::typelevel::$irq::enable(); - }; - } - crate::_generated::init_dma(); -} - -foreach_dma_channel! { - ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { - impl sealed::Channel for crate::peripherals::$channel_peri { - fn regs(&self) -> pac::dma::Dma { - pac::$dma_peri - } - fn num(&self) -> usize { - $channel_num - } - fn index(&self) -> usize { - $index - } - fn on_irq() { - unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) } - } - } - - impl Channel for crate::peripherals::$channel_peri {} - }; -} - -/// Safety: Must be called with a matching set of parameters for a valid dma channel -pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: usize) { - let cr = dma.st(channel_num).cr(); - let isr = dma.isr(channel_num / 4).read(); - - if isr.teif(channel_num % 4) { - panic!("DMA: error on DMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num); - } - - if isr.htif(channel_num % 4) && cr.read().htie() { - // Acknowledge half transfer complete interrupt - dma.ifcr(channel_num / 4).write(|w| w.set_htif(channel_num % 4, true)); - } else if isr.tcif(channel_num % 4) && cr.read().tcie() { - // Acknowledge transfer complete interrupt - dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true)); - STATE.complete_count[index].fetch_add(1, Ordering::Release); - } else { - return; - } - - STATE.ch_wakers[index].wake(); -} - -/// DMA request type alias. (also known as DMA channel number in some chips) -#[cfg(any(dma_v2, dmamux))] -pub type Request = u8; -/// DMA request type alias. (also known as DMA channel number in some chips) -#[cfg(not(any(dma_v2, dmamux)))] -pub type Request = (); - -/// DMA channel. -#[cfg(dmamux)] -pub trait Channel: sealed::Channel + Peripheral

+ 'static + super::dmamux::MuxChannel {} -/// DMA channel. -#[cfg(not(dmamux))] -pub trait Channel: sealed::Channel + Peripheral

+ 'static {} - -pub(crate) mod sealed { - use super::*; - - pub trait Channel { - fn regs(&self) -> pac::dma::Dma; - fn num(&self) -> usize; - fn index(&self) -> usize; - fn on_irq(); - } -} - -/// DMA transfer. -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Transfer<'a, C: Channel> { - channel: PeripheralRef<'a, C>, -} - -impl<'a, C: Channel> Transfer<'a, C> { - /// Create a new read DMA transfer (peripheral to memory). - pub unsafe fn new_read( - channel: impl Peripheral

+ 'a, - request: Request, - peri_addr: *mut W, - buf: &'a mut [W], - options: TransferOptions, - ) -> Self { - Self::new_read_raw(channel, request, peri_addr, buf, options) - } - - /// Create a new read DMA transfer (peripheral to memory), using raw pointers. - pub unsafe fn new_read_raw( - channel: impl Peripheral

+ 'a, - request: Request, - peri_addr: *mut W, - buf: *mut [W], - options: TransferOptions, - ) -> Self { - into_ref!(channel); - - let (ptr, len) = super::slice_ptr_parts_mut(buf); - assert!(len > 0 && len <= 0xFFFF); - - Self::new_inner( - channel, - request, - Dir::PeripheralToMemory, - peri_addr as *const u32, - ptr as *mut u32, - len, - true, - W::size(), - options, - ) - } - - /// Create a new write DMA transfer (memory to peripheral). - pub unsafe fn new_write( - channel: impl Peripheral

+ 'a, - request: Request, - buf: &'a [W], - peri_addr: *mut W, - options: TransferOptions, - ) -> Self { - Self::new_write_raw(channel, request, buf, peri_addr, options) - } - - /// Create a new write DMA transfer (memory to peripheral), using raw pointers. - pub unsafe fn new_write_raw( - channel: impl Peripheral

+ 'a, - request: Request, - buf: *const [W], - peri_addr: *mut W, - options: TransferOptions, - ) -> Self { - into_ref!(channel); - - let (ptr, len) = super::slice_ptr_parts(buf); - assert!(len > 0 && len <= 0xFFFF); - - Self::new_inner( - channel, - request, - Dir::MemoryToPeripheral, - peri_addr as *const u32, - ptr as *mut u32, - len, - true, - W::size(), - options, - ) - } - - /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. - pub unsafe fn new_write_repeated( - channel: impl Peripheral

+ 'a, - request: Request, - repeated: &'a W, - count: usize, - peri_addr: *mut W, - options: TransferOptions, - ) -> Self { - into_ref!(channel); - - Self::new_inner( - channel, - request, - Dir::MemoryToPeripheral, - peri_addr as *const u32, - repeated as *const W as *mut u32, - count, - false, - W::size(), - options, - ) - } - - unsafe fn new_inner( - channel: PeripheralRef<'a, C>, - _request: Request, - dir: Dir, - peri_addr: *const u32, - mem_addr: *mut u32, - mem_len: usize, - incr_mem: bool, - data_size: WordSize, - options: TransferOptions, - ) -> Self { - let ch = channel.regs().st(channel.num()); - - // "Preceding reads and writes cannot be moved past subsequent writes." - fence(Ordering::SeqCst); - - let mut this = Self { channel }; - this.clear_irqs(); - - #[cfg(dmamux)] - super::dmamux::configure_dmamux(&*this.channel, _request); - - ch.par().write_value(peri_addr as u32); - ch.m0ar().write_value(mem_addr as u32); - ch.ndtr().write_value(regs::Ndtr(mem_len as _)); - ch.fcr().write(|w| { - if let Some(fth) = options.fifo_threshold { - // FIFO mode - w.set_dmdis(vals::Dmdis::DISABLED); - w.set_fth(fth.into()); - } else { - // Direct mode - w.set_dmdis(vals::Dmdis::ENABLED); - } - }); - ch.cr().write(|w| { - w.set_dir(dir.into()); - w.set_msize(data_size.into()); - w.set_psize(data_size.into()); - w.set_pl(vals::Pl::VERYHIGH); - w.set_minc(incr_mem); - w.set_pinc(false); - w.set_teie(true); - w.set_tcie(options.complete_transfer_ir); - w.set_circ(options.circular); - if options.circular { - debug!("Setting circular mode"); - } - #[cfg(dma_v1)] - w.set_trbuff(true); - - #[cfg(dma_v2)] - w.set_chsel(_request); - - w.set_pburst(options.pburst.into()); - w.set_mburst(options.mburst.into()); - w.set_pfctrl(options.flow_ctrl.into()); - - w.set_en(true); - }); - - this - } - - fn clear_irqs(&mut self) { - let isrn = self.channel.num() / 4; - let isrbit = self.channel.num() % 4; - - self.channel.regs().ifcr(isrn).write(|w| { - w.set_tcif(isrbit, true); - w.set_teif(isrbit, true); - }); - } - - /// Request the transfer to stop. - /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - let ch = self.channel.regs().st(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - ch.cr().write(|w| { - w.set_teie(true); - w.set_tcie(true); - }); - } - - /// Return whether this transfer is still running. - /// - /// If this returns `false`, it can be because either the transfer finished, or - /// it was requested to stop early with [`request_stop`](Self::request_stop). - pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().st(self.channel.num()); - ch.cr().read().en() - } - - /// Gets the total remaining transfers for the channel - /// Note: this will be zero for transfers that completed without cancellation. - pub fn get_remaining_transfers(&self) -> u16 { - let ch = self.channel.regs().st(self.channel.num()); - ch.ndtr().read().ndt() - } - - /// Blocking wait until the transfer finishes. - pub fn blocking_wait(mut self) { - while self.is_running() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - - core::mem::forget(self); - } -} - -impl<'a, C: Channel> Drop for Transfer<'a, C> { - fn drop(&mut self) { - self.request_stop(); - while self.is_running() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - } -} - -impl<'a, C: Channel> Unpin for Transfer<'a, C> {} -impl<'a, C: Channel> Future for Transfer<'a, C> { - type Output = (); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - STATE.ch_wakers[self.channel.index()].register(cx.waker()); - - if self.is_running() { - Poll::Pending - } else { - Poll::Ready(()) - } - } -} - -// ================================== - -/// Double-buffered DMA transfer. -pub struct DoubleBuffered<'a, C: Channel, W: Word> { - channel: PeripheralRef<'a, C>, - _phantom: PhantomData, -} - -impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { - /// Create a new read DMA transfer (peripheral to memory). - pub unsafe fn new_read( - channel: impl Peripheral

+ 'a, - _request: Request, - peri_addr: *mut W, - buf0: *mut W, - buf1: *mut W, - len: usize, - options: TransferOptions, - ) -> Self { - into_ref!(channel); - assert!(len > 0 && len <= 0xFFFF); - - let dir = Dir::PeripheralToMemory; - let data_size = W::size(); - - let channel_number = channel.num(); - let dma = channel.regs(); - - // "Preceding reads and writes cannot be moved past subsequent writes." - fence(Ordering::SeqCst); - - let mut this = Self { - channel, - _phantom: PhantomData, - }; - this.clear_irqs(); - - #[cfg(dmamux)] - super::dmamux::configure_dmamux(&*this.channel, _request); - - let ch = dma.st(channel_number); - ch.par().write_value(peri_addr as u32); - ch.m0ar().write_value(buf0 as u32); - ch.m1ar().write_value(buf1 as u32); - ch.ndtr().write_value(regs::Ndtr(len as _)); - ch.fcr().write(|w| { - if let Some(fth) = options.fifo_threshold { - // FIFO mode - w.set_dmdis(vals::Dmdis::DISABLED); - w.set_fth(fth.into()); - } else { - // Direct mode - w.set_dmdis(vals::Dmdis::ENABLED); - } - }); - ch.cr().write(|w| { - w.set_dir(dir.into()); - w.set_msize(data_size.into()); - w.set_psize(data_size.into()); - w.set_pl(vals::Pl::VERYHIGH); - w.set_minc(true); - w.set_pinc(false); - w.set_teie(true); - w.set_tcie(true); - #[cfg(dma_v1)] - w.set_trbuff(true); - - #[cfg(dma_v2)] - w.set_chsel(_request); - - w.set_pburst(options.pburst.into()); - w.set_mburst(options.mburst.into()); - w.set_pfctrl(options.flow_ctrl.into()); - - w.set_en(true); - }); - - this - } - - fn clear_irqs(&mut self) { - let channel_number = self.channel.num(); - let dma = self.channel.regs(); - let isrn = channel_number / 4; - let isrbit = channel_number % 4; - - dma.ifcr(isrn).write(|w| { - w.set_htif(isrbit, true); - w.set_tcif(isrbit, true); - w.set_teif(isrbit, true); - }); - } - - /// Set the first buffer address. - /// - /// You may call this while DMA is transferring the other buffer. - pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { - let ch = self.channel.regs().st(self.channel.num()); - ch.m0ar().write_value(buffer as _); - } - - /// Set the second buffer address. - /// - /// You may call this while DMA is transferring the other buffer. - pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { - let ch = self.channel.regs().st(self.channel.num()); - ch.m1ar().write_value(buffer as _); - } - - /// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now) - pub fn is_buffer0_accessible(&mut self) -> bool { - let ch = self.channel.regs().st(self.channel.num()); - ch.cr().read().ct() == vals::Ct::MEMORY1 - } - - /// Set a waker to be woken when one of the buffers is being transferred. - pub fn set_waker(&mut self, waker: &Waker) { - STATE.ch_wakers[self.channel.index()].register(waker); - } - - /// Request the transfer to stop. - /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - let ch = self.channel.regs().st(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - ch.cr().write(|w| { - w.set_teie(true); - w.set_tcie(true); - }); - } - - /// Return whether this transfer is still running. - /// - /// If this returns `false`, it can be because either the transfer finished, or - /// it was requested to stop early with [`request_stop`](Self::request_stop). - pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().st(self.channel.num()); - ch.cr().read().en() - } - - /// Gets the total remaining transfers for the channel - /// Note: this will be zero for transfers that completed without cancellation. - pub fn get_remaining_transfers(&self) -> u16 { - let ch = self.channel.regs().st(self.channel.num()); - ch.ndtr().read().ndt() - } -} - -impl<'a, C: Channel, W: Word> Drop for DoubleBuffered<'a, C, W> { - fn drop(&mut self) { - self.request_stop(); - while self.is_running() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - } -} - -// ============================== - -struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>); - -impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { - fn get_remaining_transfers(&self) -> usize { - let ch = self.0.regs().st(self.0.num()); - ch.ndtr().read().ndt() as usize - } - - fn get_complete_count(&self) -> usize { - STATE.complete_count[self.0.index()].load(Ordering::Acquire) - } - - fn reset_complete_count(&mut self) -> usize { - STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) - } - - fn set_waker(&mut self, waker: &Waker) { - STATE.ch_wakers[self.0.index()].register(waker); - } -} - -/// Ringbuffer for receiving data using DMA circular mode. -pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { - cr: regs::Cr, - channel: PeripheralRef<'a, C>, - ringbuf: ReadableDmaRingBuffer<'a, W>, -} - -impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { - /// Create a new ring buffer. - pub unsafe fn new( - channel: impl Peripheral

+ 'a, - _request: Request, - peri_addr: *mut W, - buffer: &'a mut [W], - options: TransferOptions, - ) -> Self { - into_ref!(channel); - - let len = buffer.len(); - assert!(len > 0 && len <= 0xFFFF); - - let dir = Dir::PeripheralToMemory; - let data_size = W::size(); - - let channel_number = channel.num(); - let dma = channel.regs(); - - // "Preceding reads and writes cannot be moved past subsequent writes." - fence(Ordering::SeqCst); - - let mut w = regs::Cr(0); - w.set_dir(dir.into()); - w.set_msize(data_size.into()); - w.set_psize(data_size.into()); - w.set_pl(vals::Pl::VERYHIGH); - w.set_minc(true); - w.set_pinc(false); - w.set_teie(true); - w.set_htie(options.half_transfer_ir); - w.set_tcie(true); - w.set_circ(true); - #[cfg(dma_v1)] - w.set_trbuff(true); - #[cfg(dma_v2)] - w.set_chsel(_request); - w.set_pburst(options.pburst.into()); - w.set_mburst(options.mburst.into()); - w.set_pfctrl(options.flow_ctrl.into()); - w.set_en(true); - - let buffer_ptr = buffer.as_mut_ptr(); - let mut this = Self { - channel, - cr: w, - ringbuf: ReadableDmaRingBuffer::new(buffer), - }; - this.clear_irqs(); - - #[cfg(dmamux)] - super::dmamux::configure_dmamux(&*this.channel, _request); - - let ch = dma.st(channel_number); - ch.par().write_value(peri_addr as u32); - ch.m0ar().write_value(buffer_ptr as u32); - ch.ndtr().write_value(regs::Ndtr(len as _)); - ch.fcr().write(|w| { - if let Some(fth) = options.fifo_threshold { - // FIFO mode - w.set_dmdis(vals::Dmdis::DISABLED); - w.set_fth(fth.into()); - } else { - // Direct mode - w.set_dmdis(vals::Dmdis::ENABLED); - } - }); - - this - } - - /// Start the ring buffer operation. - /// - /// You must call this after creating it for it to work. - pub fn start(&mut self) { - let ch = self.channel.regs().st(self.channel.num()); - ch.cr().write_value(self.cr); - } - - /// Clear all data in the ring buffer. - pub fn clear(&mut self) { - self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); - } - - /// Read elements from the ring buffer - /// Return a tuple of the length read and the length remaining in the buffer - /// If not all of the elements were read, then there will be some elements in the buffer remaining - /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. - pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { - self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) - } - - /// Read an exact number of elements from the ringbuffer. - /// - /// Returns the remaining number of elements available for immediate reading. - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. - /// - /// Async/Wake Behavior: - /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, - /// and when it wraps around. This means that when called with a buffer of length 'M', when this - /// ring buffer was created with a buffer of size 'N': - /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. - /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. - pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result { - self.ringbuf - .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) - .await - } - - /// The capacity of the ringbuffer - pub const fn capacity(&self) -> usize { - self.ringbuf.cap() - } - - /// Set a waker to be woken when at least one byte is received. - pub fn set_waker(&mut self, waker: &Waker) { - DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); - } - - fn clear_irqs(&mut self) { - let channel_number = self.channel.num(); - let dma = self.channel.regs(); - let isrn = channel_number / 4; - let isrbit = channel_number % 4; - - dma.ifcr(isrn).write(|w| { - w.set_htif(isrbit, true); - w.set_tcif(isrbit, true); - w.set_teif(isrbit, true); - }); - } - - /// Request DMA to stop. - /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - let ch = self.channel.regs().st(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - ch.cr().write(|w| { - w.set_teie(true); - w.set_htie(true); - w.set_tcie(true); - }); - } - - /// Return whether DMA is still running. - /// - /// If this returns `false`, it can be because either the transfer finished, or - /// it was requested to stop early with [`request_stop`](Self::request_stop). - pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().st(self.channel.num()); - ch.cr().read().en() - } -} - -impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { - fn drop(&mut self) { - self.request_stop(); - while self.is_running() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - } -} - -/// Ringbuffer for writing data using DMA circular mode. -pub struct WritableRingBuffer<'a, C: Channel, W: Word> { - cr: regs::Cr, - channel: PeripheralRef<'a, C>, - ringbuf: WritableDmaRingBuffer<'a, W>, -} - -impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { - /// Create a new ring buffer. - pub unsafe fn new( - channel: impl Peripheral

+ 'a, - _request: Request, - peri_addr: *mut W, - buffer: &'a mut [W], - options: TransferOptions, - ) -> Self { - into_ref!(channel); - - let len = buffer.len(); - assert!(len > 0 && len <= 0xFFFF); - - let dir = Dir::MemoryToPeripheral; - let data_size = W::size(); - - let channel_number = channel.num(); - let dma = channel.regs(); - - // "Preceding reads and writes cannot be moved past subsequent writes." - fence(Ordering::SeqCst); - - let mut w = regs::Cr(0); - w.set_dir(dir.into()); - w.set_msize(data_size.into()); - w.set_psize(data_size.into()); - w.set_pl(vals::Pl::VERYHIGH); - w.set_minc(true); - w.set_pinc(false); - w.set_teie(true); - w.set_htie(options.half_transfer_ir); - w.set_tcie(true); - w.set_circ(true); - #[cfg(dma_v1)] - w.set_trbuff(true); - #[cfg(dma_v2)] - w.set_chsel(_request); - w.set_pburst(options.pburst.into()); - w.set_mburst(options.mburst.into()); - w.set_pfctrl(options.flow_ctrl.into()); - w.set_en(true); - - let buffer_ptr = buffer.as_mut_ptr(); - let mut this = Self { - channel, - cr: w, - ringbuf: WritableDmaRingBuffer::new(buffer), - }; - this.clear_irqs(); - - #[cfg(dmamux)] - super::dmamux::configure_dmamux(&*this.channel, _request); - - let ch = dma.st(channel_number); - ch.par().write_value(peri_addr as u32); - ch.m0ar().write_value(buffer_ptr as u32); - ch.ndtr().write_value(regs::Ndtr(len as _)); - ch.fcr().write(|w| { - if let Some(fth) = options.fifo_threshold { - // FIFO mode - w.set_dmdis(vals::Dmdis::DISABLED); - w.set_fth(fth.into()); - } else { - // Direct mode - w.set_dmdis(vals::Dmdis::ENABLED); - } - }); - - this - } - - /// Start the ring buffer operation. - /// - /// You must call this after creating it for it to work. - pub fn start(&mut self) { - let ch = self.channel.regs().st(self.channel.num()); - ch.cr().write_value(self.cr); - } - - /// Clear all data in the ring buffer. - pub fn clear(&mut self) { - self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); - } - - /// Write elements directly to the raw buffer. - /// This can be used to fill the buffer before starting the DMA transfer. - #[allow(dead_code)] - pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { - self.ringbuf.write_immediate(buf) - } - - /// Write elements from the ring buffer - /// Return a tuple of the length written and the length remaining in the buffer - pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { - self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) - } - - /// Write an exact number of elements to the ringbuffer. - pub async fn write_exact(&mut self, buffer: &[W]) -> Result { - self.ringbuf - .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) - .await - } - - /// The capacity of the ringbuffer - pub const fn capacity(&self) -> usize { - self.ringbuf.cap() - } - - /// Set a waker to be woken when at least one byte is received. - pub fn set_waker(&mut self, waker: &Waker) { - DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); - } - - fn clear_irqs(&mut self) { - let channel_number = self.channel.num(); - let dma = self.channel.regs(); - let isrn = channel_number / 4; - let isrbit = channel_number % 4; - - dma.ifcr(isrn).write(|w| { - w.set_htif(isrbit, true); - w.set_tcif(isrbit, true); - w.set_teif(isrbit, true); - }); - } - - /// Request DMA to stop. - /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - let ch = self.channel.regs().st(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - ch.cr().write(|w| { - w.set_teie(true); - w.set_htie(true); - w.set_tcie(true); - }); - } - - /// Return whether DMA is still running. - /// - /// If this returns `false`, it can be because either the transfer finished, or - /// it was requested to stop early with [`request_stop`](Self::request_stop). - pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().st(self.channel.num()); - ch.cr().read().en() - } -} - -impl<'a, C: Channel, W: Word> Drop for WritableRingBuffer<'a, C, W> { - fn drop(&mut self) { - self.request_stop(); - while self.is_running() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::SeqCst); - } -} diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs new file mode 100644 index 000000000..08aba2795 --- /dev/null +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -0,0 +1,913 @@ +use core::future::Future; +use core::pin::Pin; +use core::sync::atomic::{fence, AtomicUsize, Ordering}; +use core::task::{Context, Poll, Waker}; + +use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; + +use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer}; +use super::word::{Word, WordSize}; +use super::{AnyChannel, Channel, Dir, Request, STATE}; +use crate::interrupt::typelevel::Interrupt; +use crate::interrupt::Priority; +use crate::pac; + +pub(crate) struct ChannelInfo { + pub(crate) dma: DmaInfo, + pub(crate) num: usize, + #[cfg(dmamux)] + pub(crate) dmamux: super::DmamuxInfo, +} + +#[derive(Clone, Copy)] +pub(crate) enum DmaInfo { + #[cfg(dma)] + Dma(pac::dma::Dma), + #[cfg(bdma)] + Bdma(pac::bdma::Dma), +} + +/// DMA transfer options. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct TransferOptions { + /// Peripheral burst transfer configuration + #[cfg(dma)] + pub pburst: Burst, + /// Memory burst transfer configuration + #[cfg(dma)] + pub mburst: Burst, + /// Flow control configuration + #[cfg(dma)] + pub flow_ctrl: FlowControl, + /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. + #[cfg(dma)] + pub fifo_threshold: Option, + /// Enable circular DMA + /// + /// Note: + /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task. + /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever. + pub circular: bool, + /// Enable half transfer interrupt + pub half_transfer_ir: bool, + /// Enable transfer complete interrupt + pub complete_transfer_ir: bool, +} + +impl Default for TransferOptions { + fn default() -> Self { + Self { + #[cfg(dma)] + pburst: Burst::Single, + #[cfg(dma)] + mburst: Burst::Single, + #[cfg(dma)] + flow_ctrl: FlowControl::Dma, + #[cfg(dma)] + fifo_threshold: None, + circular: false, + half_transfer_ir: false, + complete_transfer_ir: true, + } + } +} + +#[cfg(dma)] +pub use dma_only::*; +#[cfg(dma)] +mod dma_only { + use pac::dma::vals; + + use super::*; + + impl From for vals::Size { + fn from(raw: WordSize) -> Self { + match raw { + WordSize::OneByte => Self::BITS8, + WordSize::TwoBytes => Self::BITS16, + WordSize::FourBytes => Self::BITS32, + } + } + } + + impl From

for vals::Dir { + fn from(raw: Dir) -> Self { + match raw { + Dir::MemoryToPeripheral => Self::MEMORYTOPERIPHERAL, + Dir::PeripheralToMemory => Self::PERIPHERALTOMEMORY, + } + } + } + + /// DMA transfer burst setting. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum Burst { + /// Single transfer + Single, + /// Incremental burst of 4 beats + Incr4, + /// Incremental burst of 8 beats + Incr8, + /// Incremental burst of 16 beats + Incr16, + } + + impl From for vals::Burst { + fn from(burst: Burst) -> Self { + match burst { + Burst::Single => vals::Burst::SINGLE, + Burst::Incr4 => vals::Burst::INCR4, + Burst::Incr8 => vals::Burst::INCR8, + Burst::Incr16 => vals::Burst::INCR16, + } + } + } + + /// DMA flow control setting. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum FlowControl { + /// Flow control by DMA + Dma, + /// Flow control by peripheral + Peripheral, + } + + impl From for vals::Pfctrl { + fn from(flow: FlowControl) -> Self { + match flow { + FlowControl::Dma => vals::Pfctrl::DMA, + FlowControl::Peripheral => vals::Pfctrl::PERIPHERAL, + } + } + } + + /// DMA FIFO threshold. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum FifoThreshold { + /// 1/4 full FIFO + Quarter, + /// 1/2 full FIFO + Half, + /// 3/4 full FIFO + ThreeQuarters, + /// Full FIFO + Full, + } + + impl From for vals::Fth { + fn from(value: FifoThreshold) -> Self { + match value { + FifoThreshold::Quarter => vals::Fth::QUARTER, + FifoThreshold::Half => vals::Fth::HALF, + FifoThreshold::ThreeQuarters => vals::Fth::THREEQUARTERS, + FifoThreshold::Full => vals::Fth::FULL, + } + } + } +} + +#[cfg(bdma)] +mod bdma_only { + use pac::bdma::vals; + + use super::*; + + impl From for vals::Size { + fn from(raw: WordSize) -> Self { + match raw { + WordSize::OneByte => Self::BITS8, + WordSize::TwoBytes => Self::BITS16, + WordSize::FourBytes => Self::BITS32, + } + } + } + + impl From for vals::Dir { + fn from(raw: Dir) -> Self { + match raw { + Dir::MemoryToPeripheral => Self::FROMMEMORY, + Dir::PeripheralToMemory => Self::FROMPERIPHERAL, + } + } + } +} + +pub(crate) struct ChannelState { + waker: AtomicWaker, + complete_count: AtomicUsize, +} + +impl ChannelState { + pub(crate) const NEW: Self = Self { + waker: AtomicWaker::new(), + complete_count: AtomicUsize::new(0), + }; +} + +/// safety: must be called only once +pub(crate) unsafe fn init( + cs: critical_section::CriticalSection, + #[cfg(dma)] dma_priority: Priority, + #[cfg(bdma)] bdma_priority: Priority, +) { + foreach_interrupt! { + ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { + crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority); + crate::interrupt::typelevel::$irq::enable(); + }; + ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { + crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority); + crate::interrupt::typelevel::$irq::enable(); + }; + } + crate::_generated::init_dma(); + crate::_generated::init_bdma(); +} + +impl AnyChannel { + /// Safety: Must be called with a matching set of parameters for a valid dma channel + pub(crate) unsafe fn on_irq(&self) { + let info = self.info(); + let state = &STATE[self.id as usize]; + match self.info().dma { + #[cfg(dma)] + DmaInfo::Dma(r) => { + let cr = r.st(info.num).cr(); + let isr = r.isr(info.num / 4).read(); + + if isr.teif(info.num % 4) { + panic!("DMA: error on DMA@{:08x} channel {}", r.as_ptr() as u32, info.num); + } + + if isr.htif(info.num % 4) && cr.read().htie() { + // Acknowledge half transfer complete interrupt + r.ifcr(info.num / 4).write(|w| w.set_htif(info.num % 4, true)); + } else if isr.tcif(info.num % 4) && cr.read().tcie() { + // Acknowledge transfer complete interrupt + r.ifcr(info.num / 4).write(|w| w.set_tcif(info.num % 4, true)); + state.complete_count.fetch_add(1, Ordering::Release); + } else { + return; + } + + state.waker.wake(); + } + #[cfg(bdma)] + DmaInfo::Bdma(r) => { + let isr = r.isr().read(); + let cr = r.ch(info.num).cr(); + + if isr.teif(info.num) { + panic!("DMA: error on BDMA@{:08x} channel {}", r.as_ptr() as u32, info.num); + } + + if isr.htif(info.num) && cr.read().htie() { + // Acknowledge half transfer complete interrupt + r.ifcr().write(|w| w.set_htif(info.num, true)); + } else if isr.tcif(info.num) && cr.read().tcie() { + // Acknowledge transfer complete interrupt + r.ifcr().write(|w| w.set_tcif(info.num, true)); + #[cfg(not(armv6m))] + state.complete_count.fetch_add(1, Ordering::Release); + #[cfg(armv6m)] + critical_section::with(|_| { + let x = state.complete_count.load(Ordering::Relaxed); + state.complete_count.store(x + 1, Ordering::Release); + }) + } else { + return; + } + + state.waker.wake(); + } + } + } + + unsafe fn configure( + &self, + _request: Request, + dir: Dir, + peri_addr: *const u32, + mem_addr: *mut u32, + mem_len: usize, + incr_mem: bool, + data_size: WordSize, + options: TransferOptions, + ) { + let info = self.info(); + + #[cfg(dmamux)] + super::dmamux::configure_dmamux(&info.dmamux, _request); + + assert!(mem_len > 0 && mem_len <= 0xFFFF); + + match self.info().dma { + #[cfg(dma)] + DmaInfo::Dma(r) => { + let ch = r.st(info.num); + + // "Preceding reads and writes cannot be moved past subsequent writes." + fence(Ordering::SeqCst); + + self.clear_irqs(); + + ch.par().write_value(peri_addr as u32); + ch.m0ar().write_value(mem_addr as u32); + ch.ndtr().write_value(pac::dma::regs::Ndtr(mem_len as _)); + ch.fcr().write(|w| { + if let Some(fth) = options.fifo_threshold { + // FIFO mode + w.set_dmdis(pac::dma::vals::Dmdis::DISABLED); + w.set_fth(fth.into()); + } else { + // Direct mode + w.set_dmdis(pac::dma::vals::Dmdis::ENABLED); + } + }); + ch.cr().write(|w| { + w.set_dir(dir.into()); + w.set_msize(data_size.into()); + w.set_psize(data_size.into()); + w.set_pl(pac::dma::vals::Pl::VERYHIGH); + w.set_minc(incr_mem); + w.set_pinc(false); + w.set_teie(true); + w.set_htie(options.half_transfer_ir); + w.set_tcie(options.complete_transfer_ir); + w.set_circ(options.circular); + #[cfg(dma_v1)] + w.set_trbuff(true); + #[cfg(dma_v2)] + w.set_chsel(_request); + w.set_pburst(options.pburst.into()); + w.set_mburst(options.mburst.into()); + w.set_pfctrl(options.flow_ctrl.into()); + w.set_en(false); // don't start yet + }); + } + #[cfg(bdma)] + DmaInfo::Bdma(r) => { + #[cfg(bdma_v2)] + critical_section::with(|_| r.cselr().modify(|w| w.set_cs(info.num, _request))); + + let state: &ChannelState = &STATE[self.id as usize]; + let ch = r.ch(info.num); + + state.complete_count.store(0, Ordering::Release); + self.clear_irqs(); + + ch.par().write_value(peri_addr as u32); + ch.mar().write_value(mem_addr as u32); + ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); + ch.cr().write(|w| { + w.set_psize(data_size.into()); + w.set_msize(data_size.into()); + w.set_minc(incr_mem); + w.set_dir(dir.into()); + w.set_teie(true); + w.set_tcie(options.complete_transfer_ir); + w.set_htie(options.half_transfer_ir); + w.set_circ(options.circular); + w.set_pl(pac::bdma::vals::Pl::VERYHIGH); + w.set_en(false); // don't start yet + }); + } + } + } + + fn start(&self) { + let info = self.info(); + match self.info().dma { + #[cfg(dma)] + DmaInfo::Dma(r) => { + let ch = r.st(info.num); + ch.cr().modify(|w| w.set_en(true)) + } + #[cfg(bdma)] + DmaInfo::Bdma(r) => { + let ch = r.ch(info.num); + ch.cr().modify(|w| w.set_en(true)); + } + } + } + + fn clear_irqs(&self) { + let info = self.info(); + match self.info().dma { + #[cfg(dma)] + DmaInfo::Dma(r) => { + let isrn = info.num / 4; + let isrbit = info.num % 4; + + r.ifcr(isrn).write(|w| { + w.set_htif(isrbit, true); + w.set_tcif(isrbit, true); + w.set_teif(isrbit, true); + }); + } + #[cfg(bdma)] + DmaInfo::Bdma(r) => { + r.ifcr().write(|w| { + w.set_htif(info.num, true); + w.set_tcif(info.num, true); + w.set_teif(info.num, true); + }); + } + } + } + + fn request_stop(&self) { + let info = self.info(); + match self.info().dma { + #[cfg(dma)] + DmaInfo::Dma(r) => { + // Disable the channel. Keep the IEs enabled so the irqs still fire. + r.st(info.num).cr().write(|w| { + w.set_teie(true); + w.set_tcie(true); + }); + } + #[cfg(bdma)] + DmaInfo::Bdma(r) => { + // Disable the channel. Keep the IEs enabled so the irqs still fire. + r.ch(info.num).cr().write(|w| { + w.set_teie(true); + w.set_tcie(true); + }); + } + } + } + + fn is_running(&self) -> bool { + let info = self.info(); + match self.info().dma { + #[cfg(dma)] + DmaInfo::Dma(r) => r.st(info.num).cr().read().en(), + #[cfg(bdma)] + DmaInfo::Bdma(r) => { + let state: &ChannelState = &STATE[self.id as usize]; + let ch = r.ch(info.num); + let en = ch.cr().read().en(); + let circular = ch.cr().read().circ(); + let tcif = state.complete_count.load(Ordering::Acquire) != 0; + en && (circular || !tcif) + } + } + } + + fn get_remaining_transfers(&self) -> u16 { + let info = self.info(); + match self.info().dma { + #[cfg(dma)] + DmaInfo::Dma(r) => r.st(info.num).ndtr().read().ndt(), + #[cfg(bdma)] + DmaInfo::Bdma(r) => r.ch(info.num).ndtr().read().ndt(), + } + } +} + +/// DMA transfer. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Transfer<'a> { + channel: PeripheralRef<'a, AnyChannel>, +} + +impl<'a> Transfer<'a> { + /// Create a new read DMA transfer (peripheral to memory). + pub unsafe fn new_read( + channel: impl Peripheral

+ 'a, + request: Request, + peri_addr: *mut W, + buf: &'a mut [W], + options: TransferOptions, + ) -> Self { + Self::new_read_raw(channel, request, peri_addr, buf, options) + } + + /// Create a new read DMA transfer (peripheral to memory), using raw pointers. + pub unsafe fn new_read_raw( + channel: impl Peripheral

+ 'a, + request: Request, + peri_addr: *mut W, + buf: *mut [W], + options: TransferOptions, + ) -> Self { + into_ref!(channel); + + let (ptr, len) = super::slice_ptr_parts_mut(buf); + assert!(len > 0 && len <= 0xFFFF); + + Self::new_inner( + channel.map_into(), + request, + Dir::PeripheralToMemory, + peri_addr as *const u32, + ptr as *mut u32, + len, + true, + W::size(), + options, + ) + } + + /// Create a new write DMA transfer (memory to peripheral). + pub unsafe fn new_write( + channel: impl Peripheral

+ 'a, + request: Request, + buf: &'a [W], + peri_addr: *mut W, + options: TransferOptions, + ) -> Self { + Self::new_write_raw(channel, request, buf, peri_addr, options) + } + + /// Create a new write DMA transfer (memory to peripheral), using raw pointers. + pub unsafe fn new_write_raw( + channel: impl Peripheral

+ 'a, + request: Request, + buf: *const [W], + peri_addr: *mut W, + options: TransferOptions, + ) -> Self { + into_ref!(channel); + + let (ptr, len) = super::slice_ptr_parts(buf); + assert!(len > 0 && len <= 0xFFFF); + + Self::new_inner( + channel.map_into(), + request, + Dir::MemoryToPeripheral, + peri_addr as *const u32, + ptr as *mut u32, + len, + true, + W::size(), + options, + ) + } + + /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. + pub unsafe fn new_write_repeated( + channel: impl Peripheral

+ 'a, + request: Request, + repeated: &'a W, + count: usize, + peri_addr: *mut W, + options: TransferOptions, + ) -> Self { + into_ref!(channel); + + Self::new_inner( + channel.map_into(), + request, + Dir::MemoryToPeripheral, + peri_addr as *const u32, + repeated as *const W as *mut u32, + count, + false, + W::size(), + options, + ) + } + + unsafe fn new_inner( + channel: PeripheralRef<'a, AnyChannel>, + _request: Request, + dir: Dir, + peri_addr: *const u32, + mem_addr: *mut u32, + mem_len: usize, + incr_mem: bool, + data_size: WordSize, + options: TransferOptions, + ) -> Self { + channel.configure( + _request, dir, peri_addr, mem_addr, mem_len, incr_mem, data_size, options, + ); + channel.start(); + + Self { channel } + } + + /// Request the transfer to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. + pub fn request_stop(&mut self) { + self.channel.request_stop() + } + + /// Return whether this transfer is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). + pub fn is_running(&mut self) -> bool { + self.channel.is_running() + } + + /// Gets the total remaining transfers for the channel + /// Note: this will be zero for transfers that completed without cancellation. + pub fn get_remaining_transfers(&self) -> u16 { + self.channel.get_remaining_transfers() + } + + /// Blocking wait until the transfer finishes. + pub fn blocking_wait(mut self) { + while self.is_running() {} + + // "Subsequent reads and writes cannot be moved ahead of preceding reads." + fence(Ordering::SeqCst); + + core::mem::forget(self); + } +} + +impl<'a> Drop for Transfer<'a> { + fn drop(&mut self) { + self.request_stop(); + while self.is_running() {} + + // "Subsequent reads and writes cannot be moved ahead of preceding reads." + fence(Ordering::SeqCst); + } +} + +impl<'a> Unpin for Transfer<'a> {} +impl<'a> Future for Transfer<'a> { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let state: &ChannelState = &STATE[self.channel.id as usize]; + + state.waker.register(cx.waker()); + + if self.is_running() { + Poll::Pending + } else { + Poll::Ready(()) + } + } +} + +// ============================== + +struct DmaCtrlImpl<'a>(PeripheralRef<'a, AnyChannel>); + +impl<'a> DmaCtrl for DmaCtrlImpl<'a> { + fn get_remaining_transfers(&self) -> usize { + self.0.get_remaining_transfers() as _ + } + + fn get_complete_count(&self) -> usize { + STATE[self.0.id as usize].complete_count.load(Ordering::Acquire) + } + + fn reset_complete_count(&mut self) -> usize { + let state = &STATE[self.0.id as usize]; + #[cfg(not(armv6m))] + return state.complete_count.swap(0, Ordering::AcqRel); + #[cfg(armv6m)] + return critical_section::with(|_| { + let x = state.complete_count.load(Ordering::Acquire); + state.complete_count.store(0, Ordering::Release); + x + }); + } + + fn set_waker(&mut self, waker: &Waker) { + STATE[self.0.id as usize].waker.register(waker); + } +} + +/// Ringbuffer for receiving data using DMA circular mode. +pub struct ReadableRingBuffer<'a, W: Word> { + channel: PeripheralRef<'a, AnyChannel>, + ringbuf: ReadableDmaRingBuffer<'a, W>, +} + +impl<'a, W: Word> ReadableRingBuffer<'a, W> { + /// Create a new ring buffer. + pub unsafe fn new( + channel: impl Peripheral

+ 'a, + _request: Request, + peri_addr: *mut W, + buffer: &'a mut [W], + mut options: TransferOptions, + ) -> Self { + into_ref!(channel); + let channel: PeripheralRef<'a, AnyChannel> = channel.map_into(); + + let buffer_ptr = buffer.as_mut_ptr(); + let len = buffer.len(); + let dir = Dir::PeripheralToMemory; + let data_size = W::size(); + + options.complete_transfer_ir = true; + options.circular = true; + + channel.configure( + _request, + dir, + peri_addr as *mut u32, + buffer_ptr as *mut u32, + len, + true, + data_size, + options, + ); + + Self { + channel, + ringbuf: ReadableDmaRingBuffer::new(buffer), + } + } + + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. + pub fn start(&mut self) { + self.channel.start() + } + + /// Clear all data in the ring buffer. + pub fn clear(&mut self) { + self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); + } + + /// Read elements from the ring buffer + /// Return a tuple of the length read and the length remaining in the buffer + /// If not all of the elements were read, then there will be some elements in the buffer remaining + /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read + /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. + pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { + self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) + } + + /// Read an exact number of elements from the ringbuffer. + /// + /// Returns the remaining number of elements available for immediate reading. + /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. + /// + /// Async/Wake Behavior: + /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, + /// and when it wraps around. This means that when called with a buffer of length 'M', when this + /// ring buffer was created with a buffer of size 'N': + /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. + /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. + pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result { + self.ringbuf + .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) + .await + } + + /// The capacity of the ringbuffer + pub const fn capacity(&self) -> usize { + self.ringbuf.cap() + } + + /// Set a waker to be woken when at least one byte is received. + pub fn set_waker(&mut self, waker: &Waker) { + DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); + } + + /// Request DMA to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. + pub fn request_stop(&mut self) { + self.channel.request_stop() + } + + /// Return whether DMA is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). + pub fn is_running(&mut self) -> bool { + self.channel.is_running() + } +} + +impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { + fn drop(&mut self) { + self.request_stop(); + while self.is_running() {} + + // "Subsequent reads and writes cannot be moved ahead of preceding reads." + fence(Ordering::SeqCst); + } +} + +/// Ringbuffer for writing data using DMA circular mode. +pub struct WritableRingBuffer<'a, W: Word> { + channel: PeripheralRef<'a, AnyChannel>, + ringbuf: WritableDmaRingBuffer<'a, W>, +} + +impl<'a, W: Word> WritableRingBuffer<'a, W> { + /// Create a new ring buffer. + pub unsafe fn new( + channel: impl Peripheral

+ 'a, + _request: Request, + peri_addr: *mut W, + buffer: &'a mut [W], + mut options: TransferOptions, + ) -> Self { + into_ref!(channel); + let channel: PeripheralRef<'a, AnyChannel> = channel.map_into(); + + let len = buffer.len(); + let dir = Dir::MemoryToPeripheral; + let data_size = W::size(); + let buffer_ptr = buffer.as_mut_ptr(); + + options.complete_transfer_ir = true; + options.circular = true; + + channel.configure( + _request, + dir, + peri_addr as *mut u32, + buffer_ptr as *mut u32, + len, + true, + data_size, + options, + ); + + Self { + channel, + ringbuf: WritableDmaRingBuffer::new(buffer), + } + } + + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. + pub fn start(&mut self) { + self.channel.start() + } + + /// Clear all data in the ring buffer. + pub fn clear(&mut self) { + self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); + } + + /// Write elements directly to the raw buffer. + /// This can be used to fill the buffer before starting the DMA transfer. + #[allow(dead_code)] + pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + self.ringbuf.write_immediate(buf) + } + + /// Write elements from the ring buffer + /// Return a tuple of the length written and the length remaining in the buffer + pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) + } + + /// Write an exact number of elements to the ringbuffer. + pub async fn write_exact(&mut self, buffer: &[W]) -> Result { + self.ringbuf + .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) + .await + } + + /// The capacity of the ringbuffer + pub const fn capacity(&self) -> usize { + self.ringbuf.cap() + } + + /// Set a waker to be woken when at least one byte is received. + pub fn set_waker(&mut self, waker: &Waker) { + DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); + } + + /// Request DMA to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. + pub fn request_stop(&mut self) { + self.channel.request_stop() + } + + /// Return whether DMA is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). + pub fn is_running(&mut self) -> bool { + self.channel.is_running() + } +} + +impl<'a, W: Word> Drop for WritableRingBuffer<'a, W> { + fn drop(&mut self) { + self.request_stop(); + while self.is_running() {} + + // "Subsequent reads and writes cannot be moved ahead of preceding reads." + fence(Ordering::SeqCst); + } +} diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index ac6f44107..1e9ab5944 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -1,9 +1,14 @@ #![macro_use] -use crate::{pac, peripherals}; +use crate::pac; -pub(crate) fn configure_dmamux(channel: &M, request: u8) { - let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); +pub(crate) struct DmamuxInfo { + pub(crate) mux: pac::dmamux::Dmamux, + pub(crate) num: usize, +} + +pub(crate) fn configure_dmamux(info: &DmamuxInfo, request: u8) { + let ch_mux_regs = info.mux.ccr(info.num); ch_mux_regs.write(|reg| { reg.set_nbreq(0); reg.set_dmareq_id(request); @@ -15,11 +20,7 @@ pub(crate) fn configure_dmamux(channel: &M, request: u8) { } pub(crate) mod dmamux_sealed { - use super::*; - pub trait MuxChannel { - fn mux_regs(&self) -> pac::dmamux::Dmamux; - fn mux_num(&self) -> usize; - } + pub trait MuxChannel {} } /// DMAMUX1 instance. @@ -34,18 +35,11 @@ pub trait MuxChannel: dmamux_sealed::MuxChannel { type Mux; } -foreach_dma_channel! { - ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, $index:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => { - impl dmamux_sealed::MuxChannel for peripherals::$channel_peri { - fn mux_regs(&self) -> pac::dmamux::Dmamux { - pac::$dmamux - } - fn mux_num(&self) -> usize { - $dmamux_channel - } - } - impl MuxChannel for peripherals::$channel_peri { - type Mux = $dmamux; +macro_rules! dmamux_channel_impl { + ($channel_peri:ident, $dmamux:ident) => { + impl crate::dma::dmamux_sealed::MuxChannel for crate::peripherals::$channel_peri {} + impl crate::dma::MuxChannel for crate::peripherals::$channel_peri { + type Mux = crate::dma::$dmamux; } }; } diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 337e7b309..ef03970ef 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -9,13 +9,17 @@ use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use super::word::{Word, WordSize}; -use super::Dir; -use crate::_generated::GPDMA_CHANNEL_COUNT; +use super::{AnyChannel, Channel, Dir, Request, STATE}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::Priority; use crate::pac; use crate::pac::gpdma::vals; +pub(crate) struct ChannelInfo { + pub(crate) dma: pac::gpdma::Gpdma, + pub(crate) num: usize, +} + /// GPDMA transfer options. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -38,21 +42,16 @@ impl From for vals::ChTr1Dw { } } -struct State { - ch_wakers: [AtomicWaker; GPDMA_CHANNEL_COUNT], +pub(crate) struct ChannelState { + waker: AtomicWaker, } -impl State { - const fn new() -> Self { - const AW: AtomicWaker = AtomicWaker::new(); - Self { - ch_wakers: [AW; GPDMA_CHANNEL_COUNT], - } - } +impl ChannelState { + pub(crate) const NEW: Self = Self { + waker: AtomicWaker::new(), + }; } -static STATE: State = State::new(); - /// safety: must be called only once pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) { foreach_interrupt! { @@ -64,87 +63,50 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: P crate::_generated::init_gpdma(); } -foreach_dma_channel! { - ($channel_peri:ident, $dma_peri:ident, gpdma, $channel_num:expr, $index:expr, $dmamux:tt) => { - impl sealed::Channel for crate::peripherals::$channel_peri { - fn regs(&self) -> pac::gpdma::Gpdma { - pac::$dma_peri - } - fn num(&self) -> usize { - $channel_num - } - fn index(&self) -> usize { - $index - } - fn on_irq() { - unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) } - } +impl AnyChannel { + /// Safety: Must be called with a matching set of parameters for a valid dma channel + pub(crate) unsafe fn on_irq(&self) { + let info = self.info(); + let state = &STATE[self.id as usize]; + + let ch = info.dma.ch(info.num); + let sr = ch.sr().read(); + + if sr.dtef() { + panic!( + "DMA: data transfer error on DMA@{:08x} channel {}", + info.dma.as_ptr() as u32, + info.num + ); + } + if sr.usef() { + panic!( + "DMA: user settings error on DMA@{:08x} channel {}", + info.dma.as_ptr() as u32, + info.num + ); } - impl Channel for crate::peripherals::$channel_peri {} - }; -} + if sr.suspf() || sr.tcf() { + // disable all xxIEs to prevent the irq from firing again. + ch.cr().write(|_| {}); -/// Safety: Must be called with a matching set of parameters for a valid dma channel -pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, index: usize) { - let ch = dma.ch(channel_num); - let sr = ch.sr().read(); - - if sr.dtef() { - panic!( - "DMA: data transfer error on DMA@{:08x} channel {}", - dma.as_ptr() as u32, - channel_num - ); - } - if sr.usef() { - panic!( - "DMA: user settings error on DMA@{:08x} channel {}", - dma.as_ptr() as u32, - channel_num - ); - } - - if sr.suspf() || sr.tcf() { - // disable all xxIEs to prevent the irq from firing again. - ch.cr().write(|_| {}); - - // Wake the future. It'll look at tcf and see it's set. - STATE.ch_wakers[index].wake(); - } -} - -/// DMA request type alias. (also known as DMA channel number in some chips) -pub type Request = u8; - -/// DMA channel. -#[cfg(dmamux)] -pub trait Channel: sealed::Channel + Peripheral

+ 'static + super::dmamux::MuxChannel {} -/// DMA channel. -#[cfg(not(dmamux))] -pub trait Channel: sealed::Channel + Peripheral

+ 'static {} - -pub(crate) mod sealed { - use super::*; - - pub trait Channel { - fn regs(&self) -> pac::gpdma::Gpdma; - fn num(&self) -> usize; - fn index(&self) -> usize; - fn on_irq(); + // Wake the future. It'll look at tcf and see it's set. + state.waker.wake(); + } } } /// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Transfer<'a, C: Channel> { - channel: PeripheralRef<'a, C>, +pub struct Transfer<'a> { + channel: PeripheralRef<'a, AnyChannel>, } -impl<'a, C: Channel> Transfer<'a, C> { +impl<'a> Transfer<'a> { /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( - channel: impl Peripheral

+ 'a, + channel: impl Peripheral

+ 'a, request: Request, peri_addr: *mut W, buf: &'a mut [W], @@ -155,7 +117,7 @@ impl<'a, C: Channel> Transfer<'a, C> { /// Create a new read DMA transfer (peripheral to memory), using raw pointers. pub unsafe fn new_read_raw( - channel: impl Peripheral

+ 'a, + channel: impl Peripheral

+ 'a, request: Request, peri_addr: *mut W, buf: *mut [W], @@ -167,7 +129,7 @@ impl<'a, C: Channel> Transfer<'a, C> { assert!(len > 0 && len <= 0xFFFF); Self::new_inner( - channel, + channel.map_into(), request, Dir::PeripheralToMemory, peri_addr as *const u32, @@ -181,7 +143,7 @@ impl<'a, C: Channel> Transfer<'a, C> { /// Create a new write DMA transfer (memory to peripheral). pub unsafe fn new_write( - channel: impl Peripheral

+ 'a, + channel: impl Peripheral

+ 'a, request: Request, buf: &'a [W], peri_addr: *mut W, @@ -192,7 +154,7 @@ impl<'a, C: Channel> Transfer<'a, C> { /// Create a new write DMA transfer (memory to peripheral), using raw pointers. pub unsafe fn new_write_raw( - channel: impl Peripheral

+ 'a, + channel: impl Peripheral

+ 'a, request: Request, buf: *const [W], peri_addr: *mut W, @@ -204,7 +166,7 @@ impl<'a, C: Channel> Transfer<'a, C> { assert!(len > 0 && len <= 0xFFFF); Self::new_inner( - channel, + channel.map_into(), request, Dir::MemoryToPeripheral, peri_addr as *const u32, @@ -218,7 +180,7 @@ impl<'a, C: Channel> Transfer<'a, C> { /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. pub unsafe fn new_write_repeated( - channel: impl Peripheral

+ 'a, + channel: impl Peripheral

+ 'a, request: Request, repeated: &'a W, count: usize, @@ -228,7 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> { into_ref!(channel); Self::new_inner( - channel, + channel.map_into(), request, Dir::MemoryToPeripheral, peri_addr as *const u32, @@ -241,7 +203,7 @@ impl<'a, C: Channel> Transfer<'a, C> { } unsafe fn new_inner( - channel: PeripheralRef<'a, C>, + channel: PeripheralRef<'a, AnyChannel>, request: Request, dir: Dir, peri_addr: *const u32, @@ -251,7 +213,8 @@ impl<'a, C: Channel> Transfer<'a, C> { data_size: WordSize, _options: TransferOptions, ) -> Self { - let ch = channel.regs().ch(channel.num()); + let info = channel.info(); + let ch = info.dma.ch(info.num); // "Preceding reads and writes cannot be moved past subsequent writes." fence(Ordering::SeqCst); @@ -311,10 +274,10 @@ impl<'a, C: Channel> Transfer<'a, C> { /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { - let ch = self.channel.regs().ch(self.channel.num()); - ch.cr().modify(|w| { - w.set_susp(true); - }) + let info = self.channel.info(); + let ch = info.dma.ch(info.num); + + ch.cr().modify(|w| w.set_susp(true)) } /// Return whether this transfer is still running. @@ -322,7 +285,9 @@ impl<'a, C: Channel> Transfer<'a, C> { /// If this returns `false`, it can be because either the transfer finished, or /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().ch(self.channel.num()); + let info = self.channel.info(); + let ch = info.dma.ch(info.num); + let sr = ch.sr().read(); !sr.tcf() && !sr.suspf() } @@ -330,7 +295,9 @@ impl<'a, C: Channel> Transfer<'a, C> { /// Gets the total remaining transfers for the channel /// Note: this will be zero for transfers that completed without cancellation. pub fn get_remaining_transfers(&self) -> u16 { - let ch = self.channel.regs().ch(self.channel.num()); + let info = self.channel.info(); + let ch = info.dma.ch(info.num); + ch.br1().read().bndt() } @@ -345,7 +312,7 @@ impl<'a, C: Channel> Transfer<'a, C> { } } -impl<'a, C: Channel> Drop for Transfer<'a, C> { +impl<'a> Drop for Transfer<'a> { fn drop(&mut self) { self.request_stop(); while self.is_running() {} @@ -355,11 +322,12 @@ impl<'a, C: Channel> Drop for Transfer<'a, C> { } } -impl<'a, C: Channel> Unpin for Transfer<'a, C> {} -impl<'a, C: Channel> Future for Transfer<'a, C> { +impl<'a> Unpin for Transfer<'a> {} +impl<'a> Future for Transfer<'a> { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - STATE.ch_wakers[self.channel.index()].register(cx.waker()); + let state = &STATE[self.channel.id as usize]; + state.waker.register(cx.waker()); if self.is_running() { Poll::Pending diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 38945ac33..6b1ac6207 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -1,19 +1,10 @@ //! Direct Memory Access (DMA) +#![macro_use] -#[cfg(dma)] -pub(crate) mod dma; -#[cfg(dma)] -pub use dma::*; - -// stm32h7 has both dma and bdma. In that case, we export dma as "main" dma, -// and bdma as "secondary", under `embassy_stm32::dma::bdma`. -#[cfg(all(bdma, dma))] -pub mod bdma; - -#[cfg(all(bdma, not(dma)))] -pub(crate) mod bdma; -#[cfg(all(bdma, not(dma)))] -pub use bdma::*; +#[cfg(any(bdma, dma))] +mod dma_bdma; +#[cfg(any(bdma, dma))] +pub use dma_bdma::*; #[cfg(gpdma)] pub(crate) mod gpdma; @@ -22,16 +13,16 @@ pub use gpdma::*; #[cfg(dmamux)] mod dmamux; +#[cfg(dmamux)] +pub use dmamux::*; pub(crate) mod ringbuffer; pub mod word; use core::mem; -use embassy_hal_internal::impl_peripheral; +use embassy_hal_internal::{impl_peripheral, Peripheral}; -#[cfg(dmamux)] -pub use self::dmamux::*; use crate::interrupt::Priority; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -41,6 +32,73 @@ enum Dir { PeripheralToMemory, } +/// DMA request type alias. (also known as DMA channel number in some chips) +#[cfg(any(dma_v2, bdma_v2, gpdma, dmamux))] +pub type Request = u8; +/// DMA request type alias. (also known as DMA channel number in some chips) +#[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] +pub type Request = (); + +pub(crate) mod sealed { + pub trait Channel { + fn id(&self) -> u8; + } + pub trait ChannelInterrupt { + unsafe fn on_irq(); + } +} + +/// DMA channel. +pub trait Channel: sealed::Channel + Peripheral

+ Into + 'static { + /// Type-erase (degrade) this pin into an `AnyChannel`. + /// + /// This converts DMA channel singletons (`DMA1_CH3`, `DMA2_CH1`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of channels, or avoiding generics. + #[inline] + fn degrade(self) -> AnyChannel { + AnyChannel { id: self.id() } + } +} + +macro_rules! dma_channel_impl { + ($channel_peri:ident, $index:expr) => { + impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { + fn id(&self) -> u8 { + $index + } + } + impl crate::dma::sealed::ChannelInterrupt for crate::peripherals::$channel_peri { + unsafe fn on_irq() { + crate::dma::AnyChannel { id: $index }.on_irq(); + } + } + + impl crate::dma::Channel for crate::peripherals::$channel_peri {} + + impl From for crate::dma::AnyChannel { + fn from(x: crate::peripherals::$channel_peri) -> Self { + crate::dma::Channel::degrade(x) + } + } + }; +} + +/// Type-erased DMA channel. +pub struct AnyChannel { + pub(crate) id: u8, +} +impl_peripheral!(AnyChannel); + +impl AnyChannel { + fn info(&self) -> &ChannelInfo { + &crate::_generated::DMA_CHANNELS[self.id as usize] + } +} + +const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len(); +static STATE: [ChannelState; CHANNEL_COUNT] = [ChannelState::NEW; CHANNEL_COUNT]; + /// "No DMA" placeholder. /// /// You may pass this in place of a real DMA channel when creating a driver @@ -70,10 +128,14 @@ pub(crate) unsafe fn init( #[cfg(dma)] dma_priority: Priority, #[cfg(gpdma)] gpdma_priority: Priority, ) { - #[cfg(bdma)] - bdma::init(cs, bdma_priority); - #[cfg(dma)] - dma::init(cs, dma_priority); + #[cfg(any(dma, bdma))] + dma_bdma::init( + cs, + #[cfg(dma)] + dma_priority, + #[cfg(bdma)] + bdma_priority, + ); #[cfg(gpdma)] gpdma::init(cs, gpdma_priority); #[cfg(dmamux)] diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 5e647612c..b6c3e4028 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -501,9 +501,9 @@ impl Config { } } -enum RingBuffer<'d, C: Channel, W: word::Word> { - Writable(WritableRingBuffer<'d, C, W>), - Readable(ReadableRingBuffer<'d, C, W>), +enum RingBuffer<'d, W: word::Word> { + Writable(WritableRingBuffer<'d, W>), + Readable(ReadableRingBuffer<'d, W>), } #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] @@ -528,13 +528,13 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { ) } -fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( - dma: impl Peripheral

+ 'd, +fn get_ring_buffer<'d, T: Instance, W: word::Word>( + dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], request: Request, sub_block: WhichSubBlock, tx_rx: TxRx, -) -> RingBuffer<'d, C, W> { +) -> RingBuffer<'d, W> { let opts = TransferOptions { half_transfer_ir: true, //the new_write() and new_read() always use circular mode @@ -593,17 +593,17 @@ pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (S } /// SAI sub-block driver. -pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { +pub struct Sai<'d, T: Instance, W: word::Word> { _peri: PeripheralRef<'d, T>, sd: Option>, fs: Option>, sck: Option>, mclk: Option>, - ring_buffer: RingBuffer<'d, C, W>, + ring_buffer: RingBuffer<'d, W>, sub_block: WhichSubBlock, } -impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { +impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// Create a new SAI driver in asynchronous mode with MCLK. /// /// You can obtain the [`SubBlock`] with [`split_subblocks`]. @@ -613,13 +613,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { sd: impl Peripheral

> + 'd, fs: impl Peripheral

> + 'd, mclk: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> Self - where - C: Channel + Dma, - { + ) -> Self { into_ref!(mclk); let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -642,13 +639,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { sck: impl Peripheral

> + 'd, sd: impl Peripheral

> + 'd, fs: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, dma_buf: &'d mut [W], config: Config, - ) -> Self - where - C: Channel + Dma, - { + ) -> Self { let peri = peri.peri; into_ref!(peri, dma, sck, sd, fs); @@ -671,7 +665,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { None, Some(sd.map_into()), Some(fs.map_into()), - get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), + get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), config, ) } @@ -682,13 +676,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { pub fn new_synchronous( peri: SubBlock<'d, T, S>, sd: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> Self - where - C: Channel + Dma, - { + ) -> Self { update_synchronous_config(&mut config); let peri = peri.peri; @@ -709,7 +700,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { None, Some(sd.map_into()), None, - get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), + get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), config, ) } @@ -721,7 +712,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { mclk: Option>, sd: Option>, fs: Option>, - ring_buffer: RingBuffer<'d, C, W>, + ring_buffer: RingBuffer<'d, W>, config: Config, ) -> Self { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] @@ -830,7 +821,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { } } - fn is_transmitter(ring_buffer: &RingBuffer) -> bool { + fn is_transmitter(ring_buffer: &RingBuffer) -> bool { match ring_buffer { RingBuffer::Writable(_) => true, _ => false, @@ -889,7 +880,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { } } -impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> { +impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> { fn drop(&mut self) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 61589a215..bf1d2ca9b 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -228,10 +228,10 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> { } #[cfg(sdmmc_v1)] -type Transfer<'a, C> = crate::dma::Transfer<'a, C>; +type Transfer<'a> = crate::dma::Transfer<'a>; #[cfg(sdmmc_v2)] -struct Transfer<'a, C> { - _dummy: core::marker::PhantomData<&'a mut C>, +struct Transfer<'a> { + _dummy: PhantomData<&'a ()>, } #[cfg(all(sdmmc_v1, dma))] @@ -548,7 +548,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { buffer: &'a mut [u32], length_bytes: u32, block_size: u8, - ) -> Transfer<'a, Dma> { + ) -> Transfer<'a> { assert!(block_size <= 14, "Block size up to 2^14 bytes"); let regs = T::regs(); @@ -596,12 +596,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// # Safety /// /// `buffer` must be valid for the whole transfer and word aligned - fn prepare_datapath_write<'a>( - &'a mut self, - buffer: &'a [u32], - length_bytes: u32, - block_size: u8, - ) -> Transfer<'a, Dma> { + fn prepare_datapath_write<'a>(&'a mut self, buffer: &'a [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> { assert!(block_size <= 14, "Block size up to 2^14 bytes"); let regs = T::regs(); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index a0ab060a3..b852f0176 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -7,19 +7,19 @@ use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralRef; use futures::future::{select, Either}; -use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, RxDma, UartRx}; +use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx}; use crate::dma::ReadableRingBuffer; use crate::usart::{Regs, Sr}; /// Rx-only Ring-buffered UART Driver /// /// Created with [UartRx::into_ring_buffered] -pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma> { +pub struct RingBufferedUartRx<'d, T: BasicInstance> { _peri: PeripheralRef<'d, T>, - ring_buf: ReadableRingBuffer<'d, RxDma, u8>, + ring_buf: ReadableRingBuffer<'d, u8>, } -impl<'d, T: BasicInstance, RxDma: super::RxDma> SetConfig for RingBufferedUartRx<'d, T, RxDma> { +impl<'d, T: BasicInstance> SetConfig for RingBufferedUartRx<'d, T> { type Config = Config; type ConfigError = ConfigError; @@ -32,7 +32,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { /// Turn the `UartRx` into a buffered uart which can continously receive in the background /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the /// DMA controller, and must be large enough to prevent overflows. - pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { + pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); let request = self.rx_dma.request(); @@ -51,7 +51,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { } } -impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxDma> { +impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> { /// Clear the ring buffer and start receiving in the background pub fn start(&mut self) -> Result<(), Error> { // Clear the ring buffer so that it is ready to receive data @@ -208,7 +208,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD } } -impl> Drop for RingBufferedUartRx<'_, T, RxDma> { +impl Drop for RingBufferedUartRx<'_, T> { fn drop(&mut self) { self.teardown_uart(); @@ -245,18 +245,16 @@ fn clear_idle_flag(r: Regs) -> Sr { sr } -impl embedded_io_async::ErrorType for RingBufferedUartRx<'_, T, Rx> +impl embedded_io_async::ErrorType for RingBufferedUartRx<'_, T> where T: BasicInstance, - Rx: RxDma, { type Error = Error; } -impl embedded_io_async::Read for RingBufferedUartRx<'_, T, Rx> +impl embedded_io_async::Read for RingBufferedUartRx<'_, T> where T: BasicInstance, - Rx: RxDma, { async fn read(&mut self, buf: &mut [u8]) -> Result { self.read(buf).await diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index f5d618db4..0c110421d 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -74,7 +74,7 @@ async fn transmit_task(mut tx: UartTx<'static, peris::UART, peris::UART_TX_DMA>) } #[embassy_executor::task] -async fn receive_task(mut rx: RingBufferedUartRx<'static, peris::UART, peris::UART_RX_DMA>) { +async fn receive_task(mut rx: RingBufferedUartRx<'static, peris::UART>) { info!("Ready to receive..."); let mut rng = ChaCha8Rng::seed_from_u64(1337); From e79d2dd7561c0acfb2eb81ea95929c1ca8ba1b77 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Sat, 24 Feb 2024 12:54:58 -0800 Subject: [PATCH 548/760] Move to internal mod and re-export the enums --- embassy-stm32/build.rs | 37 +++++++++++++++++++------------ embassy-stm32/src/rcc/f013.rs | 14 +++++------- embassy-stm32/src/rcc/mod.rs | 2 +- examples/stm32f334/src/bin/pwm.rs | 4 +--- 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index a0b74c0b9..64d8afa13 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -601,7 +601,7 @@ fn main() { .iter() .map(|(_fieldset, fieldname, enum_name)| { quote! { - pub #fieldname: Option + pub #fieldname: Option<#enum_name> } }) .collect(); @@ -627,23 +627,32 @@ fn main() { }) .collect(); - g.extend(quote! { - #[derive(Clone, Copy)] - pub struct ClockMux { - #( #struct_fields, )* - } + let enum_names: BTreeSet<_> = rcc_cfgr_regs + .iter() + .map(|(_fieldset, _fieldname, enum_name)| enum_name) + .collect(); - impl Default for ClockMux { - fn default() -> Self { - Self { - #( #field_names: None, )* + g.extend(quote! { + pub mod mux { + #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* + + #[derive(Clone, Copy)] + pub struct ClockMux { + #( #struct_fields, )* + } + + impl Default for ClockMux { + fn default() -> Self { + Self { + #( #field_names: None, )* + } } } - } - impl ClockMux { - pub fn init(self) { - #( #inits )* + impl ClockMux { + pub fn init(self) { + #( #inits )* + } } } }); diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 86af4bd68..de209272d 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -97,10 +97,9 @@ pub struct Config { pub adc: AdcClockSource, #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] pub adc34: AdcClockSource, - #[cfg(stm32f334)] - pub hrtim: HrtimClockSource, + #[cfg(clock_mux)] - pub mux: crate::rcc::ClockMux, + pub mux: crate::rcc::mux::ClockMux, pub ls: super::LsConfig, } @@ -128,8 +127,7 @@ impl Default for Config { adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), - #[cfg(stm32f334)] - hrtim: HrtimClockSource::BusClk, + #[cfg(clock_mux)] mux: Default::default(), } @@ -350,7 +348,8 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(stm32f334)] + /* + TODO: Maybe add something like this to clock_mux? How can we autogenerate the data for this? let hrtim = match config.hrtim { // Must be configured after the bus is ready, otherwise it won't work HrtimClockSource::BusClk => None, @@ -366,6 +365,7 @@ pub(crate) unsafe fn init(config: Config) { Some(pll * 2u32) } }; + */ #[cfg(clock_mux)] config.mux.init(); @@ -384,8 +384,6 @@ pub(crate) unsafe fn init(config: Config) { adc: Some(adc), #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] adc34: Some(adc34), - #[cfg(stm32f334)] - hrtim: hrtim, rtc: rtc, hsi48: hsi48, #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 24516d426..b5a8bc2a4 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -32,7 +32,7 @@ mod _version; pub use _version::*; #[cfg(clock_mux)] -pub use crate::_generated::ClockMux; +pub use crate::_generated::mux as mux; pub use crate::_generated::Clocks; #[cfg(feature = "low-power")] diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index cf5eb7b26..7c6d6cd71 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -28,9 +28,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; - // TODO: The two lines here do the same thing - config.rcc.hrtim = HrtimClockSource::PllClk; - config.rcc.mux.hrtim1sw = Some(embassy_stm32::pac::rcc::vals::Timsw::PLL1_P); + config.rcc.mux.hrtim1sw = Some(embassy_stm32::rcc::mux::Timsw::PLL1_P); } let p = embassy_stm32::init(config); From 394abda092cac80c875998c429f629caa289f9d1 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Sat, 24 Feb 2024 12:58:38 -0800 Subject: [PATCH 549/760] Fix report with the same name --- 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 b5a8bc2a4..c8ca713de 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -32,7 +32,7 @@ mod _version; pub use _version::*; #[cfg(clock_mux)] -pub use crate::_generated::mux as mux; +pub use crate::_generated::mux; pub use crate::_generated::Clocks; #[cfg(feature = "low-power")] From 2d634d07e08650caf2c2940343a1a63e0bc66f05 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 24 Feb 2024 18:31:05 +1000 Subject: [PATCH 550/760] FDCAN: Remove extra traits from. Comments Fix. --- embassy-stm32/src/can/fdcan.rs | 47 ++++++++++++++-------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index f1f6f935e..fc5d47ab7 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -861,22 +861,13 @@ pub(crate) mod sealed { } } -/// Trait for FDCAN interrupt channel 0 -pub trait IT0Instance { - /// Type for FDCAN interrupt channel 0 +/// Instance trait +pub trait Instance: sealed::Instance + RccPeripheral + 'static { + /// Interrupt 0 type IT0Interrupt: crate::interrupt::typelevel::Interrupt; -} - -/// Trait for FDCAN interrupt channel 1 -pub trait IT1Instance { - /// Type for FDCAN interrupt channel 1 + /// Interrupt 0 type IT1Interrupt: crate::interrupt::typelevel::Interrupt; } - -/// InterruptableInstance trait -pub trait InterruptableInstance: IT0Instance + IT1Instance {} -/// Instance trait -pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {} /// Fdcan Instance struct pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); @@ -921,22 +912,22 @@ fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { } - impl Instance for peripherals::$inst {} + #[allow(non_snake_case)] + pub(crate) mod $inst { - foreach_interrupt!( - ($inst,can,FDCAN,IT0,$irq:ident) => { - impl IT0Instance for peripherals::$inst { - type IT0Interrupt = crate::interrupt::typelevel::$irq; - } - }; - ($inst,can,FDCAN,IT1,$irq:ident) => { - impl IT1Instance for peripherals::$inst { - type IT1Interrupt = crate::interrupt::typelevel::$irq; - } - }; - ); - - impl InterruptableInstance for peripherals::$inst {} + foreach_interrupt!( + ($inst,can,FDCAN,IT0,$irq:ident) => { + pub type Interrupt0 = crate::interrupt::typelevel::$irq; + }; + ($inst,can,FDCAN,IT1,$irq:ident) => { + pub type Interrupt1 = crate::interrupt::typelevel::$irq; + }; + ); + } + impl Instance for peripherals::$inst { + type IT0Interrupt = $inst::Interrupt0; + type IT1Interrupt = $inst::Interrupt1; + } }; ($inst:ident, $msg_ram_inst:ident) => { From 779898c0e74d850f324528d2b2db3c9d76ec86d1 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 24 Feb 2024 20:13:52 +1000 Subject: [PATCH 551/760] FDCAN: Expose some pub types in API --- embassy-stm32/src/can/fdcan.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index fc5d47ab7..817ee2115 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -18,16 +18,18 @@ use crate::{interrupt, peripherals, Peripheral}; pub mod enums; use enums::*; -pub mod util; +mod util; pub mod frame; use frame::*; +/// Timestamp for incoming packets. Use Embassy time when enabled. #[cfg(feature = "time")] -type Timestamp = embassy_time::Instant; +pub type Timestamp = embassy_time::Instant; +/// Timestamp for incoming packets. #[cfg(not(feature = "time"))] -type Timestamp = u16; +pub type Timestamp = u16; /// Interrupt handler channel 0. pub struct IT0InterruptHandler { @@ -139,7 +141,8 @@ pub enum FdcanOperatingMode { //TestMode, } -/// FDCAN Instance +/// FDCAN Configuration instance instance +/// Create instance of this first pub struct FdcanConfigurator<'d, T: Instance> { config: crate::can::fd::config::FdCanConfig, /// Reference to internals. @@ -868,6 +871,7 @@ pub trait Instance: sealed::Instance + RccPeripheral + 'static { /// Interrupt 0 type IT1Interrupt: crate::interrupt::typelevel::Interrupt; } + /// Fdcan Instance struct pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); From a061cf31334d7c1912528edecb4738c84d98e17a Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 24 Feb 2024 20:23:34 +1000 Subject: [PATCH 552/760] FDCAN: Allow access to buffered senders and receivers. --- embassy-stm32/src/can/fdcan.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 817ee2115..d290295f5 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -434,6 +434,12 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S rx_buf: &'static RxBuf, } +/// Sender that can be used for sending CAN frames. +pub type BufferedCanSender = embassy_sync::channel::DynamicSender<'static, ClassicFrame>; + +/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. +pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (ClassicFrame, Timestamp)>; + impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { @@ -479,6 +485,16 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { Ok(self.rx_buf.receive().await) } + + /// Returns a sender that can be used for sending CAN frames. + pub fn writer(&self) -> BufferedCanSender { + self.tx_buf.sender().into() + } + + /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. + pub fn reader(&self) -> BufferedCanReceiver { + self.rx_buf.receiver().into() + } } impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop @@ -507,6 +523,12 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF rx_buf: &'static RxFdBuf, } +/// Sender that can be used for sending CAN frames. +pub type BufferedFdCanSender = embassy_sync::channel::DynamicSender<'static, FdFrame>; + +/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. +pub type BufferedFdCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (FdFrame, Timestamp)>; + impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { @@ -552,6 +574,16 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> { Ok(self.rx_buf.receive().await) } + + /// Returns a sender that can be used for sending CAN frames. + pub fn writer(&self) -> BufferedFdCanSender { + self.tx_buf.sender().into() + } + + /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. + pub fn reader(&self) -> BufferedFdCanReceiver { + self.rx_buf.receiver().into() + } } impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop From 0565098b06f73b542369c4d4f97f34c78e9bd058 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 25 Feb 2024 08:57:18 +1000 Subject: [PATCH 553/760] FDCAN: Fix some indenting in macros --- embassy-stm32/src/can/fdcan.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index d290295f5..4b76cc34d 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -929,22 +929,22 @@ macro_rules! impl_fdcan { unsafe { peripherals::$inst::mut_state() } } -#[cfg(feature = "time")] -fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { - let now_embassy = embassy_time::Instant::now(); - if ns_per_timer_tick == 0 { - return now_embassy; - } - let cantime = { Self::regs().tscv().read().tsc() }; - let delta = cantime.overflowing_sub(ts_val).0 as u64; - let ns = ns_per_timer_tick * delta as u64; - now_embassy - embassy_time::Duration::from_nanos(ns) -} + #[cfg(feature = "time")] + fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + let now_embassy = embassy_time::Instant::now(); + if ns_per_timer_tick == 0 { + return now_embassy; + } + let cantime = { Self::regs().tscv().read().tsc() }; + let delta = cantime.overflowing_sub(ts_val).0 as u64; + let ns = ns_per_timer_tick * delta as u64; + now_embassy - embassy_time::Duration::from_nanos(ns) + } -#[cfg(not(feature = "time"))] -fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { - ts_val -} + #[cfg(not(feature = "time"))] + fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + ts_val + } } From 1327a644b6194093e732372d2aab571214ef5717 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 25 Feb 2024 09:57:30 +1000 Subject: [PATCH 554/760] FDCAN: Don't require internal module for public API. --- embassy-stm32/src/can/fdcan.rs | 11 ++++++----- examples/stm32g4/src/bin/can.rs | 4 ++-- tests/stm32/src/bin/fdcan.rs | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 4b76cc34d..744d756f5 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -3,12 +3,9 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -pub mod fd; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; -use fd::config::*; -use fd::filter::*; use crate::can::fd::peripheral::Registers; use crate::gpio::sealed::AFType; @@ -17,10 +14,14 @@ use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals, Peripheral}; pub mod enums; -use enums::*; +pub(crate) mod fd; +pub mod frame; mod util; -pub mod frame; +use enums::*; +use fd::config::*; +use fd::filter::*; +pub use fd::{config, filter}; use frame::*; /// Timestamp for incoming packets. Use Embassy time when enabled. diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index affa97039..a41f765c1 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -22,8 +22,8 @@ async fn main(_spawner: Spawner) { let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); can.set_extended_filter( - can::fd::filter::ExtendedFilterSlot::_0, - can::fd::filter::ExtendedFilter::accept_all_into_fifo1(), + can::filter::ExtendedFilterSlot::_0, + can::filter::ExtendedFilter::accept_all_into_fifo1(), ); // 250k bps diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index 398e31ffc..f21aa797c 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -81,8 +81,8 @@ async fn main(_spawner: Spawner) { can.set_bitrate(250_000); can.set_extended_filter( - can::fd::filter::ExtendedFilterSlot::_0, - can::fd::filter::ExtendedFilter::accept_all_into_fifo1(), + can::filter::ExtendedFilterSlot::_0, + can::filter::ExtendedFilter::accept_all_into_fifo1(), ); let mut can = can.into_internal_loopback_mode(); From a737a7350e6aa42b867679dbb21c2d6fb8b22b91 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 25 Feb 2024 10:00:17 +1000 Subject: [PATCH 555/760] FDCAN: Remove history from comments. --- embassy-stm32/src/can/fd/config.rs | 2 +- embassy-stm32/src/can/fd/filter.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index 38b409121..f2401d92f 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -1,5 +1,5 @@ //! Configuration for FDCAN Module -//! Note: This file is copied and modified from fdcan crate by Richard Meadows +// Note: This file is copied and modified from fdcan crate by Richard Meadows use core::num::{NonZeroU16, NonZeroU8}; diff --git a/embassy-stm32/src/can/fd/filter.rs b/embassy-stm32/src/can/fd/filter.rs index 3e2129e6e..2023a2ef0 100644 --- a/embassy-stm32/src/can/fd/filter.rs +++ b/embassy-stm32/src/can/fd/filter.rs @@ -1,5 +1,5 @@ //! Definition of Filter structs for FDCAN Module -//! Note: This file is copied and modified from fdcan crate by Richard Meadows +// Note: This file is copied and modified from fdcan crate by Richard Meadows use embedded_can::{ExtendedId, StandardId}; From 489d0be2a2971cfae7d6413b601bbd044d42e351 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 26 Feb 2024 00:00:17 +0100 Subject: [PATCH 556/760] stm32/rcc: unify naming sysclk field to `sys`, enum to `Sysclk`. --- embassy-stm32/src/rcc/c0.rs | 14 +++++----- embassy-stm32/src/rcc/g0.rs | 16 ++++++------ embassy-stm32/src/rcc/l.rs | 26 +++++++++---------- embassy-stm32/src/rcc/u5.rs | 20 +++++++------- embassy-stm32/src/rcc/wba.rs | 24 ++++++++--------- examples/stm32g0/src/bin/hf_timer.rs | 4 +-- examples/stm32l1/src/bin/usb_serial.rs | 2 +- examples/stm32l4/src/bin/rng.rs | 4 +-- examples/stm32l4/src/bin/rtc.rs | 2 +- .../src/bin/spe_adin1110_http_server.rs | 2 +- examples/stm32l4/src/bin/usb_serial.rs | 2 +- examples/stm32l5/src/bin/rng.rs | 4 +-- examples/stm32l5/src/bin/usb_ethernet.rs | 2 +- examples/stm32l5/src/bin/usb_hid_mouse.rs | 2 +- examples/stm32l5/src/bin/usb_serial.rs | 2 +- examples/stm32u5/src/bin/usb_serial.rs | 2 +- examples/stm32wl/src/bin/random.rs | 2 +- examples/stm32wl/src/bin/rtc.rs | 2 +- examples/stm32wl/src/bin/uart_async.rs | 2 +- tests/stm32/src/common.rs | 14 +++++----- 20 files changed, 74 insertions(+), 74 deletions(-) diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index ca1222185..ec6ec34e8 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -9,7 +9,7 @@ pub const HSI_FREQ: Hertz = Hertz(48_000_000); /// System clock mux source #[derive(Clone, Copy)] -pub enum ClockSrc { +pub enum Sysclk { HSE(Hertz), HSI(HSIPrescaler), LSI, @@ -17,7 +17,7 @@ pub enum ClockSrc { /// Clocks configutation pub struct Config { - pub mux: ClockSrc, + pub sys: Sysclk, pub ahb_pre: AHBPrescaler, pub apb_pre: APBPrescaler, pub ls: super::LsConfig, @@ -27,7 +27,7 @@ impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::HSI(HSIPrescaler::DIV1), + sys: Sysclk::HSI(HSIPrescaler::DIV1), ahb_pre: AHBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1, ls: Default::default(), @@ -36,8 +36,8 @@ impl Default for Config { } pub(crate) unsafe fn init(config: Config) { - let (sys_clk, sw) = match config.mux { - ClockSrc::HSI(div) => { + let (sys_clk, sw) = match config.sys { + Sysclk::HSI(div) => { // Enable HSI RCC.cr().write(|w| { w.set_hsidiv(div); @@ -47,14 +47,14 @@ pub(crate) unsafe fn init(config: Config) { (HSI_FREQ / div, Sw::HSI) } - ClockSrc::HSE(freq) => { + Sysclk::HSE(freq) => { // Enable HSE RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} (freq, Sw::HSE) } - ClockSrc::LSI => { + Sysclk::LSI => { // Enable LSI RCC.csr2().write(|w| w.set_lsion(true)); while !RCC.csr2().read().lsirdy() {} diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index e3cd46fb9..0b1f34a20 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -19,7 +19,7 @@ pub enum HseMode { /// System clock mux source #[derive(Clone, Copy)] -pub enum ClockSrc { +pub enum Sysclk { HSE(Hertz, HseMode), HSI(HSIPrescaler), PLL(PllConfig), @@ -89,7 +89,7 @@ pub enum UsbSrc { /// Clocks configutation pub struct Config { - pub mux: ClockSrc, + pub sys: Sysclk, pub ahb_pre: AHBPrescaler, pub apb_pre: APBPrescaler, pub low_power_run: bool, @@ -102,7 +102,7 @@ impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::HSI(HSIPrescaler::DIV1), + sys: Sysclk::HSI(HSIPrescaler::DIV1), ahb_pre: AHBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1, low_power_run: false, @@ -202,8 +202,8 @@ pub(crate) unsafe fn init(config: Config) { let mut pll1_q_freq = None; let mut pll1_p_freq = None; - let (sys_clk, sw) = match config.mux { - ClockSrc::HSI(div) => { + let (sys_clk, sw) = match config.sys { + Sysclk::HSI(div) => { // Enable HSI RCC.cr().write(|w| { w.set_hsidiv(div); @@ -213,7 +213,7 @@ pub(crate) unsafe fn init(config: Config) { (HSI_FREQ / div, Sw::HSI) } - ClockSrc::HSE(freq, mode) => { + Sysclk::HSE(freq, mode) => { // Enable HSE RCC.cr().write(|w| { w.set_hseon(true); @@ -223,7 +223,7 @@ pub(crate) unsafe fn init(config: Config) { (freq, Sw::HSE) } - ClockSrc::PLL(pll) => { + Sysclk::PLL(pll) => { let (r_freq, q_freq, p_freq) = pll.init(); pll1_q_freq = q_freq; @@ -231,7 +231,7 @@ pub(crate) unsafe fn init(config: Config) { (r_freq, Sw::PLL1_R) } - ClockSrc::LSI => { + Sysclk::LSI => { // Enable LSI RCC.csr().write(|w| w.set_lsion(true)); while !RCC.csr().read().lsirdy() {} diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 04ea81ec4..aa4245d4e 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -7,7 +7,7 @@ pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; pub use crate::pac::rcc::vals::Clk48sel as Clk48Src; #[cfg(any(stm32wb, stm32wl))] pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; -pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as ClockSrc}; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -50,7 +50,7 @@ pub struct Config { pub pllsai2: Option, // sysclk, buses. - pub mux: ClockSrc, + pub sys: Sysclk, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, @@ -80,7 +80,7 @@ impl Default for Config { hse: None, hsi: false, msi: Some(MSIRange::RANGE4M), - mux: ClockSrc::MSI, + sys: Sysclk::MSI, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, @@ -113,7 +113,7 @@ pub const WPAN_DEFAULT: Config = Config { mode: HseMode::Oscillator, prescaler: HsePrescaler::DIV1, }), - mux: ClockSrc::PLL1_R, + sys: Sysclk::PLL1_R, #[cfg(crs)] hsi48: Some(super::Hsi48Config { sync_from_usb: false }), msi: None, @@ -161,11 +161,11 @@ pub(crate) unsafe fn init(config: Config) { // Turn on MSI and configure it to 4MHz. msi_enable(MSIRange::RANGE4M) } - if RCC.cfgr().read().sws() != ClockSrc::MSI { + if RCC.cfgr().read().sws() != Sysclk::MSI { // Set MSI as a clock source, reset prescalers. RCC.cfgr().write_value(Cfgr::default()); // Wait for clock switch status bits to change. - while RCC.cfgr().read().sws() != ClockSrc::MSI {} + while RCC.cfgr().read().sws() != Sysclk::MSI {} } // Set voltage scale @@ -260,11 +260,11 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] let pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input); - let sys_clk = match config.mux { - ClockSrc::HSE => hse.unwrap(), - ClockSrc::HSI => hsi.unwrap(), - ClockSrc::MSI => msi.unwrap(), - ClockSrc::PLL1_R => pll.r.unwrap(), + let sys_clk = match config.sys { + Sysclk::HSE => hse.unwrap(), + Sysclk::HSI => hsi.unwrap(), + Sysclk::MSI => msi.unwrap(), + Sysclk::PLL1_R => pll.r.unwrap(), }; #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] @@ -350,12 +350,12 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != latency {} RCC.cfgr().modify(|w| { - w.set_sw(config.mux); + w.set_sw(config.sys); w.set_hpre(config.ahb_pre); w.set_ppre1(config.apb1_pre); w.set_ppre2(config.apb2_pre); }); - while RCC.cfgr().read().sws() != config.mux {} + while RCC.cfgr().read().sws() != config.sys {} #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source)); diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 72613f0f3..43138f05c 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -1,7 +1,7 @@ pub use crate::pac::pwr::vals::Vos as VoltageScale; pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, - Pllsrc as PllSource, Ppre as APBPrescaler, Sw as ClockSrc, + Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; use crate::pac::{FLASH, PWR, RCC}; @@ -72,7 +72,7 @@ pub struct Config { pub pll3: Option, // sysclk, buses. - pub mux: ClockSrc, + pub sys: Sysclk, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, @@ -97,7 +97,7 @@ impl Default for Config { pll1: None, pll2: None, pll3: None, - mux: ClockSrc::MSIS, + sys: Sysclk::MSIS, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, @@ -181,11 +181,11 @@ pub(crate) unsafe fn init(config: Config) { let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range); - let sys_clk = match config.mux { - ClockSrc::HSE => hse.unwrap(), - ClockSrc::HSI => hsi.unwrap(), - ClockSrc::MSIS => msi.unwrap(), - ClockSrc::PLL1_R => pll1.r.unwrap(), + let sys_clk = match config.sys { + Sysclk::HSE => hse.unwrap(), + Sysclk::HSI => hsi.unwrap(), + Sysclk::MSIS => msi.unwrap(), + Sysclk::PLL1_R => pll1.r.unwrap(), }; // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? @@ -230,8 +230,8 @@ pub(crate) unsafe fn init(config: Config) { }); // Switch the system clock source - RCC.cfgr1().modify(|w| w.set_sw(config.mux)); - while RCC.cfgr1().read().sws() != config.mux {} + RCC.cfgr1().modify(|w| w.set_sw(config.sys)); + while RCC.cfgr1().read().sws() != config.sys {} // Configure the bus prescalers RCC.cfgr2().modify(|w| { diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index fbf2d1cf9..9d5dcfc4b 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -1,7 +1,7 @@ pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::regs::Cfgr1; pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as ClockSrc, + Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -23,7 +23,7 @@ pub struct Config { pub hse: Option, // sysclk, buses. - pub mux: ClockSrc, + pub sys: Sysclk, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, @@ -43,7 +43,7 @@ impl Default for Config { Config { hse: None, hsi: true, - mux: ClockSrc::HSI, + sys: Sysclk::HSI, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, @@ -65,11 +65,11 @@ pub(crate) unsafe fn init(config: Config) { if !RCC.cr().read().hsion() { hsi_enable() } - if RCC.cfgr1().read().sws() != ClockSrc::HSI { + if RCC.cfgr1().read().sws() != Sysclk::HSI { // Set HSI as a clock source, reset prescalers. RCC.cfgr1().write_value(Cfgr1::default()); // Wait for clock switch status bits to change. - while RCC.cfgr1().read().sws() != ClockSrc::HSI {} + while RCC.cfgr1().read().sws() != Sysclk::HSI {} } // Set voltage scale @@ -94,11 +94,11 @@ pub(crate) unsafe fn init(config: Config) { HSE_FREQ }); - let sys_clk = match config.mux { - ClockSrc::HSE => hse.unwrap(), - ClockSrc::HSI => hsi.unwrap(), - ClockSrc::_RESERVED_1 => unreachable!(), - ClockSrc::PLL1_R => todo!(), + let sys_clk = match config.sys { + Sysclk::HSE => hse.unwrap(), + Sysclk::HSI => hsi.unwrap(), + Sysclk::_RESERVED_1 => unreachable!(), + Sysclk::PLL1_R => todo!(), }; assert!(sys_clk.0 <= 100_000_000); @@ -142,9 +142,9 @@ pub(crate) unsafe fn init(config: Config) { // TODO: Set the SRAM wait states RCC.cfgr1().modify(|w| { - w.set_sw(config.mux); + w.set_sw(config.sys); }); - while RCC.cfgr1().read().sws() != config.mux {} + while RCC.cfgr1().read().sws() != config.sys {} RCC.cfgr2().modify(|w| { w.set_hpre(config.ahb_pre); diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 78a779e29..3f63d0dfd 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -5,7 +5,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::pac::rcc::vals::Tim1sel; -use embassy_stm32::rcc::{ClockSrc, Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr}; +use embassy_stm32::rcc::{Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr, Sysclk}; use embassy_stm32::time::khz; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; @@ -16,7 +16,7 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut rcc_config = RccConfig::default(); - rcc_config.mux = ClockSrc::PLL(PllConfig { + rcc_config.sys = Sysclk::PLL(PllConfig { source: PllSource::HSI, m: Pllm::DIV1, n: Plln::MUL16, diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs index 7b1e84cbc..f738ea358 100644 --- a/examples/stm32l1/src/bin/usb_serial.rs +++ b/examples/stm32l1/src/bin/usb_serial.rs @@ -27,7 +27,7 @@ async fn main(_spawner: Spawner) { mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3) }); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; } let p = embassy_stm32::init(config); diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs index 638b3e9e4..14d0e3c1e 100644 --- a/examples/stm32l4/src/bin/rng.rs +++ b/examples/stm32l4/src/bin/rng.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ClockSrc, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource}; +use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk}; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; use {defmt_rtt as _, panic_probe as _}; @@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI, diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index 526620bfb..a8a375ab4 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); { use embassy_stm32::rcc::*; - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.hse = Some(Hse { freq: Hertz::mhz(8), mode: HseMode::Oscillator, diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 026a3a477..32bfab6eb 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -75,7 +75,7 @@ async fn main(spawner: Spawner) { use embassy_stm32::rcc::*; // 80Mhz clock (Source: 8 / SrcDiv: 1 * PllMul 20 / ClkDiv 2) // 80MHz highest frequency for flash 0 wait. - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.hse = Some(Hse { freq: Hertz::mhz(8), mode: HseMode::Oscillator, diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 8cc9a7aed..9247e56a1 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI, diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs index 50da6c946..0a644e73d 100644 --- a/examples/stm32l5/src/bin/rng.rs +++ b/examples/stm32l5/src/bin/rng.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ClockSrc, Pll, PllMul, PllPreDiv, PllRDiv, PllSource}; +use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, PllSource, Sysclk}; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; use {defmt_rtt as _, panic_probe as _}; @@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.hsi = true; - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { // 64Mhz clock (16 / 1 * 8 / 2) source: PllSource::HSI, diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 88060b6b0..f6d8b16d0 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -45,7 +45,7 @@ async fn net_task(stack: &'static Stack>) -> ! { async fn main(spawner: Spawner) { let mut config = Config::default(); config.rcc.hsi = true; - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { // 80Mhz clock (16 / 1 * 10 / 2) source: PllSource::HSI, diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 7c8a8ebfb..c51ed96e0 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -22,7 +22,7 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.hsi = true; - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { // 80Mhz clock (16 / 1 * 10 / 2) source: PllSource::HSI, diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 75053ce4b..87987f2ce 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.hsi = true; - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { // 80Mhz clock (16 / 1 * 10 / 2) source: PllSource::HSI, diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 99cdeacc9..61851e5a2 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) { divq: None, divr: Some(PllDiv::DIV1), // 160 MHz }); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.voltage_range = VoltageScale::RANGE1; config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB } diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 3610392be..8e9fe02b2 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { mode: HseMode::Bypass, prescaler: HsePrescaler::DIV1, }); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { source: PllSource::HSE, prediv: PllPreDiv::DIV2, diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index 4738d5770..0c26426ef 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -21,7 +21,7 @@ async fn main(_spawner: Spawner) { mode: HseMode::Bypass, prescaler: HsePrescaler::DIV1, }); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { source: PllSource::HSE, prediv: PllPreDiv::DIV2, diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index 8e545834c..3637243a0 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -20,7 +20,7 @@ but can be surely changed for your needs. #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); - config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; + config.rcc.sys = embassy_stm32::rcc::Sysclk::HSE; let p = embassy_stm32::init(config); defmt::info!("Starting system"); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 1e6b1cce9..7b9585afd 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -527,7 +527,7 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] { use embassy_stm32::rcc::*; - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI, @@ -547,7 +547,7 @@ pub fn config() -> Config { mode: HseMode::Bypass, prescaler: HsePrescaler::DIV1, }); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { source: PllSource::HSE, prediv: PllPreDiv::DIV2, @@ -562,7 +562,7 @@ pub fn config() -> Config { { use embassy_stm32::rcc::*; config.rcc.hsi = true; - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { // 110Mhz clock (16 / 4 * 55 / 2) source: PllSource::HSI, @@ -586,7 +586,7 @@ pub fn config() -> Config { divq: None, divr: Some(PllDiv::DIV1), // 160 MHz }); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; config.rcc.voltage_range = VoltageScale::RANGE1; config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB } @@ -594,7 +594,7 @@ pub fn config() -> Config { #[cfg(feature = "stm32wba52cg")] { use embassy_stm32::rcc::*; - config.rcc.mux = ClockSrc::HSI; + config.rcc.sys = Sysclk::HSI; embassy_stm32::pac::RCC.ccipr2().write(|w| { w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI); @@ -610,7 +610,7 @@ pub fn config() -> Config { mul: PllMul::MUL4, div: PllDiv::DIV2, // 32Mhz clock (16 * 4 / 2) }); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; } #[cfg(any(feature = "stm32l152re"))] @@ -622,7 +622,7 @@ pub fn config() -> Config { mul: PllMul::MUL4, div: PllDiv::DIV2, // 32Mhz clock (16 * 4 / 2) }); - config.rcc.mux = ClockSrc::PLL1_R; + config.rcc.sys = Sysclk::PLL1_R; } config From c23b59bdc82a766549f8ba83b7d3b678b5080a3f Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Sun, 25 Feb 2024 16:12:32 -0800 Subject: [PATCH 557/760] Add `pll1_p_mul_2` clock. --- embassy-stm32/src/rcc/f013.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index de209272d..bbc76d086 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -209,6 +209,9 @@ pub(crate) unsafe fn init(config: Config) { out_freq }); + #[cfg(stm32f3)] + let pll_mul_2 = pll.map(|pll| { pll * 2u32 }); + #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] let usb = match pll { Some(Hertz(72_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1_5), @@ -374,6 +377,8 @@ pub(crate) unsafe fn init(config: Config) { hsi: hsi, hse: hse, pll1_p: pll, + #[cfg(stm32f3)] + pll1_p_mul_2: pll_mul_2, sys: Some(sys), pclk1: Some(pclk1), pclk2: Some(pclk2), From 7dbae799dc708734af53494f54b0e6f46468daf3 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Sun, 25 Feb 2024 16:24:52 -0800 Subject: [PATCH 558/760] Rust FMT --- embassy-stm32/src/rcc/f013.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index bbc76d086..2e9540c6a 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -210,7 +210,7 @@ pub(crate) unsafe fn init(config: Config) { }); #[cfg(stm32f3)] - let pll_mul_2 = pll.map(|pll| { pll * 2u32 }); + let pll_mul_2 = pll.map(|pll| pll * 2u32 ); #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] let usb = match pll { From 2dfd66b7c4098dbde3c5beafae9de527cb6644e6 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Sun, 25 Feb 2024 16:25:42 -0800 Subject: [PATCH 559/760] :facepalm: --- embassy-stm32/src/rcc/f013.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 2e9540c6a..56bb2a0d9 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -210,7 +210,7 @@ pub(crate) unsafe fn init(config: Config) { }); #[cfg(stm32f3)] - let pll_mul_2 = pll.map(|pll| pll * 2u32 ); + let pll_mul_2 = pll.map(|pll| pll * 2u32); #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] let usb = match pll { From abde7891e3f763b356f86d6f0619c971bf0ef055 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Sun, 25 Feb 2024 16:44:46 -0800 Subject: [PATCH 560/760] Update metapac version --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d585d2cd6..e0bee6a92 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-6097928f720646c73d6483a3245f922bd5faee2f" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-88f71cbcd2f048c40bad162c7e7864cc3897eba4" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-6097928f720646c73d6483a3245f922bd5faee2f", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-88f71cbcd2f048c40bad162c7e7864cc3897eba4", default-features = false, features = ["metadata"]} [features] From 79e5e8b052b56f8c6fc07d8407fcfc3aaf39bab3 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:11:54 -0500 Subject: [PATCH 561/760] Add cryp configuration. --- embassy-stm32/src/cryp/mod.rs | 227 ++++++++++++++++++++++++++++++++++ embassy-stm32/src/lib.rs | 2 + 2 files changed, 229 insertions(+) create mode 100644 embassy-stm32/src/cryp/mod.rs diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs new file mode 100644 index 000000000..dedc6ddc5 --- /dev/null +++ b/embassy-stm32/src/cryp/mod.rs @@ -0,0 +1,227 @@ +use embassy_hal_internal::{into_ref, PeripheralRef}; +use pac::cryp::Init; + +use crate::pac; +use crate::peripherals::CRYP; +use crate::rcc::sealed::RccPeripheral; +use crate::{interrupt, peripherals, Peripheral}; + +pub struct Context<'c> { + key: &'c [u8], +} + +#[derive(PartialEq)] +pub enum Algorithm { + AES, + DES, + TDES, +} + +#[derive(PartialEq)] +pub enum Mode { + ECB, + CBC, + CTR, + GCM, + GMAC, + CCM, +} + +#[derive(PartialEq)] +pub enum Direction { + Encrypt, + Decrypt, +} + +/// Crypto Accelerator Driver +pub struct Cryp<'d, T: Instance, In, Out> { + _peripheral: PeripheralRef<'d, T>, + indma: PeripheralRef<'d, In>, + outdma: PeripheralRef<'d, Out>, +} + +type InitVector<'v> = Option<&'v [u8]>; + +impl<'d, T: Instance, In, Out> Cryp<'d, T, In, Out> { + /// Create a new CRYP driver. + pub fn new( + peri: impl Peripheral

+ 'd, + indma: impl Peripheral

+ 'd, + outdma: impl Peripheral

+ 'd, + ) -> Self { + CRYP::enable_and_reset(); + into_ref!(peri, indma, outdma); + let instance = Self { + _peripheral: peri, + indma: indma, + outdma: outdma, + }; + instance + } + + /// Start a new cipher operation. + /// Key size must be 128, 192, or 256 bits. + pub fn start(key: &[u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context { + T::regs().cr().modify(|w| w.set_crypen(false)); + + let keylen = key.len() * 8; + let ivlen; + if let Some(iv) = iv { + ivlen = iv.len() * 8; + } else { + ivlen = 0; + } + + // Checks for correctness + if algo == Algorithm::AES { + match keylen { + 128 => T::regs().cr().write(|w| w.set_keysize(0)), + 192 => T::regs().cr().write(|w| w.set_keysize(1)), + 256 => T::regs().cr().write(|w| w.set_keysize(2)), + _ => panic!("Key length must be 128, 192, or 256 bits."), + } + + if (mode == Mode::GCM) && (ivlen != 96) { + panic!("IV length must be 96 bits for GCM."); + } else if (mode == Mode::CBC) && (ivlen != 128) { + panic!("IV length must be 128 bits for CBC."); + } else if (mode == Mode::CCM) && (ivlen != 128) { + panic!("IV length must be 128 bits for CCM."); + } else if (mode == Mode::CTR) && (ivlen != 64) { + panic!("IV length must be 64 bits for CTR."); + } else if (mode == Mode::GCM) && (ivlen != 96) { + panic!("IV length must be 96 bits for GCM."); + } else if (mode == Mode::GMAC) && (ivlen != 96) { + panic!("IV length must be 96 bits for GMAC."); + } + } + + // Load the key into the registers. + let mut keyidx = 0; + let mut keyword: [u8; 4] = [0; 4]; + if keylen > 192 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword)); + } + if keylen > 128 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword)); + } + if keylen > 64 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword)); + } + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword)); + + // Set data type to 8-bit. This will match software implementations. + T::regs().cr().modify(|w| w.set_datatype(2)); + + if algo == Algorithm::AES { + if (mode == Mode::ECB) || (mode == Mode::CBC) { + T::regs().cr().modify(|w| w.set_algomode0(7)); + T::regs().cr().modify(|w| w.set_crypen(true)); + while T::regs().sr().read().busy() {} + } + + match mode { + Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(4)), + Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(5)), + Mode::CTR => T::regs().cr().modify(|w| w.set_algomode0(6)), + Mode::GCM => T::regs().cr().modify(|w| w.set_algomode0(8)), + Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode0(8)), + Mode::CCM => T::regs().cr().modify(|w| w.set_algomode0(9)), + } + } else if algo == Algorithm::DES { + match mode { + Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(2)), + Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(3)), + _ => panic!("Only ECB and CBC modes are valid for DES."), + } + } else if algo == Algorithm::TDES { + match mode { + Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(0)), + Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(1)), + _ => panic!("Only ECB and CBC modes are valid for TDES."), + } + } + + // Set encrypt/decrypt + if dir == Direction::Encrypt { + T::regs().cr().modify(|w| w.set_algodir(false)); + } else { + T::regs().cr().modify(|w| w.set_algodir(true)); + } + + // Load the IV into the registers. + if let Some(iv) = iv { + let mut iv_idx = 0; + let mut iv_word: [u8; 4] = [0; 4]; + iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + if iv.len() >= 12 { + T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + } + if iv.len() >= 16 { + T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); + } + } + + // Flush in/out FIFOs + T::regs().cr().modify(|w| w.fflush()); + + let ctx = Context { key: key }; + + ctx + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Instance { + fn regs() -> pac::cryp::Cryp; + } +} + +/// RNG instance trait. +pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { + /// Interrupt for this RNG instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +foreach_interrupt!( + ($inst:ident, rng, CRYP, GLOBAL, $irq:ident) => { + impl Instance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + + impl sealed::Instance for peripherals::$inst { + fn regs() -> crate::pac::cryp::Cryp { + crate::pac::$inst + } + } + }; +); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index cd1ede0fa..6859eef6c 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -34,6 +34,8 @@ pub mod adc; pub mod can; #[cfg(crc)] pub mod crc; +#[cfg(cryp)] +pub mod cryp; #[cfg(dac)] pub mod dac; #[cfg(dcmi)] From a0a8a4ec864763948d4a965ccf8ec11ca91cb15f Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:24:52 -0500 Subject: [PATCH 562/760] Support CBC, ECB, CTR modes. --- embassy-stm32/src/cryp/mod.rs | 350 +++++++++++++++++++++++++++------- 1 file changed, 282 insertions(+), 68 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index dedc6ddc5..f266313c1 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1,23 +1,34 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; -use pac::cryp::Init; use crate::pac; use crate::peripherals::CRYP; use crate::rcc::sealed::RccPeripheral; -use crate::{interrupt, peripherals, Peripheral}; +use crate::{interrupt, Peripheral}; + +const DES_BLOCK_SIZE: usize = 8; // 64 bits +const AES_BLOCK_SIZE: usize = 16; // 128 bits pub struct Context<'c> { + algo: Algorithm, + mode: Mode, + dir: Direction, + last_block_processed: bool, + aad_complete: bool, + cr: u32, + iv: [u32; 4], key: &'c [u8], + csgcmccm: [u32; 8], + csgcm: [u32; 8], } -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub enum Algorithm { AES, DES, TDES, } -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub enum Mode { ECB, CBC, @@ -27,53 +38,55 @@ pub enum Mode { CCM, } -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub enum Direction { Encrypt, Decrypt, } /// Crypto Accelerator Driver -pub struct Cryp<'d, T: Instance, In, Out> { +pub struct Cryp<'d, T: Instance> { _peripheral: PeripheralRef<'d, T>, - indma: PeripheralRef<'d, In>, - outdma: PeripheralRef<'d, Out>, } type InitVector<'v> = Option<&'v [u8]>; -impl<'d, T: Instance, In, Out> Cryp<'d, T, In, Out> { +impl<'d, T: Instance> Cryp<'d, T> { /// Create a new CRYP driver. - pub fn new( - peri: impl Peripheral

+ 'd, - indma: impl Peripheral

+ 'd, - outdma: impl Peripheral

+ 'd, - ) -> Self { + pub fn new(peri: impl Peripheral

+ 'd) -> Self { CRYP::enable_and_reset(); - into_ref!(peri, indma, outdma); - let instance = Self { - _peripheral: peri, - indma: indma, - outdma: outdma, - }; + into_ref!(peri); + let instance = Self { _peripheral: peri }; instance } /// Start a new cipher operation. /// Key size must be 128, 192, or 256 bits. - pub fn start(key: &[u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context { - T::regs().cr().modify(|w| w.set_crypen(false)); + pub fn start<'c>(&self, key: &'c [u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context<'c> { + let mut ctx = Context { + algo, + mode, + dir, + last_block_processed: false, + cr: 0, + iv: [0; 4], + key, + csgcmccm: [0; 8], + csgcm: [0; 8], + aad_complete: false, + }; - let keylen = key.len() * 8; - let ivlen; - if let Some(iv) = iv { - ivlen = iv.len() * 8; - } else { - ivlen = 0; - } + T::regs().cr().modify(|w| w.set_crypen(false)); // Checks for correctness if algo == Algorithm::AES { + let keylen = key.len() * 8; + let ivlen; + if let Some(iv) = iv { + ivlen = iv.len() * 8; + } else { + ivlen = 0; + } match keylen { 128 => T::regs().cr().write(|w| w.set_keysize(0)), 192 => T::regs().cr().write(|w| w.set_keysize(1)), @@ -96,49 +109,14 @@ impl<'d, T: Instance, In, Out> Cryp<'d, T, In, Out> { } } - // Load the key into the registers. - let mut keyidx = 0; - let mut keyword: [u8; 4] = [0; 4]; - if keylen > 192 { - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); - keyidx += 4; - T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword)); - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); - keyidx += 4; - T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword)); - } - if keylen > 128 { - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); - keyidx += 4; - T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword)); - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); - keyidx += 4; - T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword)); - } - if keylen > 64 { - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); - keyidx += 4; - T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword)); - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); - keyidx += 4; - T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword)); - } - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); - keyidx += 4; - T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword)); - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); - T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword)); + self.load_key(key); // Set data type to 8-bit. This will match software implementations. T::regs().cr().modify(|w| w.set_datatype(2)); - if algo == Algorithm::AES { - if (mode == Mode::ECB) || (mode == Mode::CBC) { - T::regs().cr().modify(|w| w.set_algomode0(7)); - T::regs().cr().modify(|w| w.set_crypen(true)); - while T::regs().sr().read().busy() {} - } + self.prepare_key(&ctx); + if algo == Algorithm::AES { match mode { Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(4)), Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(5)), @@ -192,10 +170,246 @@ impl<'d, T: Instance, In, Out> Cryp<'d, T, In, Out> { // Flush in/out FIFOs T::regs().cr().modify(|w| w.fflush()); - let ctx = Context { key: key }; + if mode == Mode::GCM { + // GCM init phase + T::regs().cr().modify(|w| w.set_gcm_ccmph(0)); + T::regs().cr().modify(|w| w.set_crypen(true)); + while T::regs().cr().read().crypen() {} + } + + self.store_context(&mut ctx); ctx } + + // pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8]) { + // if ctx.aad_complete { + // panic!("Cannot update AAD after calling 'update'!") + // } + // if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) { + // panic!("Associated data only valid for GCM, GMAC, and CCM modes.") + // } + + // let mut header_size = 0; + // let mut header: [u8;] + + // if aad.len() < 65280 { + + // } + + // // GCM header phase + // T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); + // T::regs().cr().modify(|w| w.set_crypen(true)); + // } + + pub fn update_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) { + self.load_context(ctx); + + ctx.aad_complete = true; + if last_block { + ctx.last_block_processed = true; + } + + let block_size; + if ctx.algo == Algorithm::DES { + block_size = 8; + } else { + block_size = 16; + } + let last_block_remainder = input.len() % block_size; + + // Perform checks for correctness. + + if ctx.mode == Mode::GMAC { + panic!("GMAC works on header data only. Do not call this function for GMAC."); + } + if ctx.last_block_processed { + panic!("The last block has already been processed!"); + } + if input.len() != output.len() { + panic!("Output buffer length must match input length."); + } + if !last_block { + if last_block_remainder != 0 { + panic!("Input length must be a multiple of {block_size} bytes."); + } + } + if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) { + if last_block_remainder != 0 { + panic!("Input must be a multiple of {block_size} bytes in ECB and CBC modes. Consider padding or ciphertext stealing."); + } + } + + // Load data into core, block by block. + let num_full_blocks = input.len() / block_size; + for block in 0..num_full_blocks { + let mut index = block * block_size; + let end_index = index + block_size; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&input[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + let mut index = block * block_size; + let end_index = index + block_size; + // Block until there is output to read. + while !T::regs().sr().read().ofne() {} + // Read block out + while index < end_index { + let out_word: u32 = T::regs().dout().read(); + output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); + index += 4; + } + } + + // Handle the final block, which is incomplete. + if last_block_remainder > 0 { + if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt { + //Handle special GCM partial block process. + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().write(|w| w.set_algomode0(6)); + let iv1r = T::regs().csgcmccmr(7).read() - 1; + T::regs().init(1).ivrr().write_value(iv1r); + T::regs().cr().modify(|w| w.set_crypen(true)); + } + + let mut intermediate_data: [u8; 16] = [0; 16]; + let mut last_block: [u8; 16] = [0; 16]; + last_block.copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); + let mut index = 0; + let end_index = block_size; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&last_block[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + let mut index = 0; + let end_index = block_size; + // Block until there is output to read. + while !T::regs().sr().read().ofne() {} + // Read block out + while index < end_index { + let out_word: u32 = T::regs().dout().read(); + intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); + index += 4; + } + + // Handle the last block depending on mode. + output[output.len() - last_block_remainder..output.len()] + .copy_from_slice(&intermediate_data[0..last_block_remainder]); + + if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt { + //Handle special GCM partial block process. + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().write(|w| w.set_algomode0(8)); + T::regs().init(1).ivrr().write_value(2); + T::regs().cr().modify(|w| w.set_crypen(true)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); + let mut index = 0; + let end_index = block_size; + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&intermediate_data[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + for _ in 0..4 { + T::regs().dout().read(); + } + } + } + } + + fn prepare_key(&self, ctx: &Context) { + if ctx.algo == Algorithm::AES { + if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) { + T::regs().cr().modify(|w| w.set_algomode0(7)); + T::regs().cr().modify(|w| w.set_crypen(true)); + while T::regs().sr().read().busy() {} + } + } + } + + fn load_key(&self, key: &[u8]) { + // Load the key into the registers. + let mut keyidx = 0; + let mut keyword: [u8; 4] = [0; 4]; + let keylen = key.len() * 8; + if keylen > 192 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword)); + } + if keylen > 128 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword)); + } + if keylen > 64 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword)); + } + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword)); + } + + fn store_context(&self, ctx: &mut Context) { + // Wait for data block processing to finish. + while !T::regs().sr().read().ifem() {} + while T::regs().sr().read().ofne() {} + while T::regs().sr().read().busy() {} + + // Disable crypto processor. + T::regs().cr().modify(|w| w.set_crypen(false)); + + // Save the peripheral state. + ctx.cr = T::regs().cr().read().0; + ctx.iv[0] = T::regs().init(0).ivlr().read(); + ctx.iv[1] = T::regs().init(0).ivrr().read(); + ctx.iv[2] = T::regs().init(1).ivlr().read(); + ctx.iv[3] = T::regs().init(1).ivrr().read(); + for i in 0..8 { + ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read(); + ctx.csgcm[i] = T::regs().csgcmr(i).read(); + } + } + + fn load_context(&self, ctx: &Context) { + // Reload state registers. + T::regs().cr().write(|w| w.0 = ctx.cr); + T::regs().init(0).ivlr().write_value(ctx.iv[0]); + T::regs().init(0).ivrr().write_value(ctx.iv[1]); + T::regs().init(1).ivlr().write_value(ctx.iv[2]); + T::regs().init(1).ivrr().write_value(ctx.iv[3]); + for i in 0..8 { + T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]); + T::regs().csgcmr(i).write_value(ctx.csgcm[i]); + } + self.load_key(ctx.key); + + // Prepare key if applicable. + self.prepare_key(ctx); + + // Enable crypto processor. + T::regs().cr().modify(|w| w.set_crypen(true)); + } } pub(crate) mod sealed { From 72e4cacd914195352c9760856e8b8e40a7851752 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Wed, 14 Feb 2024 22:11:38 -0500 Subject: [PATCH 563/760] CBC and ECB AES modes functional. --- embassy-stm32/src/cryp/mod.rs | 39 +++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index f266313c1..b368930da 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -3,7 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::pac; use crate::peripherals::CRYP; use crate::rcc::sealed::RccPeripheral; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, peripherals, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits @@ -49,7 +49,7 @@ pub struct Cryp<'d, T: Instance> { _peripheral: PeripheralRef<'d, T>, } -type InitVector<'v> = Option<&'v [u8]>; +pub type InitVector<'v> = Option<&'v [u8]>; impl<'d, T: Instance> Cryp<'d, T> { /// Create a new CRYP driver. @@ -88,9 +88,9 @@ impl<'d, T: Instance> Cryp<'d, T> { ivlen = 0; } match keylen { - 128 => T::regs().cr().write(|w| w.set_keysize(0)), - 192 => T::regs().cr().write(|w| w.set_keysize(1)), - 256 => T::regs().cr().write(|w| w.set_keysize(2)), + 128 => T::regs().cr().modify(|w| w.set_keysize(0)), + 192 => T::regs().cr().modify(|w| w.set_keysize(1)), + 256 => T::regs().cr().modify(|w| w.set_keysize(2)), _ => panic!("Key length must be 128, 192, or 256 bits."), } @@ -155,13 +155,13 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); iv_idx += 4; + T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); if iv.len() >= 12 { - T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); iv_idx += 4; + T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); } if iv.len() >= 16 { - T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); } @@ -206,9 +206,6 @@ impl<'d, T: Instance> Cryp<'d, T> { self.load_context(ctx); ctx.aad_complete = true; - if last_block { - ctx.last_block_processed = true; - } let block_size; if ctx.algo == Algorithm::DES { @@ -231,15 +228,19 @@ impl<'d, T: Instance> Cryp<'d, T> { } if !last_block { if last_block_remainder != 0 { - panic!("Input length must be a multiple of {block_size} bytes."); + panic!("Input length must be a multiple of {} bytes.", block_size); } } if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) { if last_block_remainder != 0 { - panic!("Input must be a multiple of {block_size} bytes in ECB and CBC modes. Consider padding or ciphertext stealing."); + panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", block_size); } } + if last_block { + ctx.last_block_processed = true; + } + // Load data into core, block by block. let num_full_blocks = input.len() / block_size; for block in 0..num_full_blocks { @@ -277,7 +278,7 @@ impl<'d, T: Instance> Cryp<'d, T> { let mut intermediate_data: [u8; 16] = [0; 16]; let mut last_block: [u8; 16] = [0; 16]; - last_block.copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); + last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); let mut index = 0; let end_index = block_size; // Write block in @@ -299,7 +300,8 @@ impl<'d, T: Instance> Cryp<'d, T> { } // Handle the last block depending on mode. - output[output.len() - last_block_remainder..output.len()] + let output_len = output.len(); + output[output_len - last_block_remainder..output_len] .copy_from_slice(&intermediate_data[0..last_block_remainder]); if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt { @@ -325,7 +327,7 @@ impl<'d, T: Instance> Cryp<'d, T> { } fn prepare_key(&self, ctx: &Context) { - if ctx.algo == Algorithm::AES { + if ctx.algo == Algorithm::AES && ctx.dir == Direction::Decrypt { if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) { T::regs().cr().modify(|w| w.set_algomode0(7)); T::regs().cr().modify(|w| w.set_crypen(true)); @@ -406,6 +408,7 @@ impl<'d, T: Instance> Cryp<'d, T> { // Prepare key if applicable. self.prepare_key(ctx); + T::regs().cr().write(|w| w.0 = ctx.cr); // Enable crypto processor. T::regs().cr().modify(|w| w.set_crypen(true)); @@ -420,14 +423,14 @@ pub(crate) mod sealed { } } -/// RNG instance trait. +/// CRYP instance trait. pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { - /// Interrupt for this RNG instance. + /// Interrupt for this CRYP instance. type Interrupt: interrupt::typelevel::Interrupt; } foreach_interrupt!( - ($inst:ident, rng, CRYP, GLOBAL, $irq:ident) => { + ($inst:ident, cryp, CRYP, GLOBAL, $irq:ident) => { impl Instance for peripherals::$inst { type Interrupt = crate::interrupt::typelevel::$irq; } From 565acdf24301a72fe084aa18b7c55a6110609374 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Wed, 14 Feb 2024 22:38:05 -0500 Subject: [PATCH 564/760] CTR mode functional. --- embassy-stm32/src/cryp/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index b368930da..4db95d55c 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -100,8 +100,8 @@ impl<'d, T: Instance> Cryp<'d, T> { panic!("IV length must be 128 bits for CBC."); } else if (mode == Mode::CCM) && (ivlen != 128) { panic!("IV length must be 128 bits for CCM."); - } else if (mode == Mode::CTR) && (ivlen != 64) { - panic!("IV length must be 64 bits for CTR."); + } else if (mode == Mode::CTR) && (ivlen != 128) { + panic!("IV length must be 128 bits for CTR."); } else if (mode == Mode::GCM) && (ivlen != 96) { panic!("IV length must be 96 bits for GCM."); } else if (mode == Mode::GMAC) && (ivlen != 96) { From c2b03eff62245bd325a781e1e260c150e0a5040c Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Fri, 16 Feb 2024 13:15:14 -0500 Subject: [PATCH 565/760] GCM mode functional. --- embassy-stm32/src/cryp/mod.rs | 244 +++++++++++++++++++++++++++------- 1 file changed, 198 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 4db95d55c..447bcf2f8 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1,3 +1,4 @@ +//! Crypto Accelerator (CRYP) use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::pac; @@ -8,6 +9,8 @@ use crate::{interrupt, peripherals, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits +/// Holds the state information for a cipher operation. +/// Allows suspending/resuming of cipher operations. pub struct Context<'c> { algo: Algorithm, mode: Mode, @@ -19,28 +22,44 @@ pub struct Context<'c> { key: &'c [u8], csgcmccm: [u32; 8], csgcm: [u32; 8], + header_len: u64, + payload_len: u64, } +/// Selects the encryption algorithm. #[derive(PartialEq, Clone, Copy)] pub enum Algorithm { + /// Advanced Encryption Standard AES, + /// Data Encryption Standard DES, + /// Triple-DES TDES, } +/// Selects the cipher mode. #[derive(PartialEq, Clone, Copy)] pub enum Mode { + /// Electronic Codebook ECB, + /// Cipher Block Chaining CBC, + /// Counter Mode CTR, + /// Galois Counter Mode GCM, + /// Galois Message Authentication Code GMAC, + /// Counter with CBC-MAC CCM, } +/// Selects whether the crypto processor operates in encryption or decryption mode. #[derive(PartialEq, Clone, Copy)] pub enum Direction { + /// Encryption mode Encrypt, + /// Decryption mode Decrypt, } @@ -49,6 +68,8 @@ pub struct Cryp<'d, T: Instance> { _peripheral: PeripheralRef<'d, T>, } +/// Initialization vector of arbitrary length. +/// When an initialization vector is not needed, `None` may be supplied. pub type InitVector<'v> = Option<&'v [u8]>; impl<'d, T: Instance> Cryp<'d, T> { @@ -62,6 +83,8 @@ impl<'d, T: Instance> Cryp<'d, T> { /// Start a new cipher operation. /// Key size must be 128, 192, or 256 bits. + /// Initialization vector must only be supplied if necessary. + /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. pub fn start<'c>(&self, key: &'c [u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context<'c> { let mut ctx = Context { algo, @@ -74,6 +97,8 @@ impl<'d, T: Instance> Cryp<'d, T> { csgcmccm: [0; 8], csgcm: [0; 8], aad_complete: false, + header_len: 0, + payload_len: 0, }; T::regs().cr().modify(|w| w.set_crypen(false)); @@ -102,8 +127,6 @@ impl<'d, T: Instance> Cryp<'d, T> { panic!("IV length must be 128 bits for CCM."); } else if (mode == Mode::CTR) && (ivlen != 128) { panic!("IV length must be 128 bits for CTR."); - } else if (mode == Mode::GCM) && (ivlen != 96) { - panic!("IV length must be 96 bits for GCM."); } else if (mode == Mode::GMAC) && (ivlen != 96) { panic!("IV length must be 96 bits for GMAC."); } @@ -121,17 +144,27 @@ impl<'d, T: Instance> Cryp<'d, T> { Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(4)), Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(5)), Mode::CTR => T::regs().cr().modify(|w| w.set_algomode0(6)), - Mode::GCM => T::regs().cr().modify(|w| w.set_algomode0(8)), - Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode0(8)), - Mode::CCM => T::regs().cr().modify(|w| w.set_algomode0(9)), + Mode::GCM => T::regs().cr().modify(|w| w.set_algomode0(0)), + Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode0(0)), + Mode::CCM => T::regs().cr().modify(|w| w.set_algomode0(1)), + } + match mode { + Mode::ECB => T::regs().cr().modify(|w| w.set_algomode3(false)), + Mode::CBC => T::regs().cr().modify(|w| w.set_algomode3(false)), + Mode::CTR => T::regs().cr().modify(|w| w.set_algomode3(false)), + Mode::GCM => T::regs().cr().modify(|w| w.set_algomode3(true)), + Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode3(true)), + Mode::CCM => T::regs().cr().modify(|w| w.set_algomode3(true)), } } else if algo == Algorithm::DES { + T::regs().cr().modify(|w| w.set_algomode3(false)); match mode { Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(2)), Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(3)), _ => panic!("Only ECB and CBC modes are valid for DES."), } } else if algo == Algorithm::TDES { + T::regs().cr().modify(|w| w.set_algomode3(false)); match mode { Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(0)), Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(1)), @@ -148,23 +181,26 @@ impl<'d, T: Instance> Cryp<'d, T> { // Load the IV into the registers. if let Some(iv) = iv { + let mut full_iv: [u8; 16] = [0; 16]; + full_iv[0..iv.len()].copy_from_slice(iv); + + if (mode == Mode::GCM) || (mode == Mode::GMAC) { + full_iv[15] = 2; + } + let mut iv_idx = 0; let mut iv_word: [u8; 4] = [0; 4]; - iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); iv_idx += 4; T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); - iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); iv_idx += 4; T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); - if iv.len() >= 12 { - iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); - iv_idx += 4; - T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); - } - if iv.len() >= 16 { - iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); - T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); - } + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); } // Flush in/out FIFOs @@ -182,41 +218,116 @@ impl<'d, T: Instance> Cryp<'d, T> { ctx } - // pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8]) { - // if ctx.aad_complete { - // panic!("Cannot update AAD after calling 'update'!") - // } - // if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) { - // panic!("Associated data only valid for GCM, GMAC, and CCM modes.") - // } - - // let mut header_size = 0; - // let mut header: [u8;] - - // if aad.len() < 65280 { - - // } - - // // GCM header phase - // T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); - // T::regs().cr().modify(|w| w.set_crypen(true)); - // } - - pub fn update_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) { + /// Controls the header phase of cipher processing. + /// This function is only valid for GCM, CCM, and GMAC modes. + /// It only needs to be called if using one of these modes and there is associated data. + /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. + /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block. + /// When supplying the last block of AAD, `last_aad_block` must be `true`. + pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8], last_aad_block: bool) { self.load_context(ctx); - ctx.aad_complete = true; - let block_size; if ctx.algo == Algorithm::DES { - block_size = 8; + block_size = DES_BLOCK_SIZE; } else { - block_size = 16; + block_size = AES_BLOCK_SIZE; + } + let last_block_remainder = aad.len() % block_size; + + // Perform checks for correctness. + if ctx.aad_complete { + panic!("Cannot update AAD after calling 'update'!") + } + if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) { + panic!("Associated data only valid for GCM, GMAC, and CCM modes.") + } + if !last_aad_block { + if last_block_remainder != 0 { + panic!("Input length must be a multiple of {} bytes.", block_size); + } + } + + ctx.header_len += aad.len() as u64; + + // GCM header phase + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); + T::regs().cr().modify(|w| w.set_crypen(true)); + + // Load data into core, block by block. + let num_full_blocks = aad.len() / block_size; + for block in 0..num_full_blocks { + let mut index = block * block_size; + let end_index = index + block_size; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&aad[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + } + + // Handle the final block, which is incomplete. + if last_block_remainder > 0 { + let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + last_block[..last_block_remainder].copy_from_slice(&aad[aad.len() - last_block_remainder..aad.len()]); + let mut index = 0; + let end_index = block_size; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&last_block[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + // Block until input FIFO is empty + while !T::regs().sr().read().ifem() {} + } + + if last_aad_block { + // Switch to payload phase. + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + } + + self.store_context(ctx); + } + + /// Performs encryption/decryption on the provided context. + /// The context determines algorithm, mode, and state of the crypto accelerator. + /// When the last piece of data is supplied, `last_block` should be `true`. + /// This function panics under various mismatches of parameters. + /// Input and output buffer lengths must match. + /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. + /// Padding or ciphertext stealing must be managed by the application for these modes. + /// Data must also be a multiple of block size unless `last_block` is `true`. + pub fn payload_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) { + self.load_context(ctx); + + let block_size; + if ctx.algo == Algorithm::DES { + block_size = DES_BLOCK_SIZE; + } else { + block_size = AES_BLOCK_SIZE; } let last_block_remainder = input.len() % block_size; // Perform checks for correctness. - + if !ctx.aad_complete && ctx.header_len > 0 { + panic!("Additional associated data must be processed first!"); + } else if !ctx.aad_complete { + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + T::regs().cr().modify(|w| w.set_crypen(true)); + } if ctx.mode == Mode::GMAC { panic!("GMAC works on header data only. Do not call this function for GMAC."); } @@ -270,14 +381,15 @@ impl<'d, T: Instance> Cryp<'d, T> { if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt { //Handle special GCM partial block process. T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().write(|w| w.set_algomode0(6)); + T::regs().cr().modify(|w| w.set_algomode3(false)); + T::regs().cr().modify(|w| w.set_algomode0(6)); let iv1r = T::regs().csgcmccmr(7).read() - 1; T::regs().init(1).ivrr().write_value(iv1r); T::regs().cr().modify(|w| w.set_crypen(true)); } - let mut intermediate_data: [u8; 16] = [0; 16]; - let mut last_block: [u8; 16] = [0; 16]; + let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); let mut index = 0; let end_index = block_size; @@ -307,7 +419,8 @@ impl<'d, T: Instance> Cryp<'d, T> { if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt { //Handle special GCM partial block process. T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().write(|w| w.set_algomode0(8)); + T::regs().cr().write(|w| w.set_algomode3(true)); + T::regs().cr().write(|w| w.set_algomode0(0)); T::regs().init(1).ivrr().write_value(2); T::regs().cr().modify(|w| w.set_crypen(true)); T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); @@ -324,12 +437,51 @@ impl<'d, T: Instance> Cryp<'d, T> { } } } + + ctx.payload_len += input.len() as u64; + } + + /// This function only needs to be called for GCM, CCM, and GMAC modes to + /// generate an authentication tag. Calling this function on any other mode + /// does nothing except consumes the context. A buffer for the authentication + /// tag must be supplied. + pub fn finish_blocking(&self, mut ctx: Context, tag: &mut [u8; 16]) { + // Just consume the context if called for any other mode. + if (ctx.mode != Mode::GCM) || (ctx.mode != Mode::CCM) || (ctx.mode != Mode::GMAC) { + return; + } + + self.load_context(&mut ctx); + + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); + T::regs().cr().modify(|w| w.set_crypen(true)); + + let headerlen1: u32 = (ctx.header_len >> 32) as u32; + let headerlen2: u32 = ctx.header_len as u32; + let payloadlen1: u32 = (ctx.payload_len >> 32) as u32; + let payloadlen2: u32 = ctx.payload_len as u32; + + T::regs().din().write_value(headerlen1.swap_bytes()); + T::regs().din().write_value(headerlen2.swap_bytes()); + T::regs().din().write_value(payloadlen1.swap_bytes()); + T::regs().din().write_value(payloadlen2.swap_bytes()); + + while !T::regs().sr().read().ofne() {} + + tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + + T::regs().cr().modify(|w| w.set_crypen(false)); } fn prepare_key(&self, ctx: &Context) { if ctx.algo == Algorithm::AES && ctx.dir == Direction::Decrypt { if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) { T::regs().cr().modify(|w| w.set_algomode0(7)); + T::regs().cr().modify(|w| w.set_algomode3(false)); T::regs().cr().modify(|w| w.set_crypen(true)); while T::regs().sr().read().busy() {} } From fec26e896052cc0eac6bfa6415a4ebad5352d1d9 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 18 Feb 2024 21:40:18 -0500 Subject: [PATCH 566/760] Refactored ciphers into traits. --- embassy-stm32/src/cryp/mod.rs | 651 ++++++++++++++++++++++------------ 1 file changed, 431 insertions(+), 220 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 447bcf2f8..29c1db12e 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1,4 +1,6 @@ //! Crypto Accelerator (CRYP) +use core::marker::PhantomData; + use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::pac; @@ -9,51 +11,375 @@ use crate::{interrupt, peripherals, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits +/// This trait encapsulates all cipher-specific behavior/ +pub trait Cipher<'c> { + /// Processing block size. Determined by the processor and the algorithm. + const BLOCK_SIZE: usize; + + /// Indicates whether the cipher requires the application to provide padding. + /// If `true`, no partial blocks will be accepted (a panic will occur). + const REQUIRES_PADDING: bool = false; + + /// Returns the symmetric key. + fn key(&self) -> &'c [u8]; + + /// Returns the initialization vector. + fn iv(&self) -> &[u8]; + + /// Sets the processor algorithm mode according to the associated cipher. + fn set_algomode(&self, p: &pac::cryp::Cryp); + + /// Performs any key preparation within the processor, if necessary. + fn prepare_key(&self, _p: &pac::cryp::Cryp) {} + + /// Performs any cipher-specific initialization. + fn init_phase(&self, _p: &pac::cryp::Cryp) {} + + /// Called prior to processing the last data block for cipher-specific operations. + fn pre_final_block(&self, _p: &pac::cryp::Cryp) {} + + /// Called after processing the last data block for cipher-specific operations. + fn post_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _int_data: &[u8; AES_BLOCK_SIZE]) {} +} + +/// This trait enables restriction of ciphers to specific key sizes. +pub trait CipherSized {} + +/// This trait enables restriction of a header phase to authenticated ciphers only. +pub trait CipherAuthenticated {} + +/// AES-ECB Cipher Mode +pub struct AesEcb<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 0], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> AesEcb<'c, KEY_SIZE> { + /// Constructs a new AES-ECB cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE]) -> Self { + return Self { key: key, iv: &[0; 0] }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn prepare_key(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(7)); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_crypen(true)); + while p.sr().read().busy() {} + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(4)); + p.cr().modify(|w| w.set_algomode3(false)); + } +} + +impl<'c> CipherSized for AesEcb<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesEcb<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesEcb<'c, { 256 / 8 }> {} + +/// AES-CBC Cipher Mode +pub struct AesCbc<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 16], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> AesCbc<'c, KEY_SIZE> { + /// Constructs a new AES-CBC cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self { + return Self { key: key, iv: iv }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn prepare_key(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(7)); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_crypen(true)); + while p.sr().read().busy() {} + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(5)); + p.cr().modify(|w| w.set_algomode3(false)); + } +} + +impl<'c> CipherSized for AesCbc<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesCbc<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesCbc<'c, { 256 / 8 }> {} + +/// AES-CTR Cipher Mode +pub struct AesCtr<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 16], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> AesCtr<'c, KEY_SIZE> { + /// Constructs a new AES-CTR cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self { + return Self { key: key, iv: iv }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(6)); + p.cr().modify(|w| w.set_algomode3(false)); + } +} + +impl<'c> CipherSized for AesCtr<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {} + +///AES-GCM Cipher Mode +pub struct AesGcm<'c, const KEY_SIZE: usize> { + iv: [u8; 16], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> { + /// Constucts a new AES-GCM cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { + let mut new_gcm = Self { key: key, iv: [0; 16] }; + new_gcm.iv[..12].copy_from_slice(iv); + new_gcm.iv[15] = 2; + new_gcm + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &[u8] { + self.iv.as_slice() + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(0)); + p.cr().modify(|w| w.set_algomode3(true)); + } + + fn init_phase(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + + fn pre_final_block(&self, p: &pac::cryp::Cryp) { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_algomode0(6)); + let iv1r = p.csgcmccmr(7).read() - 1; + p.init(1).ivrr().write_value(iv1r); + p.cr().modify(|w| w.set_crypen(true)); + } + + fn post_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, int_data: &[u8; AES_BLOCK_SIZE]) { + if dir == Direction::Encrypt { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_crypen(false)); + p.cr().write(|w| w.set_algomode3(true)); + p.cr().write(|w| w.set_algomode0(0)); + p.init(1).ivrr().write_value(2); + p.cr().modify(|w| w.set_crypen(true)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + let mut index = 0; + let end_index = Self::BLOCK_SIZE; + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&int_data[index..index + 4]); + p.din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + for _ in 0..4 { + p.dout().read(); + } + } + } +} + +impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGcm<'c, KEY_SIZE> {} + +/// AES-GMAC Cipher Mode +pub struct AesGmac<'c, const KEY_SIZE: usize> { + iv: [u8; 16], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> { + /// Constructs a new AES-GMAC cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { + let mut new_gmac = Self { key: key, iv: [0; 16] }; + new_gmac.iv[..12].copy_from_slice(iv); + new_gmac.iv[15] = 2; + new_gmac + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &[u8] { + self.iv.as_slice() + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(0)); + p.cr().modify(|w| w.set_algomode3(true)); + } + + fn init_phase(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + + fn pre_final_block(&self, p: &pac::cryp::Cryp) { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_algomode0(6)); + let iv1r = p.csgcmccmr(7).read() - 1; + p.init(1).ivrr().write_value(iv1r); + p.cr().modify(|w| w.set_crypen(true)); + } + + fn post_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, int_data: &[u8; AES_BLOCK_SIZE]) { + if dir == Direction::Encrypt { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_crypen(false)); + p.cr().write(|w| w.set_algomode3(true)); + p.cr().write(|w| w.set_algomode0(0)); + p.init(1).ivrr().write_value(2); + p.cr().modify(|w| w.set_crypen(true)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + let mut index = 0; + let end_index = Self::BLOCK_SIZE; + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&int_data[index..index + 4]); + p.din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + for _ in 0..4 { + p.dout().read(); + } + } + } +} + +impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGmac<'c, KEY_SIZE> {} + +// struct AesCcm<'c, const KEY_SIZE: usize> { +// iv: &'c [u8], +// key: &'c [u8; KEY_SIZE], +// aad_len: usize, +// payload_len: usize, +// } + +// impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> { +// pub fn new(&self, key: &[u8; KEY_SIZE], iv: &[u8], aad_len: usize, payload_len: usize) { +// if iv.len() > 13 { +// panic!("CCM IV length must be 13 bytes or less."); +// } +// self.key = key; +// self.iv = iv; +// self.aad_len = aad_len; +// self.payload_len = payload_len; +// } +// } + +// impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> { +// const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + +// fn key(&self) -> &'c [u8] { +// self.key +// } + +// fn iv(&self) -> &'c [u8] { +// self.iv +// } + +// fn set_algomode(&self, p: &pac::cryp::Cryp) { +// p.cr().modify(|w| w.set_algomode0(1)); +// p.cr().modify(|w| w.set_algomode3(true)); +// } + +// fn init_phase(&self, p: &pac::cryp::Cryp) { +// todo!(); +// } +// } + +// impl<'c> CipherSized for AesCcm<'c, { 128 / 8 }> {} +// impl<'c> CipherSized for AesCcm<'c, { 192 / 8 }> {} +// impl<'c> CipherSized for AesCcm<'c, { 256 / 8 }> {} + /// Holds the state information for a cipher operation. /// Allows suspending/resuming of cipher operations. -pub struct Context<'c> { - algo: Algorithm, - mode: Mode, +pub struct Context<'c, C: Cipher<'c> + CipherSized> { + phantom_data: PhantomData<&'c C>, + cipher: &'c C, dir: Direction, last_block_processed: bool, aad_complete: bool, cr: u32, iv: [u32; 4], - key: &'c [u8], csgcmccm: [u32; 8], csgcm: [u32; 8], header_len: u64, payload_len: u64, } -/// Selects the encryption algorithm. -#[derive(PartialEq, Clone, Copy)] -pub enum Algorithm { - /// Advanced Encryption Standard - AES, - /// Data Encryption Standard - DES, - /// Triple-DES - TDES, -} - -/// Selects the cipher mode. -#[derive(PartialEq, Clone, Copy)] -pub enum Mode { - /// Electronic Codebook - ECB, - /// Cipher Block Chaining - CBC, - /// Counter Mode - CTR, - /// Galois Counter Mode - GCM, - /// Galois Message Authentication Code - GMAC, - /// Counter with CBC-MAC - CCM, -} - /// Selects whether the crypto processor operates in encryption or decryption mode. #[derive(PartialEq, Clone, Copy)] pub enum Direction { @@ -68,10 +394,6 @@ pub struct Cryp<'d, T: Instance> { _peripheral: PeripheralRef<'d, T>, } -/// Initialization vector of arbitrary length. -/// When an initialization vector is not needed, `None` may be supplied. -pub type InitVector<'v> = Option<&'v [u8]>; - impl<'d, T: Instance> Cryp<'d, T> { /// Create a new CRYP driver. pub fn new(peri: impl Peripheral

+ 'd) -> Self { @@ -85,51 +407,31 @@ impl<'d, T: Instance> Cryp<'d, T> { /// Key size must be 128, 192, or 256 bits. /// Initialization vector must only be supplied if necessary. /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. - pub fn start<'c>(&self, key: &'c [u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context<'c> { - let mut ctx = Context { - algo, - mode, + pub fn start<'c, C: Cipher<'c> + CipherSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { + let mut ctx: Context<'c, C> = Context { dir, last_block_processed: false, cr: 0, iv: [0; 4], - key, csgcmccm: [0; 8], csgcm: [0; 8], aad_complete: false, header_len: 0, payload_len: 0, + cipher: cipher, + phantom_data: PhantomData, }; T::regs().cr().modify(|w| w.set_crypen(false)); - // Checks for correctness - if algo == Algorithm::AES { - let keylen = key.len() * 8; - let ivlen; - if let Some(iv) = iv { - ivlen = iv.len() * 8; - } else { - ivlen = 0; - } - match keylen { - 128 => T::regs().cr().modify(|w| w.set_keysize(0)), - 192 => T::regs().cr().modify(|w| w.set_keysize(1)), - 256 => T::regs().cr().modify(|w| w.set_keysize(2)), - _ => panic!("Key length must be 128, 192, or 256 bits."), - } + let key = ctx.cipher.key(); - if (mode == Mode::GCM) && (ivlen != 96) { - panic!("IV length must be 96 bits for GCM."); - } else if (mode == Mode::CBC) && (ivlen != 128) { - panic!("IV length must be 128 bits for CBC."); - } else if (mode == Mode::CCM) && (ivlen != 128) { - panic!("IV length must be 128 bits for CCM."); - } else if (mode == Mode::CTR) && (ivlen != 128) { - panic!("IV length must be 128 bits for CTR."); - } else if (mode == Mode::GMAC) && (ivlen != 96) { - panic!("IV length must be 96 bits for GMAC."); - } + if key.len() == (128 / 8) { + T::regs().cr().modify(|w| w.set_keysize(0)); + } else if key.len() == (192 / 8) { + T::regs().cr().modify(|w| w.set_keysize(1)); + } else if key.len() == (256 / 8) { + T::regs().cr().modify(|w| w.set_keysize(2)); } self.load_key(key); @@ -137,40 +439,9 @@ impl<'d, T: Instance> Cryp<'d, T> { // Set data type to 8-bit. This will match software implementations. T::regs().cr().modify(|w| w.set_datatype(2)); - self.prepare_key(&ctx); + ctx.cipher.prepare_key(&T::regs()); - if algo == Algorithm::AES { - match mode { - Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(4)), - Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(5)), - Mode::CTR => T::regs().cr().modify(|w| w.set_algomode0(6)), - Mode::GCM => T::regs().cr().modify(|w| w.set_algomode0(0)), - Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode0(0)), - Mode::CCM => T::regs().cr().modify(|w| w.set_algomode0(1)), - } - match mode { - Mode::ECB => T::regs().cr().modify(|w| w.set_algomode3(false)), - Mode::CBC => T::regs().cr().modify(|w| w.set_algomode3(false)), - Mode::CTR => T::regs().cr().modify(|w| w.set_algomode3(false)), - Mode::GCM => T::regs().cr().modify(|w| w.set_algomode3(true)), - Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode3(true)), - Mode::CCM => T::regs().cr().modify(|w| w.set_algomode3(true)), - } - } else if algo == Algorithm::DES { - T::regs().cr().modify(|w| w.set_algomode3(false)); - match mode { - Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(2)), - Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(3)), - _ => panic!("Only ECB and CBC modes are valid for DES."), - } - } else if algo == Algorithm::TDES { - T::regs().cr().modify(|w| w.set_algomode3(false)); - match mode { - Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(0)), - Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(1)), - _ => panic!("Only ECB and CBC modes are valid for TDES."), - } - } + ctx.cipher.set_algomode(&T::regs()); // Set encrypt/decrypt if dir == Direction::Encrypt { @@ -180,38 +451,27 @@ impl<'d, T: Instance> Cryp<'d, T> { } // Load the IV into the registers. - if let Some(iv) = iv { - let mut full_iv: [u8; 16] = [0; 16]; - full_iv[0..iv.len()].copy_from_slice(iv); - - if (mode == Mode::GCM) || (mode == Mode::GMAC) { - full_iv[15] = 2; - } - - let mut iv_idx = 0; - let mut iv_word: [u8; 4] = [0; 4]; - iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); - iv_idx += 4; - T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); - iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); - iv_idx += 4; - T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); - iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); - iv_idx += 4; - T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); - iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); - T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); - } + let iv = ctx.cipher.iv(); + let mut full_iv: [u8; 16] = [0; 16]; + full_iv[0..iv.len()].copy_from_slice(iv); + let mut iv_idx = 0; + let mut iv_word: [u8; 4] = [0; 4]; + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); // Flush in/out FIFOs T::regs().cr().modify(|w| w.fflush()); - if mode == Mode::GCM { - // GCM init phase - T::regs().cr().modify(|w| w.set_gcm_ccmph(0)); - T::regs().cr().modify(|w| w.set_crypen(true)); - while T::regs().cr().read().crypen() {} - } + ctx.cipher.init_phase(&T::regs()); self.store_context(&mut ctx); @@ -224,42 +484,38 @@ impl<'d, T: Instance> Cryp<'d, T> { /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block. /// When supplying the last block of AAD, `last_aad_block` must be `true`. - pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8], last_aad_block: bool) { + pub fn aad_blocking<'c, C: Cipher<'c> + CipherSized + CipherAuthenticated>( + &self, + ctx: &mut Context<'c, C>, + aad: &[u8], + last_aad_block: bool, + ) { self.load_context(ctx); - let block_size; - if ctx.algo == Algorithm::DES { - block_size = DES_BLOCK_SIZE; - } else { - block_size = AES_BLOCK_SIZE; - } - let last_block_remainder = aad.len() % block_size; + let last_block_remainder = aad.len() % C::BLOCK_SIZE; // Perform checks for correctness. if ctx.aad_complete { panic!("Cannot update AAD after calling 'update'!") } - if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) { - panic!("Associated data only valid for GCM, GMAC, and CCM modes.") - } if !last_aad_block { if last_block_remainder != 0 { - panic!("Input length must be a multiple of {} bytes.", block_size); + panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE); } } ctx.header_len += aad.len() as u64; - // GCM header phase + // Header phase T::regs().cr().modify(|w| w.set_crypen(false)); T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); T::regs().cr().modify(|w| w.set_crypen(true)); // Load data into core, block by block. - let num_full_blocks = aad.len() / block_size; + let num_full_blocks = aad.len() / C::BLOCK_SIZE; for block in 0..num_full_blocks { - let mut index = block * block_size; - let end_index = index + block_size; + let mut index = block * C::BLOCK_SIZE; + let end_index = index + C::BLOCK_SIZE; // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; @@ -276,7 +532,7 @@ impl<'d, T: Instance> Cryp<'d, T> { let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; last_block[..last_block_remainder].copy_from_slice(&aad[aad.len() - last_block_remainder..aad.len()]); let mut index = 0; - let end_index = block_size; + let end_index = C::BLOCK_SIZE; // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; @@ -307,16 +563,16 @@ impl<'d, T: Instance> Cryp<'d, T> { /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. /// Padding or ciphertext stealing must be managed by the application for these modes. /// Data must also be a multiple of block size unless `last_block` is `true`. - pub fn payload_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) { + pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized>( + &self, + ctx: &mut Context<'c, C>, + input: &[u8], + output: &mut [u8], + last_block: bool, + ) { self.load_context(ctx); - let block_size; - if ctx.algo == Algorithm::DES { - block_size = DES_BLOCK_SIZE; - } else { - block_size = AES_BLOCK_SIZE; - } - let last_block_remainder = input.len() % block_size; + let last_block_remainder = input.len() % C::BLOCK_SIZE; // Perform checks for correctness. if !ctx.aad_complete && ctx.header_len > 0 { @@ -328,9 +584,6 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().cr().modify(|w| w.fflush()); T::regs().cr().modify(|w| w.set_crypen(true)); } - if ctx.mode == Mode::GMAC { - panic!("GMAC works on header data only. Do not call this function for GMAC."); - } if ctx.last_block_processed { panic!("The last block has already been processed!"); } @@ -339,24 +592,23 @@ impl<'d, T: Instance> Cryp<'d, T> { } if !last_block { if last_block_remainder != 0 { - panic!("Input length must be a multiple of {} bytes.", block_size); + panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE); } } - if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) { + if C::REQUIRES_PADDING { if last_block_remainder != 0 { - panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", block_size); + panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); } } - if last_block { ctx.last_block_processed = true; } // Load data into core, block by block. - let num_full_blocks = input.len() / block_size; + let num_full_blocks = input.len() / C::BLOCK_SIZE; for block in 0..num_full_blocks { - let mut index = block * block_size; - let end_index = index + block_size; + let mut index = block * C::BLOCK_SIZE; + let end_index = index + C::BLOCK_SIZE; // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; @@ -364,8 +616,8 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().din().write_value(u32::from_ne_bytes(in_word)); index += 4; } - let mut index = block * block_size; - let end_index = index + block_size; + let mut index = block * C::BLOCK_SIZE; + let end_index = index + C::BLOCK_SIZE; // Block until there is output to read. while !T::regs().sr().read().ofne() {} // Read block out @@ -378,21 +630,13 @@ impl<'d, T: Instance> Cryp<'d, T> { // Handle the final block, which is incomplete. if last_block_remainder > 0 { - if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt { - //Handle special GCM partial block process. - T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().modify(|w| w.set_algomode3(false)); - T::regs().cr().modify(|w| w.set_algomode0(6)); - let iv1r = T::regs().csgcmccmr(7).read() - 1; - T::regs().init(1).ivrr().write_value(iv1r); - T::regs().cr().modify(|w| w.set_crypen(true)); - } + ctx.cipher.pre_final_block(&T::regs()); let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); let mut index = 0; - let end_index = block_size; + let end_index = C::BLOCK_SIZE; // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; @@ -401,7 +645,7 @@ impl<'d, T: Instance> Cryp<'d, T> { index += 4; } let mut index = 0; - let end_index = block_size; + let end_index = C::BLOCK_SIZE; // Block until there is output to read. while !T::regs().sr().read().ofne() {} // Read block out @@ -416,41 +660,19 @@ impl<'d, T: Instance> Cryp<'d, T> { output[output_len - last_block_remainder..output_len] .copy_from_slice(&intermediate_data[0..last_block_remainder]); - if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt { - //Handle special GCM partial block process. - T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().write(|w| w.set_algomode3(true)); - T::regs().cr().write(|w| w.set_algomode0(0)); - T::regs().init(1).ivrr().write_value(2); - T::regs().cr().modify(|w| w.set_crypen(true)); - T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); - let mut index = 0; - let end_index = block_size; - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&intermediate_data[index..index + 4]); - T::regs().din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } - for _ in 0..4 { - T::regs().dout().read(); - } - } + ctx.cipher.post_final_block(&T::regs(), ctx.dir, &intermediate_data); } ctx.payload_len += input.len() as u64; } /// This function only needs to be called for GCM, CCM, and GMAC modes to - /// generate an authentication tag. Calling this function on any other mode - /// does nothing except consumes the context. A buffer for the authentication - /// tag must be supplied. - pub fn finish_blocking(&self, mut ctx: Context, tag: &mut [u8; 16]) { - // Just consume the context if called for any other mode. - if (ctx.mode != Mode::GCM) || (ctx.mode != Mode::CCM) || (ctx.mode != Mode::GMAC) { - return; - } - + /// generate an authentication tag. + pub fn finish_blocking<'c, C: Cipher<'c> + CipherSized + CipherAuthenticated>( + &self, + mut ctx: Context<'c, C>, + tag: &mut [u8; 16], + ) { self.load_context(&mut ctx); T::regs().cr().modify(|w| w.set_crypen(false)); @@ -477,17 +699,6 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().cr().modify(|w| w.set_crypen(false)); } - fn prepare_key(&self, ctx: &Context) { - if ctx.algo == Algorithm::AES && ctx.dir == Direction::Decrypt { - if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) { - T::regs().cr().modify(|w| w.set_algomode0(7)); - T::regs().cr().modify(|w| w.set_algomode3(false)); - T::regs().cr().modify(|w| w.set_crypen(true)); - while T::regs().sr().read().busy() {} - } - } - } - fn load_key(&self, key: &[u8]) { // Load the key into the registers. let mut keyidx = 0; @@ -524,7 +735,7 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword)); } - fn store_context(&self, ctx: &mut Context) { + fn store_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &mut Context<'c, C>) { // Wait for data block processing to finish. while !T::regs().sr().read().ifem() {} while T::regs().sr().read().ofne() {} @@ -545,7 +756,7 @@ impl<'d, T: Instance> Cryp<'d, T> { } } - fn load_context(&self, ctx: &Context) { + fn load_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &Context<'c, C>) { // Reload state registers. T::regs().cr().write(|w| w.0 = ctx.cr); T::regs().init(0).ivlr().write_value(ctx.iv[0]); @@ -556,10 +767,10 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]); T::regs().csgcmr(i).write_value(ctx.csgcm[i]); } - self.load_key(ctx.key); + self.load_key(ctx.cipher.key()); // Prepare key if applicable. - self.prepare_key(ctx); + ctx.cipher.prepare_key(&T::regs()); T::regs().cr().write(|w| w.0 = ctx.cr); // Enable crypto processor. From 690b2118c6fdad88bf1e595b6a0c0afdb0583d28 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 20 Feb 2024 11:54:39 -0500 Subject: [PATCH 567/760] CCM mode functional. --- embassy-stm32/src/cryp/mod.rs | 372 ++++++++++++++++++++++++++-------- 1 file changed, 293 insertions(+), 79 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 29c1db12e..fe248def1 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1,6 +1,6 @@ //! Crypto Accelerator (CRYP) +use core::cmp::min; use core::marker::PhantomData; - use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::pac; @@ -21,7 +21,7 @@ pub trait Cipher<'c> { const REQUIRES_PADDING: bool = false; /// Returns the symmetric key. - fn key(&self) -> &'c [u8]; + fn key(&self) -> &[u8]; /// Returns the initialization vector. fn iv(&self) -> &[u8]; @@ -36,10 +36,25 @@ pub trait Cipher<'c> { fn init_phase(&self, _p: &pac::cryp::Cryp) {} /// Called prior to processing the last data block for cipher-specific operations. - fn pre_final_block(&self, _p: &pac::cryp::Cryp) {} + fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction) -> [u32; 4] { + return [0; 4]; + } /// Called after processing the last data block for cipher-specific operations. - fn post_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _int_data: &[u8; AES_BLOCK_SIZE]) {} + fn post_final_block( + &self, + _p: &pac::cryp::Cryp, + _dir: Direction, + _int_data: &[u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + _padding_mask: [u8; 16], + ) { + } + + /// Called prior to processing the first associated data block for cipher-specific operations. + fn get_header_block(&self) -> &[u8] { + return [0; 0].as_slice(); + } } /// This trait enables restriction of ciphers to specific key sizes. @@ -204,17 +219,27 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { while p.cr().read().crypen() {} } - fn pre_final_block(&self, p: &pac::cryp::Cryp) { + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] { //Handle special GCM partial block process. - p.cr().modify(|w| w.set_crypen(false)); - p.cr().modify(|w| w.set_algomode3(false)); - p.cr().modify(|w| w.set_algomode0(6)); - let iv1r = p.csgcmccmr(7).read() - 1; - p.init(1).ivrr().write_value(iv1r); - p.cr().modify(|w| w.set_crypen(true)); + if dir == Direction::Encrypt { + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_algomode0(6)); + let iv1r = p.csgcmccmr(7).read() - 1; + p.init(1).ivrr().write_value(iv1r); + p.cr().modify(|w| w.set_crypen(true)); + } + [0; 4] } - fn post_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, int_data: &[u8; AES_BLOCK_SIZE]) { + fn post_final_block( + &self, + p: &pac::cryp::Cryp, + dir: Direction, + int_data: &[u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + _padding_mask: [u8; 16], + ) { if dir == Direction::Encrypt { //Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); @@ -281,17 +306,27 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { while p.cr().read().crypen() {} } - fn pre_final_block(&self, p: &pac::cryp::Cryp) { + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] { //Handle special GCM partial block process. - p.cr().modify(|w| w.set_crypen(false)); - p.cr().modify(|w| w.set_algomode3(false)); - p.cr().modify(|w| w.set_algomode0(6)); - let iv1r = p.csgcmccmr(7).read() - 1; - p.init(1).ivrr().write_value(iv1r); - p.cr().modify(|w| w.set_crypen(true)); + if dir == Direction::Encrypt { + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_algomode0(6)); + let iv1r = p.csgcmccmr(7).read() - 1; + p.init(1).ivrr().write_value(iv1r); + p.cr().modify(|w| w.set_crypen(true)); + } + [0; 4] } - fn post_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, int_data: &[u8; AES_BLOCK_SIZE]) { + fn post_final_block( + &self, + p: &pac::cryp::Cryp, + dir: Direction, + int_data: &[u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + _padding_mask: [u8; 16], + ) { if dir == Direction::Encrypt { //Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); @@ -320,49 +355,180 @@ impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {} impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGmac<'c, KEY_SIZE> {} -// struct AesCcm<'c, const KEY_SIZE: usize> { -// iv: &'c [u8], -// key: &'c [u8; KEY_SIZE], -// aad_len: usize, -// payload_len: usize, -// } +pub struct AesCcm<'c, const KEY_SIZE: usize> { + key: &'c [u8; KEY_SIZE], + aad_header: [u8; 6], + aad_header_len: usize, + block0: [u8; 16], + ctr: [u8; 16], +} -// impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> { -// pub fn new(&self, key: &[u8; KEY_SIZE], iv: &[u8], aad_len: usize, payload_len: usize) { -// if iv.len() > 13 { -// panic!("CCM IV length must be 13 bytes or less."); -// } -// self.key = key; -// self.iv = iv; -// self.aad_len = aad_len; -// self.payload_len = payload_len; -// } -// } +impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> { + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8], aad_len: usize, payload_len: usize, tag_len: u8) -> Self { + if (iv.len()) > 13 || (iv.len() < 7) { + panic!("CCM IV length must be 7-13 bytes."); + } + if (tag_len < 4) || (tag_len > 16) { + panic!("Tag length must be between 4 and 16 bytes."); + } + if tag_len % 2 > 0 { + panic!("Tag length must be a multiple of 2 bytes."); + } -// impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> { -// const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + let mut aad_header: [u8; 6] = [0; 6]; + let mut aad_header_len = 0; + let mut block0: [u8; 16] = [0; 16]; + if aad_len != 0 { + if aad_len < 65280 { + aad_header[0] = (aad_len >> 8) as u8 & 0xFF; + aad_header[1] = aad_len as u8 & 0xFF; + aad_header_len = 2; + } else { + aad_header[0] = 0xFF; + aad_header[1] = 0xFE; + let aad_len_bytes: [u8; 4] = aad_len.to_be_bytes(); + aad_header[2] = aad_len_bytes[0]; + aad_header[3] = aad_len_bytes[1]; + aad_header[4] = aad_len_bytes[2]; + aad_header[5] = aad_len_bytes[3]; + aad_header_len = 6; + } + } + let total_aad_len = aad_header_len + aad_len; + let mut aad_padding_len = 16 - (total_aad_len % 16); + if aad_padding_len == 16 { + aad_padding_len = 0; + } + aad_header_len += aad_padding_len; + let total_aad_len_padded = aad_header_len + aad_len; + if total_aad_len_padded > 0 { + block0[0] = 0x40; + } + block0[0] |= (((tag_len - 2) >> 1) & 0x07) << 3; + block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07; + block0[1..1 + iv.len()].copy_from_slice(iv); + let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes(); + if iv.len() <= 11 { + block0[12] = payload_len_bytes[0]; + } else if payload_len_bytes[0] > 0 { + panic!("Message is too large for given IV size."); + } + if iv.len() <= 12 { + block0[13] = payload_len_bytes[1]; + } else if payload_len_bytes[1] > 0 { + panic!("Message is too large for given IV size."); + } + block0[14] = payload_len_bytes[2]; + block0[15] = payload_len_bytes[3]; + let mut ctr: [u8; 16] = [0; 16]; + ctr[0] = block0[0] & 0x07; + ctr[1..1 + iv.len()].copy_from_slice(&block0[1..1 + iv.len()]); + ctr[15] = 0x01; -// fn key(&self) -> &'c [u8] { -// self.key -// } + return Self { + key: key, + aad_header: aad_header, + aad_header_len: aad_header_len, + block0: block0, + ctr: ctr, + }; + } +} -// fn iv(&self) -> &'c [u8] { -// self.iv -// } +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; -// fn set_algomode(&self, p: &pac::cryp::Cryp) { -// p.cr().modify(|w| w.set_algomode0(1)); -// p.cr().modify(|w| w.set_algomode3(true)); -// } + fn key(&self) -> &'c [u8] { + self.key + } -// fn init_phase(&self, p: &pac::cryp::Cryp) { -// todo!(); -// } -// } + fn iv(&self) -> &[u8] { + self.ctr.as_slice() + } -// impl<'c> CipherSized for AesCcm<'c, { 128 / 8 }> {} -// impl<'c> CipherSized for AesCcm<'c, { 192 / 8 }> {} -// impl<'c> CipherSized for AesCcm<'c, { 256 / 8 }> {} + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(1)); + p.cr().modify(|w| w.set_algomode3(true)); + } + + fn init_phase(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + + let mut index = 0; + let end_index = index + Self::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&self.block0[index..index + 4]); + p.din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + + fn get_header_block(&self) -> &[u8] { + return &self.aad_header[0..self.aad_header_len]; + } + + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] { + //Handle special CCM partial block process. + let mut temp1 = [0; 4]; + if dir == Direction::Decrypt { + p.cr().modify(|w| w.set_crypen(false)); + let iv1temp = p.init(1).ivrr().read(); + temp1[0] = p.csgcmccmr(0).read(); + temp1[1] = p.csgcmccmr(1).read(); + temp1[2] = p.csgcmccmr(2).read(); + temp1[3] = p.csgcmccmr(3).read(); + p.init(1).ivrr().write_value(iv1temp); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_algomode0(6)); + p.cr().modify(|w| w.set_crypen(true)); + } + return temp1; + } + + fn post_final_block( + &self, + p: &pac::cryp::Cryp, + dir: Direction, + int_data: &[u8; AES_BLOCK_SIZE], + temp1: [u32; 4], + padding_mask: [u8; 16], + ) { + if dir == Direction::Decrypt { + //Handle special CCM partial block process. + let mut intdata_o: [u32; 4] = [0; 4]; + for i in 0..intdata_o.len() { + intdata_o[i] = p.dout().read(); + } + let mut temp2 = [0; 4]; + temp2[0] = p.csgcmccmr(0).read(); + temp2[1] = p.csgcmccmr(1).read(); + temp2[2] = p.csgcmccmr(2).read(); + temp2[3] = p.csgcmccmr(3).read(); + p.cr().write(|w| w.set_algomode3(true)); + p.cr().write(|w| w.set_algomode0(1)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + // Header phase + p.cr().modify(|w| w.set_gcm_ccmph(1)); + let mut in_data: [u32; 4] = [0; 4]; + for i in 0..in_data.len() { + let mut mask_bytes: [u8; 4] = [0; 4]; + mask_bytes.copy_from_slice(&padding_mask[(i * 4)..(i * 4) + 4]); + let mask_word = u32::from_le_bytes(mask_bytes); + in_data[i] = intdata_o[i] & mask_word; + in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; + } + } + } +} + +impl<'c> CipherSized for AesCcm<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesCcm<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesCcm<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesCcm<'c, KEY_SIZE> {} /// Holds the state information for a cipher operation. /// Allows suspending/resuming of cipher operations. @@ -371,6 +537,7 @@ pub struct Context<'c, C: Cipher<'c> + CipherSized> { cipher: &'c C, dir: Direction, last_block_processed: bool, + header_processed: bool, aad_complete: bool, cr: u32, iv: [u32; 4], @@ -378,6 +545,8 @@ pub struct Context<'c, C: Cipher<'c> + CipherSized> { csgcm: [u32; 8], header_len: u64, payload_len: u64, + aad_buffer: [u8; 16], + aad_buffer_len: usize, } /// Selects whether the crypto processor operates in encryption or decryption mode. @@ -420,6 +589,9 @@ impl<'d, T: Instance> Cryp<'d, T> { payload_len: 0, cipher: cipher, phantom_data: PhantomData, + header_processed: false, + aad_buffer: [0; 16], + aad_buffer_len: 0, }; T::regs().cr().modify(|w| w.set_crypen(false)); @@ -492,16 +664,9 @@ impl<'d, T: Instance> Cryp<'d, T> { ) { self.load_context(ctx); - let last_block_remainder = aad.len() % C::BLOCK_SIZE; - // Perform checks for correctness. if ctx.aad_complete { - panic!("Cannot update AAD after calling 'update'!") - } - if !last_aad_block { - if last_block_remainder != 0 { - panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE); - } + panic!("Cannot update AAD after starting payload!") } ctx.header_len += aad.len() as u64; @@ -511,11 +676,49 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); T::regs().cr().modify(|w| w.set_crypen(true)); - // Load data into core, block by block. - let num_full_blocks = aad.len() / C::BLOCK_SIZE; - for block in 0..num_full_blocks { - let mut index = block * C::BLOCK_SIZE; - let end_index = index + C::BLOCK_SIZE; + // First write the header B1 block if not yet written. + if !ctx.header_processed { + ctx.header_processed = true; + let header = ctx.cipher.get_header_block(); + ctx.aad_buffer[0..header.len()].copy_from_slice(header); + ctx.aad_buffer_len += header.len(); + } + + // Fill the header block to make a full block. + let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len); + ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]); + ctx.aad_buffer_len += len_to_copy; + ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); + let mut aad_len_remaining = aad.len() - len_to_copy; + + if ctx.aad_buffer_len < C::BLOCK_SIZE { + // The buffer isn't full and this is the last buffer, so process it as is (already padded). + if last_aad_block { + let mut index = 0; + let end_index = C::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&aad[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + + // Switch to payload phase. + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + } else { + // Just return because we don't yet have a full block to process. + return; + } + } else { + // Load the full block from the buffer. + let mut index = 0; + let end_index = C::BLOCK_SIZE; // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; @@ -527,20 +730,26 @@ impl<'d, T: Instance> Cryp<'d, T> { while !T::regs().sr().read().ifem() {} } - // Handle the final block, which is incomplete. - if last_block_remainder > 0 { - let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; - last_block[..last_block_remainder].copy_from_slice(&aad[aad.len() - last_block_remainder..aad.len()]); - let mut index = 0; - let end_index = C::BLOCK_SIZE; + // Handle a partial block that is passed in. + ctx.aad_buffer_len = 0; + let leftovers = aad_len_remaining % C::BLOCK_SIZE; + ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]); + aad_len_remaining -= leftovers; + assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0); + + // Load full data blocks into core. + let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; + for _ in 0..num_full_blocks { + let mut index = len_to_copy; + let end_index = len_to_copy + C::BLOCK_SIZE; // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&last_block[index..index + 4]); + in_word.copy_from_slice(&aad[index..index + 4]); T::regs().din().write_value(u32::from_ne_bytes(in_word)); index += 4; } - // Block until input FIFO is empty + // Block until input FIFO is empty. while !T::regs().sr().read().ifem() {} } @@ -630,7 +839,7 @@ impl<'d, T: Instance> Cryp<'d, T> { // Handle the final block, which is incomplete. if last_block_remainder > 0 { - ctx.cipher.pre_final_block(&T::regs()); + let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir); let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; @@ -660,10 +869,15 @@ impl<'d, T: Instance> Cryp<'d, T> { output[output_len - last_block_remainder..output_len] .copy_from_slice(&intermediate_data[0..last_block_remainder]); - ctx.cipher.post_final_block(&T::regs(), ctx.dir, &intermediate_data); + let mut mask: [u8; 16] = [0; 16]; + mask[..last_block_remainder].fill(0xFF); + ctx.cipher + .post_final_block(&T::regs(), ctx.dir, &intermediate_data, temp1, mask); } ctx.payload_len += input.len() as u64; + + self.store_context(ctx); } /// This function only needs to be called for GCM, CCM, and GMAC modes to From 1e21b758f795b5cc8a2331aacbc2a9a39bb7a7fb Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 20 Feb 2024 14:27:37 -0500 Subject: [PATCH 568/760] Corrected GCM tag generation. --- embassy-stm32/src/cryp/mod.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index fe248def1..81446e39e 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -45,7 +45,7 @@ pub trait Cipher<'c> { &self, _p: &pac::cryp::Cryp, _dir: Direction, - _int_data: &[u8; AES_BLOCK_SIZE], + _int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], _padding_mask: [u8; 16], ) { @@ -236,16 +236,18 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { &self, p: &pac::cryp::Cryp, dir: Direction, - int_data: &[u8; AES_BLOCK_SIZE], + int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], - _padding_mask: [u8; 16], + padding_mask: [u8; AES_BLOCK_SIZE], ) { if dir == Direction::Encrypt { //Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); - p.cr().write(|w| w.set_algomode3(true)); - p.cr().write(|w| w.set_algomode0(0)); - p.init(1).ivrr().write_value(2); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(0)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_gcm_ccmph(3)); let mut index = 0; @@ -323,7 +325,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { &self, p: &pac::cryp::Cryp, dir: Direction, - int_data: &[u8; AES_BLOCK_SIZE], + int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], _padding_mask: [u8; 16], ) { @@ -493,7 +495,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> { &self, p: &pac::cryp::Cryp, dir: Direction, - int_data: &[u8; AES_BLOCK_SIZE], + int_data: &mut [u8; AES_BLOCK_SIZE], temp1: [u32; 4], padding_mask: [u8; 16], ) { @@ -872,7 +874,7 @@ impl<'d, T: Instance> Cryp<'d, T> { let mut mask: [u8; 16] = [0; 16]; mask[..last_block_remainder].fill(0xFF); ctx.cipher - .post_final_block(&T::regs(), ctx.dir, &intermediate_data, temp1, mask); + .post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask); } ctx.payload_len += input.len() as u64; From f64a62149e423f6fdb643f7343d971eedc4a3a12 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 20 Feb 2024 15:26:31 -0500 Subject: [PATCH 569/760] Corrected CCM partial block ops. --- embassy-stm32/src/cryp/mod.rs | 46 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 81446e39e..634c85883 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -327,14 +327,16 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], - _padding_mask: [u8; 16], + padding_mask: [u8; AES_BLOCK_SIZE], ) { if dir == Direction::Encrypt { //Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); - p.cr().write(|w| w.set_algomode3(true)); - p.cr().write(|w| w.set_algomode0(0)); - p.init(1).ivrr().write_value(2); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(0)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_gcm_ccmph(3)); let mut index = 0; @@ -479,10 +481,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> { if dir == Direction::Decrypt { p.cr().modify(|w| w.set_crypen(false)); let iv1temp = p.init(1).ivrr().read(); - temp1[0] = p.csgcmccmr(0).read(); - temp1[1] = p.csgcmccmr(1).read(); - temp1[2] = p.csgcmccmr(2).read(); - temp1[3] = p.csgcmccmr(3).read(); + temp1[0] = p.csgcmccmr(0).read().swap_bytes(); + temp1[1] = p.csgcmccmr(1).read().swap_bytes(); + temp1[2] = p.csgcmccmr(2).read().swap_bytes(); + temp1[3] = p.csgcmccmr(3).read().swap_bytes(); p.init(1).ivrr().write_value(iv1temp); p.cr().modify(|w| w.set_algomode3(false)); p.cr().modify(|w| w.set_algomode0(6)); @@ -501,27 +503,27 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> { ) { if dir == Direction::Decrypt { //Handle special CCM partial block process. - let mut intdata_o: [u32; 4] = [0; 4]; - for i in 0..intdata_o.len() { - intdata_o[i] = p.dout().read(); - } let mut temp2 = [0; 4]; - temp2[0] = p.csgcmccmr(0).read(); - temp2[1] = p.csgcmccmr(1).read(); - temp2[2] = p.csgcmccmr(2).read(); - temp2[3] = p.csgcmccmr(3).read(); - p.cr().write(|w| w.set_algomode3(true)); - p.cr().write(|w| w.set_algomode0(1)); + temp2[0] = p.csgcmccmr(0).read().swap_bytes(); + temp2[1] = p.csgcmccmr(1).read().swap_bytes(); + temp2[2] = p.csgcmccmr(2).read().swap_bytes(); + temp2[3] = p.csgcmccmr(3).read().swap_bytes(); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(1)); p.cr().modify(|w| w.set_gcm_ccmph(3)); // Header phase p.cr().modify(|w| w.set_gcm_ccmph(1)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } let mut in_data: [u32; 4] = [0; 4]; for i in 0..in_data.len() { - let mut mask_bytes: [u8; 4] = [0; 4]; - mask_bytes.copy_from_slice(&padding_mask[(i * 4)..(i * 4) + 4]); - let mask_word = u32::from_le_bytes(mask_bytes); - in_data[i] = intdata_o[i] & mask_word; + let mut int_bytes: [u8; 4] = [0; 4]; + int_bytes.copy_from_slice(&int_data[(i * 4)..(i * 4) + 4]); + let int_word = u32::from_le_bytes(int_bytes); + in_data[i] = int_word; in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; + p.din().write_value(in_data[i]); } } } From 14c2c28e068d6e506c372611800e6dded8d8f440 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 20 Feb 2024 18:05:35 -0500 Subject: [PATCH 570/760] Corrected additional associated data operation. --- embassy-stm32/src/cryp/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 634c85883..d53252a6a 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -703,7 +703,7 @@ impl<'d, T: Instance> Cryp<'d, T> { // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&aad[index..index + 4]); + in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); T::regs().din().write_value(u32::from_ne_bytes(in_word)); index += 4; } From 29d8b459568b53f1e281d0914b5c897206c9bd4b Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Wed, 21 Feb 2024 12:07:53 -0500 Subject: [PATCH 571/760] Add DES and TDES support. Support variable tag sizes. --- embassy-stm32/src/cryp/mod.rs | 237 +++++++++++++++++++++++++++++----- 1 file changed, 203 insertions(+), 34 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index d53252a6a..a4f1e42dc 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -60,8 +60,152 @@ pub trait Cipher<'c> { /// This trait enables restriction of ciphers to specific key sizes. pub trait CipherSized {} +/// This trait enables restriction of initialization vectors to sizes compatibile with a cipher mode. +pub trait IVSized {} + /// This trait enables restriction of a header phase to authenticated ciphers only. -pub trait CipherAuthenticated {} +pub trait CipherAuthenticated { + /// Defines the authentication tag size. + const TAG_SIZE: usize = TAG_SIZE; +} + +/// TDES-ECB Cipher Mode +pub struct TdesEcb<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 0], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> TdesEcb<'c, KEY_SIZE> { + /// Constructs a new AES-ECB cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE]) -> Self { + return Self { key: key, iv: &[0; 0] }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = DES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(0)); + p.cr().modify(|w| w.set_algomode3(false)); + } +} + +impl<'c> CipherSized for TdesEcb<'c, { 112 / 8 }> {} +impl<'c> CipherSized for TdesEcb<'c, { 168 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for TdesEcb<'c, KEY_SIZE> {} + +/// TDES-CBC Cipher Mode +pub struct TdesCbc<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 8], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> TdesCbc<'c, KEY_SIZE> { + /// Constructs a new TDES-CBC cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self { + return Self { key: key, iv: iv }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = DES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(1)); + p.cr().modify(|w| w.set_algomode3(false)); + } +} + +impl<'c> CipherSized for TdesCbc<'c, { 112 / 8 }> {} +impl<'c> CipherSized for TdesCbc<'c, { 168 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for TdesCbc<'c, KEY_SIZE> {} + +/// DES-ECB Cipher Mode +pub struct DesEcb<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 0], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> DesEcb<'c, KEY_SIZE> { + /// Constructs a new AES-ECB cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE]) -> Self { + return Self { key: key, iv: &[0; 0] }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = DES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(2)); + p.cr().modify(|w| w.set_algomode3(false)); + } +} + +impl<'c> CipherSized for DesEcb<'c, { 56 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for DesEcb<'c, KEY_SIZE> {} + +/// DES-CBC Cipher Mode +pub struct DesCbc<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 8], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> DesCbc<'c, KEY_SIZE> { + /// Constructs a new AES-CBC cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self { + return Self { key: key, iv: iv }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = DES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(3)); + p.cr().modify(|w| w.set_algomode3(false)); + } +} + +impl<'c> CipherSized for DesCbc<'c, { 56 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for DesCbc<'c, KEY_SIZE> {} /// AES-ECB Cipher Mode pub struct AesEcb<'c, const KEY_SIZE: usize> { @@ -96,7 +240,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { } fn set_algomode(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(4)); + p.cr().modify(|w| w.set_algomode0(2)); p.cr().modify(|w| w.set_algomode3(false)); } } @@ -104,6 +248,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { impl<'c> CipherSized for AesEcb<'c, { 128 / 8 }> {} impl<'c> CipherSized for AesEcb<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesEcb<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for AesEcb<'c, KEY_SIZE> {} /// AES-CBC Cipher Mode pub struct AesCbc<'c, const KEY_SIZE: usize> { @@ -146,6 +291,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> { impl<'c> CipherSized for AesCbc<'c, { 128 / 8 }> {} impl<'c> CipherSized for AesCbc<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesCbc<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for AesCbc<'c, KEY_SIZE> {} /// AES-CTR Cipher Mode pub struct AesCtr<'c, const KEY_SIZE: usize> { @@ -180,6 +326,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> { impl<'c> CipherSized for AesCtr<'c, { 128 / 8 }> {} impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {} ///AES-GCM Cipher Mode pub struct AesGcm<'c, const KEY_SIZE: usize> { @@ -268,7 +415,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {} impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {} -impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGcm<'c, KEY_SIZE> {} +impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {} +impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {} /// AES-GMAC Cipher Mode pub struct AesGmac<'c, const KEY_SIZE: usize> { @@ -357,9 +505,11 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {} impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {} -impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGmac<'c, KEY_SIZE> {} +impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {} +impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {} -pub struct AesCcm<'c, const KEY_SIZE: usize> { +/// AES-CCM Cipher Mode +pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> { key: &'c [u8; KEY_SIZE], aad_header: [u8; 6], aad_header_len: usize, @@ -367,18 +517,9 @@ pub struct AesCcm<'c, const KEY_SIZE: usize> { ctr: [u8; 16], } -impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> { - pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8], aad_len: usize, payload_len: usize, tag_len: u8) -> Self { - if (iv.len()) > 13 || (iv.len() < 7) { - panic!("CCM IV length must be 7-13 bytes."); - } - if (tag_len < 4) || (tag_len > 16) { - panic!("Tag length must be between 4 and 16 bytes."); - } - if tag_len % 2 > 0 { - panic!("Tag length must be a multiple of 2 bytes."); - } - +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> { + /// Constructs a new AES-CCM cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self { let mut aad_header: [u8; 6] = [0; 6]; let mut aad_header_len = 0; let mut block0: [u8; 16] = [0; 16]; @@ -408,7 +549,7 @@ impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> { if total_aad_len_padded > 0 { block0[0] = 0x40; } - block0[0] |= (((tag_len - 2) >> 1) & 0x07) << 3; + block0[0] |= ((((TAG_SIZE as u8) - 2) >> 1) & 0x07) << 3; block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07; block0[1..1 + iv.len()].copy_from_slice(iv); let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes(); @@ -439,7 +580,9 @@ impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> { } } -impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> { +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c> + for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> +{ const BLOCK_SIZE: usize = AES_BLOCK_SIZE; fn key(&self) -> &'c [u8] { @@ -529,10 +672,23 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> { } } -impl<'c> CipherSized for AesCcm<'c, { 128 / 8 }> {} -impl<'c> CipherSized for AesCcm<'c, { 192 / 8 }> {} -impl<'c> CipherSized for AesCcm<'c, { 256 / 8 }> {} -impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesCcm<'c, KEY_SIZE> {} +impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {} +impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {} +impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {} +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {} +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {} +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {} +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {} +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {} +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {} +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {} +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {} +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {} +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {} +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {} +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {} +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {} +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {} /// Holds the state information for a cipher operation. /// Allows suspending/resuming of cipher operations. @@ -580,7 +736,7 @@ impl<'d, T: Instance> Cryp<'d, T> { /// Key size must be 128, 192, or 256 bits. /// Initialization vector must only be supplied if necessary. /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. - pub fn start<'c, C: Cipher<'c> + CipherSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { + pub fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { let mut ctx: Context<'c, C> = Context { dir, last_block_processed: false, @@ -660,7 +816,11 @@ impl<'d, T: Instance> Cryp<'d, T> { /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block. /// When supplying the last block of AAD, `last_aad_block` must be `true`. - pub fn aad_blocking<'c, C: Cipher<'c> + CipherSized + CipherAuthenticated>( + pub fn aad_blocking< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( &self, ctx: &mut Context<'c, C>, aad: &[u8], @@ -776,7 +936,7 @@ impl<'d, T: Instance> Cryp<'d, T> { /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. /// Padding or ciphertext stealing must be managed by the application for these modes. /// Data must also be a multiple of block size unless `last_block` is `true`. - pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized>( + pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>( &self, ctx: &mut Context<'c, C>, input: &[u8], @@ -886,11 +1046,14 @@ impl<'d, T: Instance> Cryp<'d, T> { /// This function only needs to be called for GCM, CCM, and GMAC modes to /// generate an authentication tag. - pub fn finish_blocking<'c, C: Cipher<'c> + CipherSized + CipherAuthenticated>( + pub fn finish_blocking< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( &self, mut ctx: Context<'c, C>, - tag: &mut [u8; 16], - ) { + ) -> [u8; TAG_SIZE] { self.load_context(&mut ctx); T::regs().cr().modify(|w| w.set_crypen(false)); @@ -909,12 +1072,17 @@ impl<'d, T: Instance> Cryp<'d, T> { while !T::regs().sr().read().ofne() {} - tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); - tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); - tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); - tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + let mut full_tag: [u8; 16] = [0; 16]; + full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; + tag.copy_from_slice(&full_tag[0..TAG_SIZE]); T::regs().cr().modify(|w| w.set_crypen(false)); + + tag } fn load_key(&self, key: &[u8]) { @@ -949,7 +1117,8 @@ impl<'d, T: Instance> Cryp<'d, T> { keyword.copy_from_slice(&key[keyidx..keyidx + 4]); keyidx += 4; T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword)); - keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyword = [0; 4]; + keyword[0..key.len() - keyidx].copy_from_slice(&key[keyidx..key.len()]); T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword)); } From cbca3a5c9f8f46582287b88db173ad6876686141 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Wed, 21 Feb 2024 12:39:10 -0500 Subject: [PATCH 572/760] Support v1 and v2 cryp variants. --- embassy-stm32/src/cryp/mod.rs | 156 +++++++++++++++++++++++++++++----- 1 file changed, 133 insertions(+), 23 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index a4f1e42dc..965e4a35d 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1,4 +1,5 @@ //! Crypto Accelerator (CRYP) +#[cfg(cryp_v2)] use core::cmp::min; use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; @@ -95,8 +96,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> { } fn set_algomode(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(0)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(0)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(0)); + p.cr().modify(|w| w.set_algomode3(false)); + } } } @@ -130,8 +138,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> { } fn set_algomode(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(1)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(1)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(1)); + p.cr().modify(|w| w.set_algomode3(false)); + } } } @@ -165,8 +180,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> { } fn set_algomode(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(2)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(2)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(2)); + p.cr().modify(|w| w.set_algomode3(false)); + } } } @@ -199,8 +221,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> { } fn set_algomode(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(3)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(3)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(3)); + p.cr().modify(|w| w.set_algomode3(false)); + } } } @@ -233,15 +262,29 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { } fn prepare_key(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(7)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(7)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(7)); + p.cr().modify(|w| w.set_algomode3(false)); + } p.cr().modify(|w| w.set_crypen(true)); while p.sr().read().busy() {} } fn set_algomode(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(2)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(2)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(2)); + p.cr().modify(|w| w.set_algomode3(false)); + } } } @@ -276,15 +319,29 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> { } fn prepare_key(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(7)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(7)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(7)); + p.cr().modify(|w| w.set_algomode3(false)); + } p.cr().modify(|w| w.set_crypen(true)); while p.sr().read().busy() {} } fn set_algomode(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(5)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(5)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(5)); + p.cr().modify(|w| w.set_algomode3(false)); + } } } @@ -318,8 +375,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> { } fn set_algomode(&self, p: &pac::cryp::Cryp) { - p.cr().modify(|w| w.set_algomode0(6)); - p.cr().modify(|w| w.set_algomode3(false)); + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(6)); + } + #[cfg(cryp_v2)] + { + p.cr().modify(|w| w.set_algomode0(6)); + p.cr().modify(|w| w.set_algomode3(false)); + } } } @@ -328,12 +392,14 @@ impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {} impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {} +#[cfg(cryp_v2)] ///AES-GCM Cipher Mode pub struct AesGcm<'c, const KEY_SIZE: usize> { iv: [u8; 16], key: &'c [u8; KEY_SIZE], } +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> { /// Constucts a new AES-GCM cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { @@ -344,6 +410,7 @@ impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> { } } +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { const BLOCK_SIZE: usize = AES_BLOCK_SIZE; @@ -412,18 +479,25 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } } +#[cfg(cryp_v2)] impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {} +#[cfg(cryp_v2)] impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {} +#[cfg(cryp_v2)] impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {} +#[cfg(cryp_v2)] /// AES-GMAC Cipher Mode pub struct AesGmac<'c, const KEY_SIZE: usize> { iv: [u8; 16], key: &'c [u8; KEY_SIZE], } +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> { /// Constructs a new AES-GMAC cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { @@ -434,6 +508,7 @@ impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> { } } +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { const BLOCK_SIZE: usize = AES_BLOCK_SIZE; @@ -502,12 +577,18 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } } +#[cfg(cryp_v2)] impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {} +#[cfg(cryp_v2)] impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {} +#[cfg(cryp_v2)] impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {} +#[cfg(cryp_v2)] /// AES-CCM Cipher Mode pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> { key: &'c [u8; KEY_SIZE], @@ -517,6 +598,7 @@ pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZ ctr: [u8; 16], } +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> { /// Constructs a new AES-CCM cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self { @@ -580,6 +662,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Aes } } +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> { @@ -672,24 +755,42 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } } +#[cfg(cryp_v2)] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {} +#[cfg(cryp_v2)] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {} +#[allow(dead_code)] /// Holds the state information for a cipher operation. /// Allows suspending/resuming of cipher operations. pub struct Context<'c, C: Cipher<'c> + CipherSized> { @@ -810,6 +911,7 @@ impl<'d, T: Instance> Cryp<'d, T> { ctx } + #[cfg(cryp_v2)] /// Controls the header phase of cipher processing. /// This function is only valid for GCM, CCM, and GMAC modes. /// It only needs to be called if using one of these modes and there is associated data. @@ -951,11 +1053,14 @@ impl<'d, T: Instance> Cryp<'d, T> { if !ctx.aad_complete && ctx.header_len > 0 { panic!("Additional associated data must be processed first!"); } else if !ctx.aad_complete { - ctx.aad_complete = true; - T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); - T::regs().cr().modify(|w| w.fflush()); - T::regs().cr().modify(|w| w.set_crypen(true)); + #[cfg(cryp_v2)] + { + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + T::regs().cr().modify(|w| w.set_crypen(true)); + } } if ctx.last_block_processed { panic!("The last block has already been processed!"); @@ -1044,6 +1149,7 @@ impl<'d, T: Instance> Cryp<'d, T> { self.store_context(ctx); } + #[cfg(cryp_v2)] /// This function only needs to be called for GCM, CCM, and GMAC modes to /// generate an authentication tag. pub fn finish_blocking< @@ -1137,6 +1243,8 @@ impl<'d, T: Instance> Cryp<'d, T> { ctx.iv[1] = T::regs().init(0).ivrr().read(); ctx.iv[2] = T::regs().init(1).ivlr().read(); ctx.iv[3] = T::regs().init(1).ivrr().read(); + + #[cfg(cryp_v2)] for i in 0..8 { ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read(); ctx.csgcm[i] = T::regs().csgcmr(i).read(); @@ -1150,6 +1258,8 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().init(0).ivrr().write_value(ctx.iv[1]); T::regs().init(1).ivlr().write_value(ctx.iv[2]); T::regs().init(1).ivrr().write_value(ctx.iv[3]); + + #[cfg(cryp_v2)] for i in 0..8 { T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]); T::regs().csgcmr(i).write_value(ctx.csgcm[i]); From bf4cbd75779b230e9e33a9d2a849f67335a68cf9 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Thu, 22 Feb 2024 15:47:36 -0500 Subject: [PATCH 573/760] Add CRYP example. --- examples/stm32f7/Cargo.toml | 1 + examples/stm32f7/src/bin/cryp.rs | 69 ++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 examples/stm32f7/src/bin/cryp.rs diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 736e81723..305816a2b 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -30,6 +30,7 @@ embedded-storage = "0.3.1" static_cell = "2" sha2 = { version = "0.10.8", default-features = false } hmac = "0.12.1" +aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } [profile.release] debug = 2 diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs new file mode 100644 index 000000000..c1b80ddc3 --- /dev/null +++ b/examples/stm32f7/src/bin/cryp.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +use aes_gcm::{ + aead::{heapless::Vec, AeadInPlace, KeyInit}, + Aes128Gcm, +}; +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::cryp::*; +use embassy_stm32::Config; +use embassy_time::Instant; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let config = Config::default(); + let p = embassy_stm32::init(config); + + let payload: &[u8] = b"hello world"; + let aad: &[u8] = b"additional data"; + + let hw_cryp = Cryp::new(p.CRYP); + let key: [u8; 16] = [0; 16]; + let mut ciphertext: [u8; 11] = [0; 11]; + let mut plaintext: [u8; 11] = [0; 11]; + let iv: [u8; 12] = [0; 12]; + + let hw_start_time = Instant::now(); + + // Encrypt in hardware using AES-GCM 128-bit + let aes_gcm = AesGcm::new(&key, &iv); + let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); + hw_cryp.aad_blocking(&mut gcm_encrypt, aad, true); + hw_cryp.payload_blocking(&mut gcm_encrypt, payload, &mut ciphertext, true); + let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); + + // Decrypt in hardware using AES-GCM 128-bit + let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); + hw_cryp.aad_blocking(&mut gcm_decrypt, aad, true); + hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); + let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); + + let hw_end_time = Instant::now(); + let hw_execution_time = hw_end_time - hw_start_time; + + info!("AES-GCM Ciphertext: {:?}", ciphertext); + info!("AES-GCM Plaintext: {:?}", plaintext); + assert_eq!(payload, plaintext); + assert_eq!(encrypt_tag, decrypt_tag); + + let sw_start_time = Instant::now(); + + //Encrypt in software using AES-GCM 128-bit + let mut payload_vec: Vec = Vec::from_slice(&payload).unwrap(); + let cipher = Aes128Gcm::new(&key.into()); + let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); + + //Decrypt in software using AES-GCM 128-bit + let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); + + let sw_end_time = Instant::now(); + let sw_execution_time = sw_end_time - sw_start_time; + + info!("Hardware Execution Time: {:?}", hw_execution_time); + info!("Software Execution Time: {:?}", sw_execution_time); + + loop {} +} From 967b4927b002dbcdcfbe968bf9c15014fc1de2a0 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Fri, 23 Feb 2024 16:05:18 -0500 Subject: [PATCH 574/760] Correct tag generation. --- embassy-stm32/src/cryp/mod.rs | 8 ++++---- examples/stm32f7/src/bin/cryp.rs | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 965e4a35d..038923870 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1166,10 +1166,10 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); T::regs().cr().modify(|w| w.set_crypen(true)); - let headerlen1: u32 = (ctx.header_len >> 32) as u32; - let headerlen2: u32 = ctx.header_len as u32; - let payloadlen1: u32 = (ctx.payload_len >> 32) as u32; - let payloadlen2: u32 = ctx.payload_len as u32; + let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32; + let headerlen2: u32 = (ctx.header_len * 8) as u32; + let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32; + let payloadlen2: u32 = (ctx.payload_len * 8) as u32; T::regs().din().write_value(headerlen1.swap_bytes()); T::regs().din().write_value(headerlen2.swap_bytes()); diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index c1b80ddc3..be41955c5 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -51,13 +51,16 @@ async fn main(_spawner: Spawner) -> ! { let sw_start_time = Instant::now(); - //Encrypt in software using AES-GCM 128-bit + // Encrypt in software using AES-GCM 128-bit let mut payload_vec: Vec = Vec::from_slice(&payload).unwrap(); let cipher = Aes128Gcm::new(&key.into()); let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); + + assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]); + assert_eq!(encrypt_tag, payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]); - //Decrypt in software using AES-GCM 128-bit - let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); + // Decrypt in software using AES-GCM 128-bit + let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); let sw_end_time = Instant::now(); let sw_execution_time = sw_end_time - sw_start_time; From 25ec838af597cc2e39c530b44f1a101c80b24260 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sat, 24 Feb 2024 15:55:20 -0500 Subject: [PATCH 575/760] Correct AAD ingest. --- embassy-stm32/src/cryp/mod.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 038923870..9d1a62905 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -988,7 +988,7 @@ impl<'d, T: Instance> Cryp<'d, T> { // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&aad[index..index + 4]); + in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); T::regs().din().write_value(u32::from_ne_bytes(in_word)); index += 4; } @@ -1000,14 +1000,16 @@ impl<'d, T: Instance> Cryp<'d, T> { ctx.aad_buffer_len = 0; let leftovers = aad_len_remaining % C::BLOCK_SIZE; ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]); + ctx.aad_buffer_len += leftovers; + ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); aad_len_remaining -= leftovers; assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0); // Load full data blocks into core. let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; - for _ in 0..num_full_blocks { - let mut index = len_to_copy; - let end_index = len_to_copy + C::BLOCK_SIZE; + for block in 0..num_full_blocks { + let mut index = len_to_copy + (block * C::BLOCK_SIZE); + let end_index = index + C::BLOCK_SIZE; // Write block in while index < end_index { let mut in_word: [u8; 4] = [0; 4]; @@ -1020,6 +1022,19 @@ impl<'d, T: Instance> Cryp<'d, T> { } if last_aad_block { + if leftovers > 0 { + let mut index = 0; + let end_index = C::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + } // Switch to payload phase. ctx.aad_complete = true; T::regs().cr().modify(|w| w.set_crypen(false)); @@ -1065,7 +1080,7 @@ impl<'d, T: Instance> Cryp<'d, T> { if ctx.last_block_processed { panic!("The last block has already been processed!"); } - if input.len() != output.len() { + if input.len() > output.len() { panic!("Output buffer length must match input length."); } if !last_block { From f352b6d68b17fee886af58494b7e793cea3ea383 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sat, 24 Feb 2024 16:14:44 -0500 Subject: [PATCH 576/760] Address CI build issues. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/cryp/mod.rs | 7 +++---- examples/stm32f7/src/bin/cryp.rs | 14 ++++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d585d2cd6..4c856141b 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-6097928f720646c73d6483a3245f922bd5faee2f" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ca48d946840840c5b311c96ff17cf4f8a865f9fb" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-6097928f720646c73d6483a3245f922bd5faee2f", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ca48d946840840c5b311c96ff17cf4f8a865f9fb", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 9d1a62905..fef5def6a 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -2,12 +2,11 @@ #[cfg(cryp_v2)] use core::cmp::min; use core::marker::PhantomData; + use embassy_hal_internal::{into_ref, PeripheralRef}; -use crate::pac; -use crate::peripherals::CRYP; use crate::rcc::sealed::RccPeripheral; -use crate::{interrupt, peripherals, Peripheral}; +use crate::{interrupt, pac, peripherals, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits @@ -827,7 +826,7 @@ pub struct Cryp<'d, T: Instance> { impl<'d, T: Instance> Cryp<'d, T> { /// Create a new CRYP driver. pub fn new(peri: impl Peripheral

+ 'd) -> Self { - CRYP::enable_and_reset(); + T::enable_and_reset(); into_ref!(peri); let instance = Self { _peripheral: peri }; instance diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index be41955c5..04927841a 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -1,10 +1,9 @@ #![no_std] #![no_main] -use aes_gcm::{ - aead::{heapless::Vec, AeadInPlace, KeyInit}, - Aes128Gcm, -}; +use aes_gcm::aead::heapless::Vec; +use aes_gcm::aead::{AeadInPlace, KeyInit}; +use aes_gcm::Aes128Gcm; use defmt::info; use embassy_executor::Spawner; use embassy_stm32::cryp::*; @@ -55,9 +54,12 @@ async fn main(_spawner: Spawner) -> ! { let mut payload_vec: Vec = Vec::from_slice(&payload).unwrap(); let cipher = Aes128Gcm::new(&key.into()); let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); - + assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]); - assert_eq!(encrypt_tag, payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]); + assert_eq!( + encrypt_tag, + payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()] + ); // Decrypt in software using AES-GCM 128-bit let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); From 236fc6f650af41980af05ef03a3901b2dfcfc381 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sat, 24 Feb 2024 16:31:43 -0500 Subject: [PATCH 577/760] Add CRYP test. --- embassy-stm32/src/cryp/mod.rs | 1 - tests/stm32/Cargo.toml | 11 +++++- tests/stm32/src/bin/cryp.rs | 71 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 tests/stm32/src/bin/cryp.rs diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index fef5def6a..bb64fa423 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -5,7 +5,6 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; -use crate::rcc::sealed::RccPeripheral; use crate::{interrupt, pac, peripherals, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 828a28e2c..37519ba11 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -16,8 +16,8 @@ stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] -stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash"] -stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash"] +stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] +stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] @@ -33,6 +33,7 @@ stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] stm32h503rb = ["embassy-stm32/stm32h503rb", "rng"] +cryp = [] hash = [] eth = ["embassy-executor/task-arena-size-16384"] rng = [] @@ -80,6 +81,7 @@ portable-atomic = { version = "1.5", features = [] } chrono = { version = "^0.4", default-features = false, optional = true} sha2 = { version = "0.10.8", default-features = false } hmac = "0.12.1" +aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } # BEGIN TESTS # Generated by gen_test.py. DO NOT EDIT. @@ -88,6 +90,11 @@ name = "can" path = "src/bin/can.rs" required-features = [ "can",] +[[bin]] +name = "cryp" +path = "src/bin/cryp.rs" +required-features = [ "hash",] + [[bin]] name = "dac" path = "src/bin/dac.rs" diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs new file mode 100644 index 000000000..59c85f258 --- /dev/null +++ b/tests/stm32/src/bin/cryp.rs @@ -0,0 +1,71 @@ +// required-features: cryp +#![no_std] +#![no_main] + +#[path = "../common.rs"] +mod common; + +use aes_gcm::aead::heapless::Vec; +use aes_gcm::aead::{AeadInPlace, KeyInit}; +use aes_gcm::Aes128Gcm; +use common::*; +use embassy_executor::Spawner; +use embassy_stm32::cryp::*; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); + + const PAYLOAD1: &[u8] = b"payload data 1 ;zdfhzdfhS;GKJASBDG;ASKDJBAL,zdfhzdfhzdfhzdfhvljhb,jhbjhb,sdhsdghsdhsfhsghzdfhzdfhzdfhzdfdhsdthsthsdhsgaadfhhgkdgfuoyguoft6783567"; + const PAYLOAD2: &[u8] = b"payload data 2 ;SKEzdfhzdfhzbhgvljhb,jhbjhb,sdhsdghsdhsfhsghshsfhshstsdthadfhsdfjhsfgjsfgjxfgjzdhgDFghSDGHjtfjtjszftjzsdtjhstdsdhsdhsdhsdhsdthsthsdhsgfh"; + const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1"; + const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg"; + + let hw_cryp = Cryp::new(p.CRYP); + let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; + let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; + let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + + // Encrypt in hardware using AES-GCM 128-bit + let aes_gcm = AesGcm::new(&key, &iv); + let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); + hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false); + hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true); + hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false); + hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true); + let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); + + // Decrypt in hardware using AES-GCM 128-bit + let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); + hw_cryp.aad_blocking(&mut gcm_decrypt, AAD1, false); + hw_cryp.aad_blocking(&mut gcm_decrypt, AAD2, true); + hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); + let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); + + info!("AES-GCM Ciphertext: {:?}", ciphertext); + info!("AES-GCM Plaintext: {:?}", plaintext); + defmt::assert!(PAYLOAD1 == &plaintext[..PAYLOAD1.len()]); + defmt::assert!(PAYLOAD2 == &plaintext[PAYLOAD1.len()..]); + defmt::assert!(encrypt_tag == decrypt_tag); + + // Encrypt in software using AES-GCM 128-bit + let mut payload_vec: Vec = Vec::from_slice(&PAYLOAD1).unwrap(); + payload_vec.extend_from_slice(&PAYLOAD2).unwrap(); + let cipher = Aes128Gcm::new(&key.into()); + let mut aad: Vec = Vec::from_slice(&AAD1).unwrap(); + aad.extend_from_slice(&AAD2).unwrap(); + let _ = cipher.encrypt_in_place(&iv.into(), &aad, &mut payload_vec); + + defmt::assert!(ciphertext == payload_vec[0..ciphertext.len()]); + defmt::assert!( + encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()] + ); + + // Decrypt in software using AES-GCM 128-bit + let _ = cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From d9c0da8102226cebc36c92b874b8f0bf966ac959 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 25 Feb 2024 20:58:35 -0500 Subject: [PATCH 578/760] Update metapac to address CI build issue. --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4c856141b..e0bee6a92 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-ca48d946840840c5b311c96ff17cf4f8a865f9fb" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-88f71cbcd2f048c40bad162c7e7864cc3897eba4" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-ca48d946840840c5b311c96ff17cf4f8a865f9fb", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-88f71cbcd2f048c40bad162c7e7864cc3897eba4", default-features = false, features = ["metadata"]} [features] From 72c6f9a101141183fb2de46c2fe40aa979330d9c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 26 Feb 2024 02:58:03 +0100 Subject: [PATCH 579/760] stm32/adc: reexport enums from PAC to avoid boilerplate hell. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/adc/f1.rs | 18 ++-- embassy-stm32/src/adc/f3.rs | 16 +-- embassy-stm32/src/adc/f3_v1_1.rs | 51 +++++---- embassy-stm32/src/adc/mod.rs | 35 +++++-- embassy-stm32/src/adc/resolution.rs | 72 ------------- embassy-stm32/src/adc/sample_time.rs | 148 --------------------------- embassy-stm32/src/adc/v1.rs | 2 +- embassy-stm32/src/adc/v2.rs | 2 +- embassy-stm32/src/adc/v3.rs | 6 +- embassy-stm32/src/adc/v4.rs | 2 +- examples/stm32f0/src/bin/adc.rs | 2 +- examples/stm32f334/src/bin/adc.rs | 2 +- examples/stm32f334/src/bin/opamp.rs | 2 +- examples/stm32g4/src/bin/adc.rs | 2 +- examples/stm32h7/src/bin/adc.rs | 2 +- examples/stm32l0/src/bin/adc.rs | 2 +- examples/stm32l4/src/bin/adc.rs | 2 +- 18 files changed, 82 insertions(+), 288 deletions(-) delete mode 100644 embassy-stm32/src/adc/resolution.rs delete mode 100644 embassy-stm32/src/adc/sample_time.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index e0bee6a92..7d21383c3 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-88f71cbcd2f048c40bad162c7e7864cc3897eba4" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7c8b53413499acc3273b706318777a60f932d77a" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-88f71cbcd2f048c40bad162c7e7864cc3897eba4", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7c8b53413499acc3273b706318777a60f932d77a", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index c896d8e3a..b27b99827 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -74,7 +74,7 @@ impl<'d, T: Instance> Adc<'d, T> { Self { adc, - sample_time: Default::default(), + sample_time: SampleTime::from_bits(0), } } @@ -84,14 +84,14 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn sample_time_for_us(&self, us: u32) -> SampleTime { match us * Self::freq().0 / 1_000_000 { - 0..=1 => SampleTime::Cycles1_5, - 2..=7 => SampleTime::Cycles7_5, - 8..=13 => SampleTime::Cycles13_5, - 14..=28 => SampleTime::Cycles28_5, - 29..=41 => SampleTime::Cycles41_5, - 42..=55 => SampleTime::Cycles55_5, - 56..=71 => SampleTime::Cycles71_5, - _ => SampleTime::Cycles239_5, + 0..=1 => SampleTime::CYCLES1_5, + 2..=7 => SampleTime::CYCLES7_5, + 8..=13 => SampleTime::CYCLES13_5, + 14..=28 => SampleTime::CYCLES28_5, + 29..=41 => SampleTime::CYCLES41_5, + 42..=55 => SampleTime::CYCLES55_5, + 56..=71 => SampleTime::CYCLES71_5, + _ => SampleTime::CYCLES239_5, } } diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 6606a2b9c..efade1f64 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -97,7 +97,7 @@ impl<'d, T: Instance> Adc<'d, T> { Self { adc, - sample_time: Default::default(), + sample_time: SampleTime::from_bits(0), } } @@ -107,13 +107,13 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn sample_time_for_us(&self, us: u32) -> SampleTime { match us * Self::freq().0 / 1_000_000 { - 0..=1 => SampleTime::Cycles1_5, - 2..=4 => SampleTime::Cycles4_5, - 5..=7 => SampleTime::Cycles7_5, - 8..=19 => SampleTime::Cycles19_5, - 20..=61 => SampleTime::Cycles61_5, - 62..=181 => SampleTime::Cycles181_5, - _ => SampleTime::Cycles601_5, + 0..=1 => SampleTime::CYCLES1_5, + 2..=4 => SampleTime::CYCLES4_5, + 5..=7 => SampleTime::CYCLES7_5, + 8..=19 => SampleTime::CYCLES19_5, + 20..=61 => SampleTime::CYCLES61_5, + 62..=181 => SampleTime::CYCLES181_5, + _ => SampleTime::CYCLES601_5, } } diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index 6915a8f1c..f842893fa 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -107,12 +107,12 @@ impl Calibration { /// Returns a calibrated voltage value as in microvolts (uV) pub fn cal_uv(&self, raw: u16, resolution: super::Resolution) -> u32 { - (self.vdda_uv() / resolution.to_max_count()) * raw as u32 + (self.vdda_uv() / super::resolution_to_max_count(resolution)) * raw as u32 } /// Returns a calibrated voltage value as an f32 pub fn cal_f32(&self, raw: u16, resolution: super::Resolution) -> f32 { - raw as f32 * self.vdda_f32() / resolution.to_max_count() as f32 + raw as f32 * self.vdda_f32() / super::resolution_to_max_count(resolution) as f32 } } @@ -175,12 +175,7 @@ impl<'d, T: Instance> Adc<'d, T> { } pub fn resolution(&self) -> Resolution { - match T::regs().cr1().read().res() { - crate::pac::adc::vals::Res::TWELVEBIT => Resolution::TwelveBit, - crate::pac::adc::vals::Res::TENBIT => Resolution::TenBit, - crate::pac::adc::vals::Res::EIGHTBIT => Resolution::EightBit, - crate::pac::adc::vals::Res::SIXBIT => Resolution::SixBit, - } + T::regs().cr1().read().res() } pub fn enable_vref(&self) -> Vref { @@ -359,23 +354,23 @@ impl<'d, T: Instance> Adc<'d, T> { fn get_res_clks(res: Resolution) -> u32 { match res { - Resolution::TwelveBit => 12, - Resolution::TenBit => 11, - Resolution::EightBit => 9, - Resolution::SixBit => 7, + Resolution::BITS12 => 12, + Resolution::BITS10 => 11, + Resolution::BITS8 => 9, + Resolution::BITS6 => 7, } } fn get_sample_time_clks(sample_time: SampleTime) -> u32 { match sample_time { - SampleTime::Cycles4 => 4, - SampleTime::Cycles9 => 9, - SampleTime::Cycles16 => 16, - SampleTime::Cycles24 => 24, - SampleTime::Cycles48 => 48, - SampleTime::Cycles96 => 96, - SampleTime::Cycles192 => 192, - SampleTime::Cycles384 => 384, + SampleTime::CYCLES4 => 4, + SampleTime::CYCLES9 => 9, + SampleTime::CYCLES16 => 16, + SampleTime::CYCLES24 => 24, + SampleTime::CYCLES48 => 48, + SampleTime::CYCLES96 => 96, + SampleTime::CYCLES192 => 192, + SampleTime::CYCLES384 => 384, } } @@ -384,14 +379,14 @@ impl<'d, T: Instance> Adc<'d, T> { let us_clks = us * Self::freq().0 / 1_000_000; let clks = us_clks.saturating_sub(res_clks); match clks { - 0..=4 => SampleTime::Cycles4, - 5..=9 => SampleTime::Cycles9, - 10..=16 => SampleTime::Cycles16, - 17..=24 => SampleTime::Cycles24, - 25..=48 => SampleTime::Cycles48, - 49..=96 => SampleTime::Cycles96, - 97..=192 => SampleTime::Cycles192, - 193.. => SampleTime::Cycles384, + 0..=4 => SampleTime::CYCLES4, + 5..=9 => SampleTime::CYCLES9, + 10..=16 => SampleTime::CYCLES16, + 17..=24 => SampleTime::CYCLES24, + 25..=48 => SampleTime::CYCLES48, + 49..=96 => SampleTime::CYCLES96, + 97..=192 => SampleTime::CYCLES192, + 193.. => SampleTime::CYCLES384, } } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index b273c6394..0d0d40549 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -14,18 +14,13 @@ #[cfg_attr(adc_v4, path = "v4.rs")] mod _version; -#[cfg(not(any(adc_f1, adc_f3_v2)))] -mod resolution; -mod sample_time; - #[allow(unused)] #[cfg(not(adc_f3_v2))] pub use _version::*; -#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] -pub use resolution::Resolution; -#[cfg(not(adc_f3_v2))] -pub use sample_time::SampleTime; +#[cfg(not(any(adc_f1, adc_f3_v2)))] +pub use crate::pac::adc::vals::Res as Resolution; +pub use crate::pac::adc::vals::SampleTime; use crate::peripherals; /// Analog to Digital driver. @@ -137,3 +132,27 @@ macro_rules! impl_adc_pin { } }; } + +/// Get the maximum reading value for this resolution. +/// +/// This is `2**n - 1`. +#[cfg(not(any(adc_f1, adc_f3_v2)))] +pub const fn resolution_to_max_count(res: Resolution) -> u32 { + match res { + #[cfg(adc_v4)] + Resolution::BITS16 => (1 << 16) - 1, + #[cfg(adc_v4)] + Resolution::BITS14 => (1 << 14) - 1, + #[cfg(adc_v4)] + Resolution::BITS14V => (1 << 14) - 1, + #[cfg(adc_v4)] + Resolution::BITS12V => (1 << 12) - 1, + Resolution::BITS12 => (1 << 12) - 1, + Resolution::BITS10 => (1 << 10) - 1, + Resolution::BITS8 => (1 << 8) - 1, + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] + Resolution::BITS6 => (1 << 6) - 1, + #[allow(unreachable_patterns)] + _ => core::unreachable!(), + } +} diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs deleted file mode 100644 index 37788cd77..000000000 --- a/embassy-stm32/src/adc/resolution.rs +++ /dev/null @@ -1,72 +0,0 @@ -/// ADC resolution -#[allow(missing_docs)] -#[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Resolution { - TwelveBit, - TenBit, - EightBit, - SixBit, -} - -/// ADC resolution -#[allow(missing_docs)] -#[cfg(adc_v4)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Resolution { - SixteenBit, - FourteenBit, - TwelveBit, - TenBit, - EightBit, -} - -impl Default for Resolution { - fn default() -> Self { - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] - { - Self::TwelveBit - } - #[cfg(adc_v4)] - { - Self::SixteenBit - } - } -} - -impl From for crate::pac::adc::vals::Res { - fn from(res: Resolution) -> crate::pac::adc::vals::Res { - match res { - #[cfg(adc_v4)] - Resolution::SixteenBit => crate::pac::adc::vals::Res::SIXTEENBIT, - #[cfg(adc_v4)] - Resolution::FourteenBit => crate::pac::adc::vals::Res::FOURTEENBITV, - Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, - Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, - Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] - Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, - } - } -} - -impl Resolution { - /// Get the maximum reading value for this resolution. - /// - /// This is `2**n - 1`. - pub const fn to_max_count(&self) -> u32 { - match self { - #[cfg(adc_v4)] - Resolution::SixteenBit => (1 << 16) - 1, - #[cfg(adc_v4)] - Resolution::FourteenBit => (1 << 14) - 1, - Resolution::TwelveBit => (1 << 12) - 1, - Resolution::TenBit => (1 << 10) - 1, - Resolution::EightBit => (1 << 8) - 1, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] - Resolution::SixBit => (1 << 6) - 1, - } - } -} diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs deleted file mode 100644 index 19bc22938..000000000 --- a/embassy-stm32/src/adc/sample_time.rs +++ /dev/null @@ -1,148 +0,0 @@ -#[cfg(not(adc_f3_v2))] -macro_rules! impl_sample_time { - ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { - #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum SampleTime { - $( - #[doc = concat!($doc, " ADC clock cycles.")] - $variant, - )* - } - - impl From for crate::pac::adc::vals::SampleTime { - fn from(sample_time: SampleTime) -> crate::pac::adc::vals::SampleTime { - match sample_time { - $(SampleTime::$variant => crate::pac::adc::vals::SampleTime::$pac_variant),* - } - } - } - - impl From for SampleTime { - fn from(sample_time: crate::pac::adc::vals::SampleTime) -> SampleTime { - match sample_time { - $(crate::pac::adc::vals::SampleTime::$pac_variant => SampleTime::$variant),* - } - } - } - - impl Default for SampleTime { - fn default() -> Self { - Self::$default - } - } - }; -} - -#[cfg(any(adc_f1, adc_v1))] -impl_sample_time!( - "1.5", - Cycles1_5, - ( - ("1.5", Cycles1_5, CYCLES1_5), - ("7.5", Cycles7_5, CYCLES7_5), - ("13.5", Cycles13_5, CYCLES13_5), - ("28.5", Cycles28_5, CYCLES28_5), - ("41.5", Cycles41_5, CYCLES41_5), - ("55.5", Cycles55_5, CYCLES55_5), - ("71.5", Cycles71_5, CYCLES71_5), - ("239.5", Cycles239_5, CYCLES239_5) - ) -); - -#[cfg(adc_v2)] -impl_sample_time!( - "3", - Cycles3, - ( - ("3", Cycles3, CYCLES3), - ("15", Cycles15, CYCLES15), - ("28", Cycles28, CYCLES28), - ("56", Cycles56, CYCLES56), - ("84", Cycles84, CYCLES84), - ("112", Cycles112, CYCLES112), - ("144", Cycles144, CYCLES144), - ("480", Cycles480, CYCLES480) - ) -); - -#[cfg(any(adc_v3, adc_h5))] -impl_sample_time!( - "2.5", - Cycles2_5, - ( - ("2.5", Cycles2_5, CYCLES2_5), - ("6.5", Cycles6_5, CYCLES6_5), - ("12.5", Cycles12_5, CYCLES12_5), - ("24.5", Cycles24_5, CYCLES24_5), - ("47.5", Cycles47_5, CYCLES47_5), - ("92.5", Cycles92_5, CYCLES92_5), - ("247.5", Cycles247_5, CYCLES247_5), - ("640.5", Cycles640_5, CYCLES640_5) - ) -); - -#[cfg(any(adc_l0, adc_g0))] -impl_sample_time!( - "1.5", - Cycles1_5, - ( - ("1.5", Cycles1_5, CYCLES1_5), - ("3.5", Cycles3_5, CYCLES3_5), - ("7.5", Cycles7_5, CYCLES7_5), - ("12.5", Cycles12_5, CYCLES12_5), - ("19.5", Cycles19_5, CYCLES19_5), - ("39.5", Cycles39_5, CYCLES39_5), - ("79.5", Cycles79_5, CYCLES79_5), - ("160.5", Cycles160_5, CYCLES160_5) - ) -); - -#[cfg(adc_v4)] -impl_sample_time!( - "1.5", - Cycles1_5, - ( - ("1.5", Cycles1_5, CYCLES1_5), - ("2.5", Cycles2_5, CYCLES2_5), - ("8.5", Cycles8_5, CYCLES8_5), - ("16.5", Cycles16_5, CYCLES16_5), - ("32.5", Cycles32_5, CYCLES32_5), - ("64.5", Cycles64_5, CYCLES64_5), - ("387.5", Cycles387_5, CYCLES387_5), - ("810.5", Cycles810_5, CYCLES810_5) - ) -); - -#[cfg(adc_f3)] -impl_sample_time!( - "1.5", - Cycles1_5, - ( - ("1.5", Cycles1_5, CYCLES1_5), - ("2.5", Cycles2_5, CYCLES2_5), - ("4.5", Cycles4_5, CYCLES4_5), - ("7.5", Cycles7_5, CYCLES7_5), - ("19.5", Cycles19_5, CYCLES19_5), - ("61.5", Cycles61_5, CYCLES61_5), - ("181.5", Cycles181_5, CYCLES181_5), - ("601.5", Cycles601_5, CYCLES601_5) - ) -); - -#[cfg(any(adc_f3_v1_1))] -impl_sample_time!( - "4", - Cycles4, - ( - ("4", Cycles4, CYCLES4), - ("9", Cycles9, CYCLES9), - ("16", Cycles16, CYCLES16), - ("24", Cycles24, CYCLES24), - ("48", Cycles48, CYCLES48), - ("96", Cycles96, CYCLES96), - ("192", Cycles192, CYCLES192), - ("384", Cycles384, CYCLES384) - ) -); diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 37115dfab..a8dc6ce98 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -109,7 +109,7 @@ impl<'d, T: Instance> Adc<'d, T> { Self { adc, - sample_time: Default::default(), + sample_time: SampleTime::from_bits(0), } } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index b37ac5a5d..f6f7dbfcc 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -111,7 +111,7 @@ where Self { adc, - sample_time: Default::default(), + sample_time: SampleTime::from_bits(0), } } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 0c44e4400..5f3512cad 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -102,7 +102,7 @@ impl<'d, T: Instance> Adc<'d, T> { Self { adc, - sample_time: Default::default(), + sample_time: SampleTime::from_bits(0), } } @@ -259,8 +259,8 @@ impl<'d, T: Instance> Adc<'d, T> { } else { let sample_time = sample_time.into(); T::regs() - .smpr(ch as usize / 10) - .modify(|reg| reg.set_smp(ch as usize % 10, sample_time)); + .smpr(_ch as usize / 10) + .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time)); } } } diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 048e73184..3fd047375 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -159,7 +159,7 @@ impl<'d, T: Instance> Adc<'d, T> { } let mut s = Self { adc, - sample_time: Default::default(), + sample_time: SampleTime::from_bits(0), }; s.power_up(delay); s.configure_differential_inputs(); diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 8fef062b3..c2fb143cd 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -19,7 +19,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); - adc.set_sample_time(SampleTime::Cycles71_5); + adc.set_sample_time(SampleTime::CYCLES71_5); let mut pin = p.PA1; let mut vrefint = adc.enable_vref(&mut Delay); diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index a9fb7f1a6..bd126ce68 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) -> ! { let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); - adc.set_sample_time(SampleTime::Cycles601_5); + adc.set_sample_time(SampleTime::CYCLES601_5); info!("enable vrefint..."); diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 6f25191be..a5c710aa2 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -42,7 +42,7 @@ async fn main(_spawner: Spawner) -> ! { let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); let mut opamp = OpAmp::new(p.OPAMP2); - adc.set_sample_time(SampleTime::Cycles601_5); + adc.set_sample_time(SampleTime::CYCLES601_5); info!("enable vrefint..."); diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 99e3ef63b..6c6de1ffe 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC2, &mut Delay); - adc.set_sample_time(SampleTime::Cycles32_5); + adc.set_sample_time(SampleTime::CYCLES32_5); loop { let measured = adc.read(&mut p.PA7); diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index fe6fe69a1..f0278239f 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) { let mut adc = Adc::new(p.ADC3, &mut Delay); - adc.set_sample_time(SampleTime::Cycles32_5); + adc.set_sample_time(SampleTime::CYCLES32_5); let mut vrefint_channel = adc.enable_vrefint(); diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index adeaa208a..97d41ca4b 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -19,7 +19,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); - adc.set_sample_time(SampleTime::Cycles79_5); + adc.set_sample_time(SampleTime::CYCLES79_5); let mut pin = p.PA1; let mut vrefint = adc.enable_vref(&mut Delay); diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index d01e9f1b3..910944673 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -20,7 +20,7 @@ fn main() -> ! { let mut adc = Adc::new(p.ADC1, &mut Delay); //adc.enable_vref(); - adc.set_resolution(Resolution::EightBit); + adc.set_resolution(Resolution::BITS8); let mut channel = p.PC0; loop { From c83ab20526c0812d738853db015e201120ecce44 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 26 Feb 2024 03:00:04 +0100 Subject: [PATCH 580/760] stm32: update metapac. --- embassy-stm32/src/fmc.rs | 8 +++-- embassy-stm32/src/i2s.rs | 16 +++++----- embassy-stm32/src/lib.rs | 5 +++ embassy-stm32/src/rcc/f013.rs | 1 + embassy-stm32/src/rcc/f247.rs | 1 + embassy-stm32/src/rcc/g0.rs | 1 + embassy-stm32/src/rcc/h.rs | 1 + embassy-stm32/src/rcc/u5.rs | 2 ++ embassy-stm32/src/sai/mod.rs | 58 ++++++++++++++++++++--------------- embassy-stm32/src/spi/mod.rs | 30 +++++++++--------- 10 files changed, 73 insertions(+), 50 deletions(-) diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 873c8a70c..9d731a512 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -36,8 +36,10 @@ where // fmc v1 and v2 does not have the fmcen bit // fsmc v1, v2 and v3 does not have the fmcen bit // This is a "not" because it is expected that all future versions have this bit - #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] + #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))] T::REGS.bcr1().modify(|r| r.set_fmcen(true)); + #[cfg(any(fmc_v4))] + T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true)); } /// Get the kernel clock currently in use for this FMC instance. @@ -60,8 +62,10 @@ where // fmc v1 and v2 does not have the fmcen bit // fsmc v1, v2 and v3 does not have the fmcen bit // This is a "not" because it is expected that all future versions have this bit - #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] + #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))] T::REGS.bcr1().modify(|r| r.set_fmcen(true)); + #[cfg(any(fmc_v4))] + T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true)); } fn source_clock_hz(&self) -> u32 { diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index e9065dce6..fa9ec0532 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -79,20 +79,20 @@ impl Format { #[cfg(any(spi_v1, spi_f1))] const fn datlen(&self) -> vals::Datlen { match self { - Format::Data16Channel16 => vals::Datlen::SIXTEENBIT, - Format::Data16Channel32 => vals::Datlen::SIXTEENBIT, - Format::Data24Channel32 => vals::Datlen::TWENTYFOURBIT, - Format::Data32Channel32 => vals::Datlen::THIRTYTWOBIT, + Format::Data16Channel16 => vals::Datlen::BITS16, + Format::Data16Channel32 => vals::Datlen::BITS16, + Format::Data24Channel32 => vals::Datlen::BITS24, + Format::Data32Channel32 => vals::Datlen::BITS32, } } #[cfg(any(spi_v1, spi_f1))] const fn chlen(&self) -> vals::Chlen { match self { - Format::Data16Channel16 => vals::Chlen::SIXTEENBIT, - Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT, - Format::Data24Channel32 => vals::Chlen::THIRTYTWOBIT, - Format::Data32Channel32 => vals::Chlen::THIRTYTWOBIT, + Format::Data16Channel16 => vals::Chlen::BITS16, + Format::Data16Channel32 => vals::Chlen::BITS32, + Format::Data24Channel32 => vals::Chlen::BITS32, + Format::Data32Channel32 => vals::Chlen::BITS32, } } } diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index cd1ede0fa..15798e115 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -216,6 +216,11 @@ pub fn init(config: Config) -> Peripherals { #[cfg(dbgmcu)] crate::pac::DBGMCU.cr().modify(|cr| { + #[cfg(any(dbgmcu_h5))] + { + cr.set_stop(config.enable_debug_during_sleep); + cr.set_standby(config.enable_debug_during_sleep); + } #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))] { cr.set_dbg_stop(config.enable_debug_during_sleep); diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 56bb2a0d9..5046f0a3a 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -379,6 +379,7 @@ pub(crate) unsafe fn init(config: Config) { pll1_p: pll, #[cfg(stm32f3)] pll1_p_mul_2: pll_mul_2, + hsi_div_244: hsi.map(|h| h / 244u32), sys: Some(sys), pclk1: Some(pclk1), pclk2: Some(pclk2), diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index e306d478d..343d075cd 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -288,6 +288,7 @@ pub(crate) unsafe fn init(config: Config) { clk48: pll.q, + hsi_div488: hsi.map(|hsi| hsi/488u32), hsi_hse: None, afif: None, ); diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 0b1f34a20..ae502dd9c 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -365,5 +365,6 @@ pub(crate) unsafe fn init(config: Config) { pll1_q: pll1_q_freq, pll1_p: pll1_p_freq, rtc: rtc, + hsi_div_488: None, ); } diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index c2a71eaf1..c6da79afb 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -617,6 +617,7 @@ pub(crate) unsafe fn init(config: Config) { hsi: hsi, hsi48: hsi48, csi: csi, + csi_div_122: csi.map(|c| c / 122u32), hse: hse, lse: None, diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 43138f05c..c8814ed69 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -290,6 +290,8 @@ pub(crate) unsafe fn init(config: Config) { lsi: None, msik: None, iclk: None, + shsi: None, + shsi_div_2: None, ); } diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index b6c3e4028..02f96f8a9 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1,5 +1,6 @@ //! Serial Audio Interface (SAI) #![macro_use] +#![cfg_attr(gpdma, allow(unused))] use core::marker::PhantomData; @@ -7,6 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use self::sealed::WhichSubBlock; pub use crate::dma::word; +#[cfg(not(gpdma))] use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; use crate::gpio::sealed::{AFType, Pin as _}; use crate::gpio::AnyPin; @@ -26,6 +28,7 @@ pub enum Error { Overrun, } +#[cfg(not(gpdma))] impl From for Error { fn from(_: ringbuffer::OverrunError) -> Self { Self::Overrun @@ -41,7 +44,7 @@ pub enum Mode { } impl Mode { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn mode(&self, tx_rx: TxRx) -> vals::Mode { match tx_rx { TxRx::Transmitter => match self { @@ -76,7 +79,7 @@ pub enum SlotSize { } impl SlotSize { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn slotsz(&self) -> vals::Slotsz { match self { SlotSize::DataSize => vals::Slotsz::DATASIZE, @@ -99,7 +102,7 @@ pub enum DataSize { } impl DataSize { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn ds(&self) -> vals::Ds { match self { DataSize::Data8 => vals::Ds::BIT8, @@ -124,7 +127,7 @@ pub enum FifoThreshold { } impl FifoThreshold { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn fth(&self) -> vals::Fth { match self { FifoThreshold::Empty => vals::Fth::EMPTY, @@ -145,7 +148,7 @@ pub enum MuteValue { } impl MuteValue { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn muteval(&self) -> vals::Muteval { match self { MuteValue::Zero => vals::Muteval::SENDZERO, @@ -164,7 +167,7 @@ pub enum Protocol { } impl Protocol { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn prtcfg(&self) -> vals::Prtcfg { match self { Protocol::Free => vals::Prtcfg::FREE, @@ -183,7 +186,7 @@ pub enum SyncInput { /// Syncs with the other A/B sub-block within the SAI unit Internal, /// Syncs with a sub-block in the other SAI unit - #[cfg(sai_v4)] + #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] External(SyncInputInstance), } @@ -192,14 +195,14 @@ impl SyncInput { match self { SyncInput::None => vals::Syncen::ASYNCHRONOUS, SyncInput::Internal => vals::Syncen::INTERNAL, - #[cfg(any(sai_v4))] + #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] SyncInput::External(_) => vals::Syncen::EXTERNAL, } } } /// SAI instance to sync from. -#[cfg(sai_v4)] +#[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] #[derive(Copy, Clone, PartialEq)] #[allow(missing_docs)] pub enum SyncInputInstance { @@ -222,7 +225,7 @@ pub enum StereoMono { } impl StereoMono { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn mono(&self) -> vals::Mono { match self { StereoMono::Stereo => vals::Mono::STEREO, @@ -241,7 +244,7 @@ pub enum BitOrder { } impl BitOrder { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn lsbfirst(&self) -> vals::Lsbfirst { match self { BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, @@ -260,7 +263,7 @@ pub enum FrameSyncOffset { } impl FrameSyncOffset { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn fsoff(&self) -> vals::Fsoff { match self { FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, @@ -279,7 +282,7 @@ pub enum FrameSyncPolarity { } impl FrameSyncPolarity { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn fspol(&self) -> vals::Fspol { match self { FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, @@ -297,7 +300,7 @@ pub enum FrameSyncDefinition { } impl FrameSyncDefinition { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn fsdef(&self) -> bool { match self { FrameSyncDefinition::StartOfFrame => false, @@ -315,7 +318,7 @@ pub enum ClockStrobe { } impl ClockStrobe { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn ckstr(&self) -> vals::Ckstr { match self { ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, @@ -333,7 +336,7 @@ pub enum ComplementFormat { } impl ComplementFormat { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn cpl(&self) -> vals::Cpl { match self { ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, @@ -352,7 +355,7 @@ pub enum Companding { } impl Companding { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn comp(&self) -> vals::Comp { match self { Companding::None => vals::Comp::NOCOMPANDING, @@ -371,7 +374,7 @@ pub enum OutputDrive { } impl OutputDrive { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn outdriv(&self) -> vals::Outdriv { match self { OutputDrive::OnStart => vals::Outdriv::ONSTART, @@ -404,7 +407,7 @@ pub enum MasterClockDivider { } impl MasterClockDivider { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn mckdiv(&self) -> u8 { match self { MasterClockDivider::MasterClockDisabled => 0, @@ -501,12 +504,12 @@ impl Config { } } +#[cfg(not(gpdma))] enum RingBuffer<'d, W: word::Word> { Writable(WritableRingBuffer<'d, W>), Readable(ReadableRingBuffer<'d, W>), } -#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] fn dr(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W { let ch = w.ch(sub_block as usize); ch.dr().as_ptr() as _ @@ -528,6 +531,7 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { ) } +#[cfg(not(gpdma))] fn get_ring_buffer<'d, T: Instance, W: word::Word>( dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], @@ -554,12 +558,12 @@ fn update_synchronous_config(config: &mut Config) { config.mode = Mode::Slave; config.sync_output = false; - #[cfg(any(sai_v1, sai_v2, sai_v3))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm))] { config.sync_input = SyncInput::Internal; } - #[cfg(any(sai_v4))] + #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] { //this must either be Internal or External //The asynchronous sub-block on the same SAI needs to enable sync_output @@ -599,10 +603,14 @@ pub struct Sai<'d, T: Instance, W: word::Word> { fs: Option>, sck: Option>, mclk: Option>, + #[cfg(gpdma)] + ring_buffer: PhantomData, + #[cfg(not(gpdma))] ring_buffer: RingBuffer<'d, W>, sub_block: WhichSubBlock, } +#[cfg(not(gpdma))] impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// Create a new SAI driver in asynchronous mode with MCLK. /// @@ -715,13 +723,13 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { ring_buffer: RingBuffer<'d, W>, config: Config, ) -> Self { - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] { let ch = T::REGS.ch(sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); } - #[cfg(any(sai_v4))] + #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] { if let SyncInput::External(i) = config.sync_input { T::REGS.gcr().modify(|w| { @@ -740,7 +748,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { } } - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] { let ch = T::REGS.ch(sub_block as usize); ch.cr1().modify(|w| { diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 23f027e70..172bc8112 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -1005,8 +1005,8 @@ mod word_impl { pub type Config = vals::Dff; - impl_word!(u8, vals::Dff::EIGHTBIT); - impl_word!(u16, vals::Dff::SIXTEENBIT); + impl_word!(u8, vals::Dff::BITS8); + impl_word!(u16, vals::Dff::BITS16); } #[cfg(spi_v2)] @@ -1015,19 +1015,19 @@ mod word_impl { pub type Config = (vals::Ds, vals::Frxth); - impl_word!(word::U4, (vals::Ds::FOURBIT, vals::Frxth::QUARTER)); - impl_word!(word::U5, (vals::Ds::FIVEBIT, vals::Frxth::QUARTER)); - impl_word!(word::U6, (vals::Ds::SIXBIT, vals::Frxth::QUARTER)); - impl_word!(word::U7, (vals::Ds::SEVENBIT, vals::Frxth::QUARTER)); - impl_word!(u8, (vals::Ds::EIGHTBIT, vals::Frxth::QUARTER)); - impl_word!(word::U9, (vals::Ds::NINEBIT, vals::Frxth::HALF)); - impl_word!(word::U10, (vals::Ds::TENBIT, vals::Frxth::HALF)); - impl_word!(word::U11, (vals::Ds::ELEVENBIT, vals::Frxth::HALF)); - impl_word!(word::U12, (vals::Ds::TWELVEBIT, vals::Frxth::HALF)); - impl_word!(word::U13, (vals::Ds::THIRTEENBIT, vals::Frxth::HALF)); - impl_word!(word::U14, (vals::Ds::FOURTEENBIT, vals::Frxth::HALF)); - impl_word!(word::U15, (vals::Ds::FIFTEENBIT, vals::Frxth::HALF)); - impl_word!(u16, (vals::Ds::SIXTEENBIT, vals::Frxth::HALF)); + impl_word!(word::U4, (vals::Ds::BITS4, vals::Frxth::QUARTER)); + impl_word!(word::U5, (vals::Ds::BITS5, vals::Frxth::QUARTER)); + impl_word!(word::U6, (vals::Ds::BITS6, vals::Frxth::QUARTER)); + impl_word!(word::U7, (vals::Ds::BITS7, vals::Frxth::QUARTER)); + impl_word!(u8, (vals::Ds::BITS8, vals::Frxth::QUARTER)); + impl_word!(word::U9, (vals::Ds::BITS9, vals::Frxth::HALF)); + impl_word!(word::U10, (vals::Ds::BITS10, vals::Frxth::HALF)); + impl_word!(word::U11, (vals::Ds::BITS11, vals::Frxth::HALF)); + impl_word!(word::U12, (vals::Ds::BITS12, vals::Frxth::HALF)); + impl_word!(word::U13, (vals::Ds::BITS13, vals::Frxth::HALF)); + impl_word!(word::U14, (vals::Ds::BITS14, vals::Frxth::HALF)); + impl_word!(word::U15, (vals::Ds::BITS15, vals::Frxth::HALF)); + impl_word!(u16, (vals::Ds::BITS16, vals::Frxth::HALF)); } #[cfg(any(spi_v3, spi_v4, spi_v5))] From 766372e06a413352dc07b864dd76e85e03782790 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 25 Feb 2024 21:16:43 -0500 Subject: [PATCH 581/760] rustfmt --- tests/stm32/src/bin/cryp.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index 59c85f258..f105abf26 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs @@ -59,9 +59,7 @@ async fn main(_spawner: Spawner) { let _ = cipher.encrypt_in_place(&iv.into(), &aad, &mut payload_vec); defmt::assert!(ciphertext == payload_vec[0..ciphertext.len()]); - defmt::assert!( - encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()] - ); + defmt::assert!(encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]); // Decrypt in software using AES-GCM 128-bit let _ = cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec); From 54f502e5e6a355e0f132f33f3eecd2a0abe298bc Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 25 Feb 2024 21:31:25 -0500 Subject: [PATCH 582/760] Run gen_test.py --- tests/stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 37519ba11..bfe003a11 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -93,7 +93,7 @@ required-features = [ "can",] [[bin]] name = "cryp" path = "src/bin/cryp.rs" -required-features = [ "hash",] +required-features = [ "cryp",] [[bin]] name = "dac" From a0afd378f4f3bb0032a1f845c2883334b433dd79 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Mon, 26 Feb 2024 17:28:29 +0800 Subject: [PATCH 583/760] update usbd-hid to latest Signed-off-by: Haobo Gu --- embassy-usb/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 1b31b6145..fe5e36b32 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -56,5 +56,5 @@ log = { version = "0.4.14", optional = true } heapless = "0.8" # for HID -usbd-hid = { version = "0.6.0", optional = true } +usbd-hid = { version = "0.7.0", optional = true } ssmarshal = { version = "1.0", default-features = false, optional = true } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index abb995be6..4ab5c7b7c 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -28,7 +28,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.1" -usbd-hid = "0.6.0" +usbd-hid = "0.7.0" serde = { version = "1.0.136", default-features = false } embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 56b9c8018..24aa560d5 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -24,7 +24,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.1" -usbd-hid = "0.6.0" +usbd-hid = "0.7.0" serde = { version = "1.0.136", default-features = false } [profile.release] diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index e1092dba4..585349506 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -36,7 +36,7 @@ display-interface = "0.4.1" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.3.0" heapless = "0.8" -usbd-hid = "0.6.1" +usbd-hid = "0.7.0" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 74ccfa3b0..64c749b9b 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/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", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -usbd-hid = "0.6.0" +usbd-hid = "0.7.0" defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 0c6beb72c..5bcee178f 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -13,7 +13,7 @@ embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["de embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -usbd-hid = "0.6.0" +usbd-hid = "0.7.0" defmt = "0.3" defmt-rtt = "0.4" From 5c45723777dbd7d9d23188f5b5a2adc417e29292 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Fri, 23 Feb 2024 14:33:25 +0000 Subject: [PATCH 584/760] stm32: timers: use TIMx_CC interrupt source for advanced timers fixes (hopefully) time driver when using TIM1/8/20 --- embassy-stm32/src/time_driver.rs | 34 ++++++++++++++++++++++++++++++++ embassy-stm32/src/timer/mod.rs | 19 ++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 8e4e606a4..37b2e7526 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -16,6 +16,8 @@ use crate::pac::timer::vals; use crate::rcc::sealed::RccPeripheral; #[cfg(feature = "low-power")] use crate::rtc::Rtc; +#[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] +use crate::timer::sealed::AdvancedControlInstance; use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; use crate::{interrupt, peripherals}; @@ -76,6 +78,14 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; + (TIM1, timer, $block:ident, CC, $irq:ident) => { + #[cfg(time_driver_tim1)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; (TIM2, timer, $block:ident, UP, $irq:ident) => { #[cfg(time_driver_tim2)] #[cfg(feature = "rt")] @@ -116,6 +126,14 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; + (TIM8, timer, $block:ident, CC, $irq:ident) => { + #[cfg(time_driver_tim8)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; (TIM9, timer, $block:ident, UP, $irq:ident) => { #[cfg(time_driver_tim9)] #[cfg(feature = "rt")] @@ -148,6 +166,14 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; + (TIM20, timer, $block:ident, CC, $irq:ident) => { + #[cfg(time_driver_tim20)] + #[cfg(feature = "rt")] + #[interrupt] + fn $irq() { + DRIVER.on_interrupt() + } + }; (TIM21, timer, $block:ident, UP, $irq:ident) => { #[cfg(time_driver_tim21)] #[cfg(feature = "rt")] @@ -281,6 +307,14 @@ impl RtcDriver { ::Interrupt::unpend(); unsafe { ::Interrupt::enable() }; + #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] + { + ::CaptureCompareInterrupt::unpend(); + unsafe { + ::CaptureCompareInterrupt::enable(); + } + } + r.cr1().modify(|w| w.set_cen(true)); } diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9397da2a1..c8f580101 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -464,6 +464,9 @@ pub(crate) mod sealed { pub trait AdvancedControlInstance: GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance { + /// Capture compare interrupt for this timer. + type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; + /// Get access to the advanced timer registers. fn regs_advanced() -> crate::pac::timer::TimAdv; @@ -831,8 +834,10 @@ macro_rules! impl_2ch_cmp_timer { #[allow(unused)] macro_rules! impl_adv_timer { - ($inst:ident) => { + ($inst:ident, $irq:ident) => { impl sealed::AdvancedControlInstance for crate::peripherals::$inst { + type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq; + fn regs_advanced() -> crate::pac::timer::TimAdv { unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } } @@ -905,11 +910,13 @@ foreach_interrupt! { impl_gp16_timer!($inst); impl_1ch_cmp_timer!($inst); impl_2ch_cmp_timer!($inst); - impl_adv_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; + ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => { + impl_adv_timer!($inst, $irq); + }; ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { @@ -921,11 +928,13 @@ foreach_interrupt! { impl_gp16_timer!($inst); impl_1ch_cmp_timer!($inst); impl_2ch_cmp_timer!($inst); - impl_adv_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; + ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => { + impl_adv_timer!($inst, $irq); + }; ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { @@ -937,11 +946,13 @@ foreach_interrupt! { impl_gp16_timer!($inst); impl_1ch_cmp_timer!($inst); impl_2ch_cmp_timer!($inst); - impl_adv_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; + ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => { + impl_adv_timer!($inst, $irq); + }; } // Update Event trigger DMA for every timer From bf44adc4bcd4725f19ec99428acd70700b48e8cd Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 27 Feb 2024 14:20:58 +0800 Subject: [PATCH 585/760] allow higher psc value for iwdg_v3 --- embassy-stm32/src/wdg/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index dc701ef64..2ff0db09e 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -42,9 +42,13 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { // Prescaler value let psc = 2u16.pow(psc_power); + #[cfg(not(iwdg_v3))] + assert!(psc <= 256, "IWDG prescaler should be no more than 256"); + #[cfg(iwdg_v3)] // H5, U5, WBA + assert!(psc <= 1024, "IWDG prescaler should be no more than 1024"); + // Convert prescaler power to PR register value let pr = psc_power as u8 - 2; - assert!(pr <= 0b110); // Reload value let rl = reload_value(psc, timeout_us); From 0bcbca9e5bc506c846368d32db049c7cbb248997 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 27 Feb 2024 10:32:52 +0200 Subject: [PATCH 586/760] nrf: spim: Hide the "Copying SPIM tx buffer into RAM for DMA" traces Now that SPIM driver seems to be properly working, hide the trace logs which occur whenever tx buffer needs to be copied into RAM. --- embassy-nrf/src/spim.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 3538afa2b..c45d45e68 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -312,7 +312,7 @@ impl<'d, T: Instance> Spim<'d, T> { match self.blocking_inner_from_ram(rx, tx) { Ok(_) => Ok(()), Err(Error::BufferNotInRAM) => { - trace!("Copying SPIM tx buffer into RAM for DMA"); + // trace!("Copying SPIM tx buffer into RAM for DMA"); let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; tx_ram_buf.copy_from_slice(tx); self.blocking_inner_from_ram(rx, tx_ram_buf) @@ -366,7 +366,7 @@ impl<'d, T: Instance> Spim<'d, T> { match self.async_inner_from_ram(rx, tx).await { Ok(_) => Ok(()), Err(Error::BufferNotInRAM) => { - trace!("Copying SPIM tx buffer into RAM for DMA"); + // trace!("Copying SPIM tx buffer into RAM for DMA"); let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; tx_ram_buf.copy_from_slice(tx); self.async_inner_from_ram(rx, tx_ram_buf).await From 137855418aa0a3596b7469d6c8ad8ffbf4e76584 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 27 Feb 2024 10:35:39 +0200 Subject: [PATCH 587/760] nrf: Bump embedded-storage-async to 0.4.1 --- embassy-nrf/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 7e161df9b..0045d9f97 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -146,7 +146,7 @@ critical-section = "1.1" rand_core = "0.6.3" fixed = "1.10.0" embedded-storage = "0.3.1" -embedded-storage-async = "0.4.0" +embedded-storage-async = "0.4.1" cfg-if = "1.0.0" document-features = "0.2.7" From e63b0d7a2f89e3b210569ce77f45e9cb14ac6ae8 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 27 Feb 2024 10:38:07 +0000 Subject: [PATCH 588/760] stm32: can: fd: fix SID read/write from buf elems --- embassy-stm32/src/can/fd/peripheral.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 0771d6fbb..8e4ecf4a5 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -721,13 +721,15 @@ fn make_id(id: u32, extended: bool) -> embedded_can::Id { if extended { embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) }) } else { - embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked((id & 0x000007FF) as u16) }) + // A standard identifier is stored into ID[28:18]. + embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked(((id >> 18) & 0x000007FF) as u16) }) } } fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) { let (id, id_type) = match header.id() { - embedded_can::Id::Standard(id) => (id.as_raw() as u32, IdType::StandardId), + // A standard identifier has to be written to ID[28:18]. + embedded_can::Id::Standard(id) => ((id.as_raw() as u32) << 18, IdType::StandardId), embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId), }; From 9a4f58fe158551bd0c38d23a71f6b719d4ce5130 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 27 Feb 2024 10:38:40 +0000 Subject: [PATCH 589/760] stm32: can: fd: only TX with BRS if also TXing with FDF --- embassy-stm32/src/can/fd/peripheral.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 8e4ecf4a5..9c29e4887 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -739,7 +739,7 @@ fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) { } else { FrameFormat::Classic }; - let brs = header.len() > 8 || header.bit_rate_switching(); + let brs = (frame_format == FrameFormat::Fdcan) && header.bit_rate_switching(); mailbox.header.write(|w| { unsafe { w.id().bits(id) } From b7e0964a078d1760263df586953fbd1d29aabe2b Mon Sep 17 00:00:00 2001 From: Maia Date: Tue, 27 Feb 2024 11:07:05 -0800 Subject: [PATCH 590/760] added FDCANSEL logic for H7 --- embassy-stm32/src/rcc/h.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index c6da79afb..7b2255cc6 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -557,6 +557,9 @@ pub(crate) unsafe fn init(config: Config) { RCC.d3ccipr().modify(|w| { w.set_adcsel(config.adc_clock_source); }); + RCC.d2ccip1r().modify(|w| { + w.set_fdcansel(config.fdcan_clock_source); + }); } #[cfg(stm32h5)] { From 0ed402fd79a6dfbe4f3b2187a97d160ce7c3140b Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 27 Feb 2024 23:42:50 +0000 Subject: [PATCH 591/760] stm32: can: fd: refactor out some duplicate code --- embassy-stm32/src/can/fd/peripheral.rs | 122 +++---------------------- embassy-stm32/src/can/fdcan.rs | 66 ++++++------- embassy-stm32/src/can/frame.rs | 30 ++++++ 3 files changed, 68 insertions(+), 150 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 9c29e4887..7d26a5fe0 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -37,7 +37,7 @@ impl Registers { &mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum] } - pub fn read_classic(&self, fifonr: usize) -> Option<(ClassicFrame, u16)> { + pub fn read(&self, fifonr: usize) -> Option<(F, u16)> { // Fill level - do we have a msg? if self.regs.rxfs(fifonr).read().ffl() < 1 { return None; @@ -54,32 +54,8 @@ impl Registers { match maybe_header { Some((header, ts)) => { - let data = ClassicData::new(&buffer[0..header.len() as usize]); - Some((ClassicFrame::new(header, data.unwrap()), ts)) - } - None => None, - } - } - - pub fn read_fd(&self, fifonr: usize) -> Option<(FdFrame, u16)> { - // Fill level - do we have a msg? - if self.regs.rxfs(fifonr).read().ffl() < 1 { - return None; - } - - let read_idx = self.regs.rxfs(fifonr).read().fgi(); - let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); - - let mut buffer: [u8; 64] = [0; 64]; - let maybe_header = extract_frame(mailbox, &mut buffer); - - // Clear FIFO, reduces count and increments read buf - self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx)); - - match maybe_header { - Some((header, ts)) => { - let data = FdData::new(&buffer[0..header.len() as usize]); - Some((FdFrame::new(header, data.unwrap()), ts)) + let data = &buffer[0..header.len() as usize]; + Some((F::from_header(header, data)?, ts)) } None => None, } @@ -194,10 +170,9 @@ impl Registers { #[inline] //fn abort_pending_mailbox(&mut self, idx: Mailbox, pending: PTX) -> Option - pub fn abort_pending_mailbox(&self, bufidx: usize) -> Option //where // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, - { + pub fn abort_pending_mailbox_generic(&self, bufidx: usize) -> Option { if self.abort(bufidx) { let mailbox = self.tx_buffer_element(bufidx); @@ -216,50 +191,11 @@ impl Registers { let mut data = [0u8; 64]; data_from_tx_buffer(&mut data, mailbox, len as usize); - let cd = ClassicData::new(&data).unwrap(); - Some(ClassicFrame::new(Header::new(id, len, header_reg.rtr().bit()), cd)) - } else { - // Abort request failed because the frame was already sent (or being sent) on - // the bus. All mailboxes are now free. This can happen for small prescaler - // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR - // has preempted the execution. - None - } - } - - #[inline] - //fn abort_pending_mailbox(&mut self, idx: Mailbox, pending: PTX) -> Option - pub fn abort_pending_fd_mailbox(&self, bufidx: usize) -> Option -//where - // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, - { - if self.abort(bufidx) { - let mailbox = self.tx_buffer_element(bufidx); - - let header_reg = mailbox.header.read(); - let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); - - let len = match header_reg.to_data_length() { - DataLength::Fdcan(len) => len, - DataLength::Classic(len) => len, - }; - if len as usize > FdFrame::MAX_DATA_LEN { - return None; - } - - //let tx_ram = self.tx_msg_ram(); - let mut data = [0u8; 64]; - data_from_tx_buffer(&mut data, mailbox, len as usize); - - let cd = FdData::new(&data).unwrap(); - - let header = if header_reg.fdf().frame_format() == FrameFormat::Fdcan { - Header::new_fd(id, len, header_reg.rtr().bit(), header_reg.brs().bit()) + if header_reg.rtr().bit() { + F::new_remote(id, len as usize) } else { - Header::new(id, len, header_reg.rtr().bit()) - }; - - Some(FdFrame::new(header, cd)) + F::new(id, &data) + } } else { // Abort request failed because the frame was already sent (or being sent) on // the bus. All mailboxes are now free. This can happen for small prescaler @@ -272,7 +208,7 @@ impl Registers { /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can /// be preserved. //pub fn transmit_preserve( - pub fn write_classic(&self, frame: &ClassicFrame) -> nb::Result, Infallible> { + pub fn write(&self, frame: &F) -> nb::Result, Infallible> { let queue_is_full = self.tx_queue_is_full(); let id = frame.header().id(); @@ -281,45 +217,11 @@ impl Registers { // Discard the first slot with a lower priority message let (idx, pending_frame) = if queue_is_full { if self.is_available(0, id) { - (0, self.abort_pending_mailbox(0)) + (0, self.abort_pending_mailbox_generic(0)) } else if self.is_available(1, id) { - (1, self.abort_pending_mailbox(1)) + (1, self.abort_pending_mailbox_generic(1)) } else if self.is_available(2, id) { - (2, self.abort_pending_mailbox(2)) - } else { - // For now we bail when there is no lower priority slot available - // Can this lead to priority inversion? - return Err(nb::Error::WouldBlock); - } - } else { - // Read the Write Pointer - let idx = self.regs.txfqs().read().tfqpi(); - - (idx, None) - }; - - self.put_tx_frame(idx as usize, frame.header(), frame.data()); - - Ok(pending_frame) - } - - /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can - /// be preserved. - //pub fn transmit_preserve( - pub fn write_fd(&self, frame: &FdFrame) -> nb::Result, Infallible> { - let queue_is_full = self.tx_queue_is_full(); - - let id = frame.header().id(); - - // If the queue is full, - // Discard the first slot with a lower priority message - let (idx, pending_frame) = if queue_is_full { - if self.is_available(0, id) { - (0, self.abort_pending_fd_mailbox(0)) - } else if self.is_available(1, id) { - (1, self.abort_pending_fd_mailbox(1)) - } else if self.is_available(2, id) { - (2, self.abort_pending_fd_mailbox(2)) + (2, self.abort_pending_mailbox_generic(2)) } else { // For now we bail when there is no lower priority slot available // Can this lead to priority inversion? diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 744d756f5..6a4a25cb7 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -58,7 +58,7 @@ impl interrupt::typelevel::Handler for IT0Interrup if !T::registers().tx_queue_is_full() { match buf.tx_receiver.try_receive() { Ok(frame) => { - _ = T::registers().write_classic(&frame); + _ = T::registers().write(&frame); } Err(_) => {} } @@ -68,7 +68,7 @@ impl interrupt::typelevel::Handler for IT0Interrup if !T::registers().tx_queue_is_full() { match buf.tx_receiver.try_receive() { Ok(frame) => { - _ = T::registers().write_fd(&frame); + _ = T::registers().write(&frame); } Err(_) => {} } @@ -359,7 +359,7 @@ impl<'d, T: Instance> Fdcan<'d, T> { /// Returns the next received message frame pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { - T::state().rx_mode.read::().await + T::state().rx_mode.read_classic::().await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -633,7 +633,7 @@ impl<'c, 'd, T: Instance> FdcanTx<'d, T> { impl<'c, 'd, T: Instance> FdcanRx<'d, T> { /// Returns the next received message frame pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { - T::state().rx_mode.read::().await + T::state().rx_mode.read_classic::().await } /// Returns the next received message frame @@ -649,6 +649,7 @@ pub(crate) mod sealed { use embassy_sync::channel::{DynamicReceiver, DynamicSender}; use embassy_sync::waitqueue::AtomicWaker; + use super::CanHeader; use crate::can::_version::{BusError, Timestamp}; use crate::can::frame::{ClassicFrame, FdFrame}; @@ -689,13 +690,13 @@ pub(crate) mod sealed { waker.wake(); } RxMode::ClassicBuffered(buf) => { - if let Some(r) = T::registers().read_classic(fifonr) { + if let Some(r) = T::registers().read(fifonr) { let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); let _ = buf.rx_sender.try_send((r.0, ts)); } } RxMode::FdBuffered(buf) => { - if let Some(r) = T::registers().read_fd(fifonr) { + if let Some(r) = T::registers().read(fifonr) { let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); let _ = buf.rx_sender.try_send((r.0, ts)); } @@ -703,15 +704,15 @@ pub(crate) mod sealed { } } - pub async fn read(&self) -> Result<(ClassicFrame, Timestamp), BusError> { + async fn read(&self) -> Result<(F, Timestamp), BusError> { poll_fn(|cx| { T::state().err_waker.register(cx.waker()); self.register(cx.waker()); - if let Some((msg, ts)) = T::registers().read_classic(0) { + if let Some((msg, ts)) = T::registers().read(0) { let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); return Poll::Ready(Ok((msg, ts))); - } else if let Some((msg, ts)) = T::registers().read_classic(1) { + } else if let Some((msg, ts)) = T::registers().read(1) { let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); return Poll::Ready(Ok((msg, ts))); } else if let Some(err) = T::registers().curr_error() { @@ -723,24 +724,12 @@ pub(crate) mod sealed { .await } - pub async fn read_fd(&self) -> Result<(FdFrame, Timestamp), BusError> { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - self.register(cx.waker()); + pub async fn read_classic(&self) -> Result<(ClassicFrame, Timestamp), BusError> { + self.read::().await + } - if let Some((msg, ts)) = T::registers().read_fd(0) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some((msg, ts)) = T::registers().read_fd(1) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = T::registers().curr_error() { - // TODO: this is probably wrong - return Poll::Ready(Err(err)); - } - Poll::Pending - }) - .await + pub async fn read_fd(&self) -> Result<(FdFrame, Timestamp), BusError> { + self.read::().await } } @@ -766,11 +755,11 @@ pub(crate) mod sealed { /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. - pub async fn write(&self, frame: &ClassicFrame) -> Option { + async fn write_generic(&self, frame: &F) -> Option { poll_fn(|cx| { self.register(cx.waker()); - if let Ok(dropped) = T::registers().write_classic(frame) { + if let Ok(dropped) = T::registers().write(frame) { return Poll::Ready(dropped); } @@ -781,23 +770,20 @@ pub(crate) mod sealed { .await } + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + pub async fn write(&self, frame: &ClassicFrame) -> Option { + self.write_generic::(frame).await + } + /// Queues the message to be sent but exerts backpressure. If a lower-priority /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&self, frame: &FdFrame) -> Option { - poll_fn(|cx| { - self.register(cx.waker()); - - if let Ok(dropped) = T::registers().write_fd(frame) { - return Poll::Ready(dropped); - } - - // Couldn't replace any lower priority frames. Need to wait for some mailboxes - // to clear. - Poll::Pending - }) - .await + self.write_generic::(frame).await } } diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index 725a9b1ab..59b9fb08c 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -56,6 +56,16 @@ impl Header { } } +/// Trait for FDCAN frame types, providing ability to construct from a Header +/// and to retrieve the Header from a frame +pub trait CanHeader: Sized { + /// Construct frame from header and payload + fn from_header(header: Header, data: &[u8]) -> Option; + + /// Get this frame's header struct + fn header(&self) -> &Header; +} + /// Payload of a classic CAN data frame. /// /// Contains 0 to 8 Bytes of data. @@ -213,6 +223,16 @@ impl embedded_can::Frame for ClassicFrame { } } +impl CanHeader for ClassicFrame { + fn from_header(header: Header, data: &[u8]) -> Option { + Some(Self::new(header, ClassicData::new(data)?)) + } + + fn header(&self) -> &Header { + self.header() + } +} + /// Payload of a (FD)CAN data frame. /// /// Contains 0 to 64 Bytes of data. @@ -368,3 +388,13 @@ impl embedded_can::Frame for FdFrame { &self.data.raw() } } + +impl CanHeader for FdFrame { + fn from_header(header: Header, data: &[u8]) -> Option { + Some(Self::new(header, FdData::new(data)?)) + } + + fn header(&self) -> &Header { + self.header() + } +} From a8da42943fdd57ded612399d18846398cbd011d3 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 27 Feb 2024 23:45:53 +0000 Subject: [PATCH 592/760] stm32: can: fd: rm some irrelevant commented code and dead code --- embassy-stm32/src/can/fd/peripheral.rs | 42 -------------------------- embassy-stm32/src/can/frame.rs | 2 -- 2 files changed, 44 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 7d26a5fe0..c5606b883 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -62,11 +62,6 @@ impl Registers { } pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) { - // Fill level - do we have a msg? - //if self.regs.rxfs(fifonr).read().ffl() < 1 { return None; } - - //let read_idx = self.regs.rxfs(fifonr).read().fgi(); - let mailbox = self.tx_buffer_element(bufidx); mailbox.reset(); @@ -169,9 +164,6 @@ impl Registers { } #[inline] - //fn abort_pending_mailbox(&mut self, idx: Mailbox, pending: PTX) -> Option -//where - // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, pub fn abort_pending_mailbox_generic(&self, bufidx: usize) -> Option { if self.abort(bufidx) { let mailbox = self.tx_buffer_element(bufidx); @@ -187,7 +179,6 @@ impl Registers { return None; } - //let tx_ram = self.tx_msg_ram(); let mut data = [0u8; 64]; data_from_tx_buffer(&mut data, mailbox, len as usize); @@ -205,9 +196,6 @@ impl Registers { } } - /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can - /// be preserved. - //pub fn transmit_preserve( pub fn write(&self, frame: &F) -> nb::Result, Infallible> { let queue_is_full = self.tx_queue_is_full(); @@ -459,8 +447,6 @@ impl Registers { /// parameter to this method. #[inline] pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) { - //self.control.config.nbtr = btr; - self.regs.nbtp().write(|w| { w.set_nbrp(btr.nbrp() - 1); w.set_ntseg1(btr.ntseg1() - 1); @@ -473,8 +459,6 @@ impl Registers { /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. #[inline] pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) { - //self.control.config.dbtr = btr; - self.regs.dbtp().write(|w| { w.set_dbrp(btr.dbrp() - 1); w.set_dtseg1(btr.dtseg1() - 1); @@ -492,7 +476,6 @@ impl Registers { #[inline] pub fn set_automatic_retransmit(&mut self, enabled: bool) { self.regs.cccr().modify(|w| w.set_dar(!enabled)); - //self.control.config.automatic_retransmit = enabled; } /// Configures the transmit pause feature. See @@ -500,21 +483,18 @@ impl Registers { #[inline] pub fn set_transmit_pause(&mut self, enabled: bool) { self.regs.cccr().modify(|w| w.set_txp(!enabled)); - //self.control.config.transmit_pause = enabled; } /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`] #[inline] pub fn set_non_iso_mode(&mut self, enabled: bool) { self.regs.cccr().modify(|w| w.set_niso(enabled)); - //self.control.config.non_iso_mode = enabled; } /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`] #[inline] pub fn set_edge_filtering(&mut self, enabled: bool) { self.regs.cccr().modify(|w| w.set_efbi(enabled)); - //self.control.config.edge_filtering = enabled; } /// Configures frame transmission mode. See @@ -534,16 +514,12 @@ impl Registers { #[cfg(not(stm32h7))] w.set_brse(brse); }); - - //self.control.config.frame_transmit = fts; } /// Sets the protocol exception handling on/off #[inline] pub fn set_protocol_exception_handling(&mut self, enabled: bool) { self.regs.cccr().modify(|w| w.set_pxhd(!enabled)); - - //self.control.config.protocol_exception_handling = enabled; } /// Configures and resets the timestamp counter @@ -567,8 +543,6 @@ impl Registers { w.set_tcp(tcp); w.set_tss(tss); }); - - //self.control.config.timestamp_source = select; } #[cfg(not(stm32h7))] @@ -696,22 +670,6 @@ fn data_from_tx_buffer(buffer: &mut [u8], mailbox: &TxBufferElement, len: usize) } } -impl From<&RxFifoElement> for ClassicFrame { - fn from(mailbox: &RxFifoElement) -> Self { - let header_reg = mailbox.header.read(); - - let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); - let dlc = header_reg.to_data_length().len(); - let len = dlc as usize; - - let mut buffer: [u8; 64] = [0; 64]; - data_from_fifo(&mut buffer, mailbox, len); - let data = ClassicData::new(&buffer[0..len]); - let header = Header::new(id, dlc, header_reg.rtr().bits()); - ClassicFrame::new(header, data.unwrap()) - } -} - fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> { let header_reg = mailbox.header.read(); diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index 59b9fb08c..00a441db6 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -292,8 +292,6 @@ pub struct FdFrame { } impl FdFrame { - pub(crate) const MAX_DATA_LEN: usize = 64; - /// Create a new CAN classic Frame pub fn new(can_header: Header, data: FdData) -> FdFrame { FdFrame { can_header, data } From 1353a343b8e9d48b8f1f537dbf4e38e32a39c06d Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Wed, 28 Feb 2024 18:03:53 +1000 Subject: [PATCH 593/760] Buffer is not big enough for FD frames. --- embassy-stm32/src/can/fd/peripheral.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index c5606b883..abb546895 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -46,7 +46,7 @@ impl Registers { let read_idx = self.regs.rxfs(fifonr).read().fgi(); let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); - let mut buffer: [u8; 8] = [0; 8]; + let mut buffer = [0u8; 64]; let maybe_header = extract_frame(mailbox, &mut buffer); // Clear FIFO, reduces count and increments read buf From 368b3a9aaf97a7662217b9ff2784e3648368586c Mon Sep 17 00:00:00 2001 From: "Guilherme S. Salustiano" Date: Wed, 28 Feb 2024 14:54:54 +0100 Subject: [PATCH 594/760] fix: radio error --- embassy-nrf/src/radio/ble.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 81ef96b65..24dba582f 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -15,7 +15,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::radio::*; use crate::util::slice_in_ram_or; -/// UART error. +/// RADIO error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] From 990b44566ce1393a4a553a65d5a6c412cb656805 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Wed, 28 Feb 2024 15:11:30 +0100 Subject: [PATCH 595/760] [docs] Added some failure modes to watch out for * Linked to probe.rs website rather than the crates.io page * Fixed some formatting errors (>:( grrr asciidoc) * Added cargo add probe-rs failure mode * Added pico-w vs pico blinky failure mode --- docs/modules/ROOT/pages/getting_started.adoc | 28 +++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc index 24bde1c1f..be2b868eb 100644 --- a/docs/modules/ROOT/pages/getting_started.adoc +++ b/docs/modules/ROOT/pages/getting_started.adoc @@ -3,7 +3,7 @@ So you want to try Embassy, great! To get started, there are a few tools you need to install: * link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code. -* link:https://crates.io/crates/probe-rs[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well. +* link:https://probe.rs/[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well. If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples. @@ -82,19 +82,19 @@ If everything worked correctly, you should see a blinking LED on your board, and └─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27 ---- -NOTE: How does the `cargo run` command know how to connect to our board and program it? In each `examples` folder, there’s a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip it’s programming, so you’ll have to edit this file if you want to run examples on other chips. +NOTE: How does the `+cargo run+` command know how to connect to our board and program it? In each `examples` folder, there’s a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip it’s programming, so you’ll have to edit this file if you want to run examples on other chips. === It didn’t work! -If you hare having issues when running `cargo run --release`, please check the following: +If you hare having issues when running `+cargo run --release+`, please check the following: -* You are specifying the correct `--chip` on the command line, OR -* You have set `.cargo/config.toml`'s run line to the correct chip, AND -* You have changed `examples/Cargo.toml`'s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature) +* You are specifying the correct `+--chip+` on the command line, OR +* You have set `+.cargo/config.toml+`’s run line to the correct chip, AND +* You have changed `+examples/Cargo.toml+`’s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature) At this point the project should run. If you do not see a blinky LED for blinky, for example, be sure to check the code is toggling your board's LED pin. -If you are trying to run an example with `cargo run --release` and you see the following output: +If you are trying to run an example with `+cargo run --release+` and you see the following output: [source] ---- 0.000000 INFO Hello World! @@ -115,6 +115,20 @@ To get rid of the frame-index error add the following to your `Cargo.toml`: debug = 2 ---- +If you’re get an extremely long error message containing something like the following: + +[source] +---- +error[E0463]: can't find crate for `std` + | + = note: the `thumbv6m-none-eabi` target may not support the standard library + = note: `std` is required by `stable_deref_trait` because it does not declare `#![no_std]` +---- + +Make sure that you didn’t accidentally run `+cargo add probe-rs+` (which adds it as a dependency) instead of link:https://probe.rs/docs/getting-started/installation/[correctly installing probe-rs]. + +If you’re using a raspberry pi pico-w, make sure you’re running `+cargo run --bin wifi_blinky --release+` rather than the regular blinky. The pico-w’s on-board LED is connected to the WiFi chip, which needs to be initialized before the LED can be blinked. + If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room]. == What's next? From 2787164ea9ba30f806d6c38443d2eca2984b1e62 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Wed, 28 Feb 2024 15:15:43 +0100 Subject: [PATCH 596/760] grammar fix --- docs/modules/ROOT/pages/getting_started.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc index be2b868eb..e8bc84255 100644 --- a/docs/modules/ROOT/pages/getting_started.adoc +++ b/docs/modules/ROOT/pages/getting_started.adoc @@ -115,7 +115,7 @@ To get rid of the frame-index error add the following to your `Cargo.toml`: debug = 2 ---- -If you’re get an extremely long error message containing something like the following: +If you’re getting an extremely long error message containing something like the following: [source] ---- From d07a0148d759fa09ba1ee8dc4810bb4edd8bda49 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Wed, 28 Feb 2024 15:48:37 +0100 Subject: [PATCH 597/760] Documented rp2040 probe-rs info bug, linked to new_project page --- docs/modules/ROOT/pages/getting_started.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc index e8bc84255..73cb5530d 100644 --- a/docs/modules/ROOT/pages/getting_started.adoc +++ b/docs/modules/ROOT/pages/getting_started.adoc @@ -129,6 +129,8 @@ Make sure that you didn’t accidentally run `+cargo add probe-rs+` (which adds If you’re using a raspberry pi pico-w, make sure you’re running `+cargo run --bin wifi_blinky --release+` rather than the regular blinky. The pico-w’s on-board LED is connected to the WiFi chip, which needs to be initialized before the LED can be blinked. +If you’re using an rp2040 debug probe (e.g. the pico probe) and are having issues after running `probe-rs info`, unplug and reconnect the probe, letting it power cycle. Running `probe-rs info` is link:https://github.com/probe-rs/probe-rs/issues/1849[known to put the pico probe into an unusable state]. + If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room]. == What's next? @@ -138,3 +140,4 @@ Congratulations, you have your first Embassy application running! Here are some * Read more about the xref:runtime.adoc[executor]. * Read more about the xref:hal.adoc[HAL]. * Start xref:basic_application.adoc[writing your application]. +* Learn how to xref:new_project.adoc[start a new embassy project by adapting an example]. From 47c579eba2a7b4372a891bcd747f2bb0c56ce8a4 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Wed, 28 Feb 2024 18:08:41 +0800 Subject: [PATCH 598/760] update metapac --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/can/fd/peripheral.rs | 4 +++- embassy-stm32/src/opamp.rs | 2 ++ embassy-stm32/src/timer/mod.rs | 12 ++++++------ examples/stm32h7/src/bin/low_level_timer_api.rs | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 81b8e2f94..08ccd35ae 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-7c8b53413499acc3273b706318777a60f932d77a" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-7c8b53413499acc3273b706318777a60f932d77a", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index c5606b883..9b8802ff9 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -303,7 +303,9 @@ impl Registers { // Framework specific settings are set here // set TxBuffer to Queue Mode - self.regs.txbc().write(|w| w.set_tfqm(true)); + self.regs + .txbc() + .write(|w| w.set_tfqm(crate::pac::can::vals::Tfqm::QUEUE)); // set standard filters list size to 28 // set extended filters list size to 8 diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index ae8b3cacc..cf531e266 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -90,6 +90,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { in_pin.set_as_analog(); out_pin.set_as_analog(); + // PGA_GAIN value may have different meaning in different MCU serials, use with caution. let (vm_sel, pga_gain) = match gain { OpAmpGain::Mul1 => (0b11, 0b00), OpAmpGain::Mul2 => (0b10, 0b00), @@ -127,6 +128,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { into_ref!(pin); pin.set_as_analog(); + // PGA_GAIN value may have different meaning in different MCU serials, use with caution. let (vm_sel, pga_gain) = match gain { OpAmpGain::Mul1 => (0b11, 0b00), OpAmpGain::Mul2 => (0b10, 0b00), diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index c8f580101..8530c5229 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -379,7 +379,7 @@ pub(crate) mod sealed { let regs = Self::regs_gp32(); regs.psc().write(|r| r.set_psc(psc)); - regs.arr().write(|r| r.set_arr(arr)); + regs.arr().write_value(arr); regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); regs.egr().write(|r| r.set_ug(true)); @@ -391,7 +391,7 @@ pub(crate) mod sealed { let timer_f = Self::frequency(); let regs = Self::regs_gp32(); - let arr = regs.arr().read().arr(); + let arr = regs.arr().read(); let psc = regs.psc().read().psc(); timer_f / arr / (psc + 1) @@ -399,22 +399,22 @@ pub(crate) mod sealed { /// Set comapre value for a channel. fn set_compare_value(&self, channel: Channel, value: u32) { - Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); + Self::regs_gp32().ccr(channel.index()).write_value(value); } /// Get capture value for a channel. fn get_capture_value(&self, channel: Channel) -> u32 { - Self::regs_gp32().ccr(channel.index()).read().ccr() + Self::regs_gp32().ccr(channel.index()).read() } /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. fn get_max_compare_value(&self) -> u32 { - Self::regs_gp32().arr().read().arr() + Self::regs_gp32().arr().read() } /// Get compare value for a channel. fn get_compare_value(&self, channel: Channel) -> u32 { - Self::regs_gp32().ccr(channel.index()).read().ccr() + Self::regs_gp32().ccr(channel.index()).read() } } diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index cc508c3cf..049d9967d 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -113,11 +113,11 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { } pub fn get_max_duty(&self) -> u32 { - T::regs_gp32().arr().read().arr() + T::regs_gp32().arr().read() } pub fn set_duty(&mut self, channel: Channel, duty: u32) { defmt::assert!(duty < self.get_max_duty()); - T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty)) + T::regs_gp32().ccr(channel.index()).write_value(duty) } } From 4294bc5e4bb191adcdd2daffd77180bb602da720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Wed, 28 Feb 2024 22:36:31 +0100 Subject: [PATCH 599/760] Added IEEE 802.15.4 radio --- embassy-nrf/src/chips/nrf52833.rs | 5 + embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/radio/ble.rs | 15 +- embassy-nrf/src/radio/event.rs | 310 +++++++++++++++ embassy-nrf/src/radio/ieee802154.rs | 573 ++++++++++++++++++++++++++++ embassy-nrf/src/radio/mod.rs | 34 +- 6 files changed, 917 insertions(+), 22 deletions(-) create mode 100644 embassy-nrf/src/radio/event.rs create mode 100644 embassy-nrf/src/radio/ieee802154.rs diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 7c9b66d69..20f14e2d6 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -170,6 +170,9 @@ embassy_hal_internal::peripherals! { // I2S I2S, + + // Radio + RADIO, } impl_usb!(USBD, USBD, USBD); @@ -306,6 +309,8 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 04a6293a4..132bffa8b 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -47,7 +47,7 @@ pub mod gpio; pub mod gpiote; // TODO: tested on other chips -#[cfg(any(feature = "nrf52840"))] +#[cfg(any(feature = "nrf52833", feature = "nrf52840"))] pub mod radio; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 24dba582f..ecf8cc5eb 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -15,19 +15,6 @@ use crate::interrupt::typelevel::Interrupt; use crate::radio::*; use crate::util::slice_in_ram_or; -/// RADIO error. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Error { - /// Buffer was too long. - BufferTooLong, - /// Buffer was to short. - BufferTooShort, - /// The buffer is not in data RAM. It is most likely in flash, and nRF's DMA cannot access flash. - BufferNotInRAM, -} - /// Radio driver. pub struct Radio<'d, T: Instance> { _p: PeripheralRef<'d, T>, @@ -393,7 +380,7 @@ impl<'d, T: Instance> Radio<'d, T> { // On poll check if interrupt happen poll_fn(|cx| { - s.end_waker.register(cx.waker()); + s.event_waker.register(cx.waker()); if r.events_end.read().events_end().bit_is_set() { // trace!("radio:end"); return core::task::Poll::Ready(()); diff --git a/embassy-nrf/src/radio/event.rs b/embassy-nrf/src/radio/event.rs new file mode 100644 index 000000000..11056b4d8 --- /dev/null +++ b/embassy-nrf/src/radio/event.rs @@ -0,0 +1,310 @@ +use crate::pac; +use bitflags; + +bitflags::bitflags! { + /// Event as bit flags + pub struct Event : u32 { + /// Radio ready + const READY = 1u32 << 0; + /// Address operation done + const ADDRESS = 1u32 << 1; + /// Payload operation done + const PAYLOAD = 1u32 << 2; + /// Packet operation done + const END = 1u32 << 3; + /// Radio has been disabled + const DISABLED = 1u32 << 4; + /// Device address match in last received packet + const DEV_MATCH = 1u32 << 5; + /// No device address match in last received packet + const DEV_MISS = 1u32 << 6; + /// RSSI sampling complete + const RSSI_END = 1u32 << 7; + /// Bit counter reached target + const BC_MATCH = 1u32 << 10; + /// CRC ok in last received packet + const CRC_OK = 1u32 << 12; + /// CRC error in last received packet + const CRC_ERROR = 1u32 << 13; + /// IEEE 802.15.4 length field received + const FRAME_START = 1u32 << 14; + /// Sampling of energy detect complete + const ED_END = 1u32 << 15; + /// Sampling of energy detect stopped + const ED_STOPPED = 1u32 << 16; + /// Wireless medium in idle, ready to sent + const CCA_IDLE = 1u32 << 17; + /// Wireless medium busy, do not send + const CCA_BUSY = 1u32 << 18; + /// Clear channel assessment stopped + const CCA_STOPPED = 1u32 << 19; + /// BLE LR rate boost received + const RATE_BOOST = 1u32 << 20; + /// Radio has ramped up transmitter + const TX_READY = 1u32 << 21; + /// Radio has ramped up receiver + const RX_READY = 1u32 << 22; + /// MAC header match found + const MHR_MATCH = 1u32 << 23; + /// Preamble received, possible false triggering + const SYNC = 1u32 << 26; + /// Last bit sent / received + const PHY_END = 1u32 << 27; + /// Continuous tone extension is present + const CTE_PRESENT = 1u32 << 28; + } +} + +impl Event { + /// Read events from radio + #[cfg(not(feature = "nrf52832"))] + pub fn from_radio(radio: &pac::radio::RegisterBlock) -> Self { + let mut value = Self::empty(); + if radio.events_ready.read().events_ready().bit_is_set() { + value |= Self::READY; + } + if radio.events_address.read().events_address().bit_is_set() { + value |= Self::ADDRESS; + } + if radio.events_payload.read().events_payload().bit_is_set() { + value |= Self::PAYLOAD; + } + if radio.events_end.read().events_end().bit_is_set() { + value |= Self::END; + } + if radio.events_disabled.read().events_disabled().bit_is_set() { + value |= Self::DISABLED; + } + if radio.events_devmatch.read().events_devmatch().bit_is_set() { + value |= Self::DEV_MATCH; + } + if radio.events_devmiss.read().events_devmiss().bit_is_set() { + value |= Self::DEV_MISS; + } + if radio.events_rssiend.read().events_rssiend().bit_is_set() { + value |= Self::RSSI_END; + } + if radio.events_bcmatch.read().events_bcmatch().bit_is_set() { + value |= Self::BC_MATCH; + } + if radio.events_crcok.read().events_crcok().bit_is_set() { + value |= Self::CRC_OK; + } + if radio.events_crcerror.read().events_crcerror().bit_is_set() { + value |= Self::CRC_ERROR; + } + #[cfg(any( + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_framestart.read().events_framestart().bit_is_set() { + value |= Self::FRAME_START; + } + #[cfg(any( + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_edend.read().events_edend().bit_is_set() { + value |= Self::ED_END; + } + #[cfg(any( + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_edstopped.read().events_edstopped().bit_is_set() { + value |= Self::ED_STOPPED; + } + #[cfg(any(feature = "nrf52820", feature = "nrf52833", feature = "_nrf5340-net"))] + if radio.events_ccaidle.read().events_ccaidle().bit_is_set() { + value |= Self::CCA_IDLE; + } + #[cfg(any(feature = "nrf52820", feature = "nrf52833", feature = "_nrf5340-net"))] + if radio.events_ccabusy.read().events_ccabusy().bit_is_set() { + value |= Self::CCA_BUSY; + } + #[cfg(any(feature = "nrf52820", feature = "nrf52833", feature = "_nrf5340-net"))] + if radio.events_ccastopped.read().events_ccastopped().bit_is_set() { + value |= Self::CCA_STOPPED; + } + #[cfg(any( + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_rateboost.read().events_rateboost().bit_is_set() { + value |= Self::RATE_BOOST; + } + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_txready.read().events_txready().bit_is_set() { + value |= Self::TX_READY; + } + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_rxready.read().events_rxready().bit_is_set() { + value |= Self::RX_READY; + } + #[cfg(any( + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_mhrmatch.read().events_mhrmatch().bit_is_set() { + value |= Self::MHR_MATCH; + } + #[cfg(any(feature = "nrf52820", feature = "nrf52833", feature = "_nrf5340-net"))] + if radio.events_sync.read().events_sync().bit_is_set() { + value |= Self::SYNC; + } + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_phyend.read().events_phyend().bit_is_set() { + value |= Self::PHY_END; + } + #[cfg(any( + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "_nrf5340-net" + ))] + if radio.events_ctepresent.read().events_ctepresent().bit_is_set() { + value |= Self::CTE_PRESENT; + } + value + } + // The nRF52832 SVD probably is a bit broken + /// Read events from radio + #[cfg(feature = "nrf52832")] + pub fn from_radio(radio: &pac::radio::RegisterBlock) -> Self { + let mut value = Self::empty(); + if radio.events_ready.read().bits() == 1 { + value |= Self::READY; + } + if radio.events_address.read().bits() == 1 { + value |= Self::ADDRESS; + } + if radio.events_payload.read().bits() == 1 { + value |= Self::PAYLOAD; + } + if radio.events_end.read().bits() == 1 { + value |= Self::END; + } + if radio.events_disabled.read().bits() == 1 { + value |= Self::DISABLED; + } + if radio.events_devmatch.read().bits() == 1 { + value |= Self::DEV_MATCH; + } + if radio.events_devmiss.read().bits() == 1 { + value |= Self::DEV_MISS; + } + if radio.events_rssiend.read().bits() == 1 { + value |= Self::RSSI_END; + } + if radio.events_bcmatch.read().bits() == 1 { + value |= Self::BC_MATCH; + } + if radio.events_crcok.read().bits() == 1 { + value |= Self::CRC_OK; + } + if radio.events_crcerror.read().bits() == 1 { + value |= Self::CRC_ERROR; + } + value + } + + /// Read events from radio, mask with set interrupts + pub fn from_radio_masked(radio: &pac::radio::RegisterBlock) -> Self { + Self::from_radio(radio) & Self::from_bits_truncate(radio.intenset.read().bits()) + } +} + +#[cfg(feature = "defmt")] +impl defmt::Format for Event { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!( + fmt, + "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", + if self.contains(Self::READY) { "RD" } else { "__" }, + if self.contains(Self::ADDRESS) { "AD" } else { "__" }, + if self.contains(Self::PAYLOAD) { "PL" } else { "__" }, + if self.contains(Self::END) { " E" } else { "__" }, + if self.contains(Self::DISABLED) { "DI" } else { "__" }, + if self.contains(Self::DEV_MATCH) { "D+" } else { "__" }, + if self.contains(Self::DEV_MISS) { "D-" } else { "__" }, + if self.contains(Self::RSSI_END) { "RE" } else { "__" }, + if self.contains(Self::BC_MATCH) { "CM" } else { "__" }, + if self.contains(Self::CRC_OK) { "CO" } else { "__" }, + if self.contains(Self::CRC_ERROR) { "CE" } else { "__" }, + if self.contains(Self::FRAME_START) { "FS" } else { "__" }, + if self.contains(Self::ED_END) { "EE" } else { "__" }, + if self.contains(Self::ED_STOPPED) { "ES" } else { "__" }, + if self.contains(Self::CCA_IDLE) { "CI" } else { "__" }, + if self.contains(Self::CCA_BUSY) { "CB" } else { "__" }, + if self.contains(Self::CCA_STOPPED) { "CS" } else { "__" }, + if self.contains(Self::RATE_BOOST) { "RB" } else { "__" }, + if self.contains(Self::TX_READY) { "TX" } else { "__" }, + if self.contains(Self::RX_READY) { "RX" } else { "__" }, + if self.contains(Self::MHR_MATCH) { "MM" } else { "__" }, + if self.contains(Self::SYNC) { "SY" } else { "__" }, + if self.contains(Self::PHY_END) { "PE" } else { "__" }, + if self.contains(Self::CTE_PRESENT) { "CP" } else { "__" }, + ) + } +} + +impl core::fmt::Display for Event { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + fmt, + "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", + if self.contains(Self::READY) { "RD" } else { "__" }, + if self.contains(Self::ADDRESS) { "AD" } else { "__" }, + if self.contains(Self::PAYLOAD) { "PL" } else { "__" }, + if self.contains(Self::END) { " E" } else { "__" }, + if self.contains(Self::DISABLED) { "DI" } else { "__" }, + if self.contains(Self::DEV_MATCH) { "D+" } else { "__" }, + if self.contains(Self::DEV_MISS) { "D-" } else { "__" }, + if self.contains(Self::RSSI_END) { "RE" } else { "__" }, + if self.contains(Self::BC_MATCH) { "CM" } else { "__" }, + if self.contains(Self::CRC_OK) { "CO" } else { "__" }, + if self.contains(Self::CRC_ERROR) { "CE" } else { "__" }, + if self.contains(Self::FRAME_START) { "FS" } else { "__" }, + if self.contains(Self::ED_END) { "EE" } else { "__" }, + if self.contains(Self::ED_STOPPED) { "ES" } else { "__" }, + if self.contains(Self::CCA_IDLE) { "CI" } else { "__" }, + if self.contains(Self::CCA_BUSY) { "CB" } else { "__" }, + if self.contains(Self::CCA_STOPPED) { "CS" } else { "__" }, + if self.contains(Self::RATE_BOOST) { "RB" } else { "__" }, + if self.contains(Self::TX_READY) { "TX" } else { "__" }, + if self.contains(Self::RX_READY) { "RX" } else { "__" }, + if self.contains(Self::MHR_MATCH) { "MM" } else { "__" }, + if self.contains(Self::SYNC) { "SY" } else { "__" }, + if self.contains(Self::PHY_END) { "PE" } else { "__" }, + if self.contains(Self::CTE_PRESENT) { "CP" } else { "__" }, + ) + } +} diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs new file mode 100644 index 000000000..4d7949cb3 --- /dev/null +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -0,0 +1,573 @@ +//! IEEE 802.15.4 radio + +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::Poll; + +use super::{Error, Event, Instance, InterruptHandler}; +use crate::{ + interrupt::{self, typelevel::Interrupt}, + pac, Peripheral, +}; +use pac::radio::{state::STATE_A as RadioState, txpower::TXPOWER_A as TxPower}; + +use embassy_hal_internal::drop::OnDrop; +use embassy_hal_internal::{into_ref, PeripheralRef}; + +/// Default Start of Frame Delimiter = `0xA7` (IEEE compliant) +pub const DEFAULT_SFD: u8 = 0xA7; + +// TODO expose the other variants in `pac::CCAMODE_A` +/// Clear Channel Assessment method +pub enum Cca { + /// Carrier sense + CarrierSense, + /// Energy Detection / Energy Above Threshold + EnergyDetection { + /// Energy measurements above this value mean that the channel is assumed to be busy. + /// Note the measurement range is 0..0xFF - where 0 means that the received power was + /// less than 10 dB above the selected receiver sensitivity. This value is not given in dBm, + /// but can be converted. See the nrf52840 Product Specification Section 6.20.12.4 + /// for details. + ed_threshold: u8, + }, +} + +fn get_state(radio: &pac::radio::RegisterBlock) -> RadioState { + match radio.state.read().state().variant() { + Some(state) => state, + None => unreachable!(), + } +} + +fn trace_state(state: RadioState) { + match state { + RadioState::DISABLED => trace!("radio:state:DISABLED"), + RadioState::RX_RU => trace!("radio:state:RX_RU"), + RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"), + RadioState::RX => trace!("radio:state:RX"), + RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"), + RadioState::TX_RU => trace!("radio:state:TX_RU"), + RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"), + RadioState::TX => trace!("radio:state:TX"), + RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"), + } +} + +/// Radio driver. +pub struct Radio<'d, T: Instance> { + _p: PeripheralRef<'d, T>, + needs_enable: bool, +} + +impl<'d, T: Instance> Radio<'d, T> { + /// Create a new radio driver. + pub fn new( + radio: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + into_ref!(radio); + + let r = T::regs(); + + // Disable and enable to reset peripheral + r.power.write(|w| w.power().disabled()); + r.power.write(|w| w.power().enabled()); + + // Enable 802.15.4 mode + r.mode.write(|w| w.mode().ieee802154_250kbit()); + // Configure CRC skip address + r.crccnf.write(|w| w.len().two().skipaddr().ieee802154()); + unsafe { + // Configure CRC polynomial and init + r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021)); + r.crcinit.write(|w| w.crcinit().bits(0)); + // Configure packet layout + // 8-bit on air length + // S0 length, zero bytes + // S1 length, zero bytes + // S1 included in RAM if S1 length > 0, No. + // Code Indicator length, 0 + // Preamble length 32-bit zero + // Exclude CRC + // No TERM field + r.pcnf0.write(|w| { + w.lflen() + .bits(8) + .s0len() + .clear_bit() + .s1len() + .bits(0) + .s1incl() + .clear_bit() + .cilen() + .bits(0) + .plen() + ._32bit_zero() + .crcinc() + .include() + }); + r.pcnf1.write(|w| { + w.maxlen() + .bits(Packet::MAX_PSDU_LEN) + .statlen() + .bits(0) + .balen() + .bits(0) + .endian() + .clear_bit() + .whiteen() + .clear_bit() + }); + } + + // Enable NVIC interrupt + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + let mut radio = Self { + _p: radio, + needs_enable: false, + }; + + radio.set_sfd(DEFAULT_SFD); + radio.set_transmission_power(0); + radio.set_channel(11); + radio.set_cca(Cca::CarrierSense); + + radio + } + + /// Changes the radio channel + pub fn set_channel(&mut self, channel: u8) { + let r = T::regs(); + if channel < 11 || channel > 26 { + panic!("Bad 802.15.4 channel"); + } + let frequency_offset = (channel - 10) * 5; + self.needs_enable = true; + r.frequency + .write(|w| unsafe { w.frequency().bits(frequency_offset).map().default() }); + } + + /// Changes the Clear Channel Assessment method + pub fn set_cca(&mut self, cca: Cca) { + let r = T::regs(); + self.needs_enable = true; + match cca { + Cca::CarrierSense => r.ccactrl.write(|w| w.ccamode().carrier_mode()), + Cca::EnergyDetection { ed_threshold } => { + // "[ED] is enabled by first configuring the field CCAMODE=EdMode in CCACTRL + // and writing the CCAEDTHRES field to a chosen value." + r.ccactrl + .write(|w| unsafe { w.ccamode().ed_mode().ccaedthres().bits(ed_threshold) }); + } + } + } + + /// Changes the Start of Frame Delimiter + pub fn set_sfd(&mut self, sfd: u8) { + let r = T::regs(); + r.sfd.write(|w| unsafe { w.sfd().bits(sfd) }); + } + + /// Clear interrupts + pub fn clear_all_interrupts(&mut self) { + let r = T::regs(); + r.intenclr.write(|w| unsafe { w.bits(0xffff_ffff) }); + } + + /// Changes the radio transmission power + pub fn set_transmission_power(&mut self, power: i8) { + let r = T::regs(); + self.needs_enable = true; + + let tx_power: TxPower = match power { + 8 => TxPower::POS8D_BM, + 7 => TxPower::POS7D_BM, + 6 => TxPower::POS6D_BM, + 5 => TxPower::POS5D_BM, + 4 => TxPower::POS4D_BM, + 3 => TxPower::POS3D_BM, + 2 => TxPower::POS2D_BM, + 0 => TxPower::_0D_BM, + -4 => TxPower::NEG4D_BM, + -8 => TxPower::NEG8D_BM, + -12 => TxPower::NEG12D_BM, + -16 => TxPower::NEG16D_BM, + -20 => TxPower::NEG20D_BM, + -30 => TxPower::NEG30D_BM, + -40 => TxPower::NEG40D_BM, + _ => panic!("Invalid transmission power value"), + }; + + r.txpower.write(|w| w.txpower().variant(tx_power)); + } + + /// Waits until the radio state matches the given `state` + fn wait_for_radio_state(&self, state: RadioState) { + while self.state() != state {} + } + + fn state(&self) -> RadioState { + let r = T::regs(); + match r.state.read().state().variant() { + Some(state) => state, + None => unreachable!(), + } + } + + fn trace_state(&self) { + trace_state(self.state()); + } + + /// Moves the radio from any state to the DISABLED state + fn disable(&mut self) { + let r = T::regs(); + // See figure 110 in nRF52840-PS + loop { + match self.state() { + RadioState::DISABLED => return, + + RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => { + r.tasks_disable.write(|w| w.tasks_disable().set_bit()); + + self.wait_for_radio_state(RadioState::DISABLED); + return; + } + + // ramping down + RadioState::RX_DISABLE | RadioState::TX_DISABLE => { + self.wait_for_radio_state(RadioState::DISABLED); + return; + } + + // cancel ongoing transfer or ongoing CCA + RadioState::RX => { + r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit()); + r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + self.wait_for_radio_state(RadioState::RX_IDLE); + } + RadioState::TX => { + r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + self.wait_for_radio_state(RadioState::TX_IDLE); + } + } + } + } + + fn set_buffer(&mut self, buffer: &[u8]) { + let r = T::regs(); + r.packetptr.write(|w| unsafe { w.bits(buffer.as_ptr() as u32) }); + } + + /// Moves the radio to the RXIDLE state + fn receive_prepare(&mut self) { + let state = self.state(); + + let disable = match state { + RadioState::DISABLED => false, + RadioState::RX_DISABLE => true, + RadioState::TX_DISABLE => true, + RadioState::RX_IDLE => self.needs_enable, + // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE + RadioState::TX_IDLE => true, + _ => unreachable!(), + }; + if disable { + trace!("Receive Setup"); + self.trace_state(); + self.disable(); + } + self.needs_enable = false; + } + + fn receive_start(&mut self, packet: &mut Packet) { + // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's + // allocated in RAM + let r = T::regs(); + + // clear related events + r.events_framestart.reset(); + r.events_ccabusy.reset(); + r.events_phyend.reset(); + + self.receive_prepare(); + + // Configure shortcuts + // + // The radio goes through following states when receiving a 802.15.4 packet + // + // enable RX → ramp up RX → RX idle → Receive → end (PHYEND) + r.shorts.write(|w| w.rxready_start().enabled()); + + // set up RX buffer + self.set_buffer(packet.buffer.as_mut()); + + // start transfer + dma_start_fence(); + + match self.state() { + // Re-start receiver + RadioState::RX_IDLE => r.tasks_start.write(|w| w.tasks_start().set_bit()), + // Enable receiver + _ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()), + } + } + + fn receive_cancel() { + let r = T::regs(); + r.shorts.reset(); + if r.events_framestart.read().events_framestart().bit_is_set() { + // TODO: Is there a way to finish receiving this frame + trace!("EVENTS {}", Event::from_radio(r)); + } + r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + loop { + match get_state(r) { + RadioState::DISABLED | RadioState::RX_IDLE => break, + _ => (), + } + } + // DMA transfer may have been in progress so synchronize with its memory operations + dma_end_fence(); + } + + /// Receives one radio packet and copies its contents into the given `packet` buffer + /// + /// This methods returns the `Ok` variant if the CRC included the packet was successfully + /// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet` + /// will be updated with the received packet's data + pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), u16> { + let s = T::state(); + let r = T::regs(); + + // Start the read + self.receive_start(packet); + + let dropper = OnDrop::new(|| Self::receive_cancel()); + + self.clear_all_interrupts(); + // wait until we have received something + core::future::poll_fn(|cx| { + s.event_waker.register(cx.waker()); + + if r.events_phyend.read().events_phyend().bit_is_set() { + r.events_phyend.reset(); + trace!("RX done poll"); + return Poll::Ready(()); + } else { + r.intenset.write(|w| w.phyend().set()); + }; + + Poll::Pending + }) + .await; + + dma_end_fence(); + dropper.defuse(); + + let crc = r.rxcrc.read().rxcrc().bits() as u16; + if r.crcstatus.read().crcstatus().bit_is_set() { + Ok(()) + } else { + Err(crc) + } + } + + /// Tries to send the given `packet` + /// + /// This method performs Clear Channel Assessment (CCA) first and sends the `packet` only if the + /// channel is observed to be *clear* (no transmission is currently ongoing), otherwise no + /// packet is transmitted and the `Err` variant is returned + /// + /// NOTE this method will *not* modify the `packet` argument. The mutable reference is used to + /// ensure the `packet` buffer is allocated in RAM, which is required by the RADIO peripheral + // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's + // allocated in RAM + pub async fn try_send(&mut self, packet: &mut Packet) -> Result<(), Error> { + let s = T::state(); + let r = T::regs(); + + // clear related events + r.events_framestart.reset(); + r.events_ccabusy.reset(); + r.events_phyend.reset(); + + // enable radio to perform cca + self.receive_prepare(); + + /// transmit result + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum TransmitResult { + /// Success + Success, + /// Clear channel assessment reported channel in use + ChannelInUse, + } + + // Configure shortcuts + // + // The radio goes through following states when sending a 802.15.4 packet + // + // enable RX → ramp up RX → clear channel assessment (CCA) → CCA result + // CCA idle → enable TX → start TX → TX → end (PHYEND) → disabled + // + // CCA might end up in the event CCABUSY in which there will be no transmission + r.shorts.write(|w| { + w.rxready_ccastart() + .enabled() + .ccaidle_txen() + .enabled() + .txready_start() + .enabled() + .ccabusy_disable() + .enabled() + .phyend_disable() + .enabled() + }); + + // Set transmission buffer + self.set_buffer(packet.buffer.as_mut()); + + // the DMA transfer will start at some point after the following write operation so + // we place the compiler fence here + dma_start_fence(); + // start CCA. In case the channel is clear, the data at packetptr will be sent automatically + + match self.state() { + // Re-start receiver + RadioState::RX_IDLE => r.tasks_ccastart.write(|w| w.tasks_ccastart().set_bit()), + // Enable receiver + _ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()), + } + + self.clear_all_interrupts(); + let result = core::future::poll_fn(|cx| { + s.event_waker.register(cx.waker()); + + if r.events_phyend.read().events_phyend().bit_is_set() { + r.events_phyend.reset(); + r.events_ccabusy.reset(); + trace!("TX done poll"); + return Poll::Ready(TransmitResult::Success); + } else if r.events_ccabusy.read().events_ccabusy().bit_is_set() { + r.events_ccabusy.reset(); + trace!("TX no CCA"); + return Poll::Ready(TransmitResult::ChannelInUse); + } + + r.intenset.write(|w| w.phyend().set().ccabusy().set()); + + Poll::Pending + }) + .await; + + match result { + TransmitResult::Success => Ok(()), + TransmitResult::ChannelInUse => Err(Error::ChannelInUse), + } + } +} + +/// An IEEE 802.15.4 packet +/// +/// This `Packet` is a PHY layer packet. It's made up of the physical header (PHR) and the PSDU +/// (PHY service data unit). The PSDU of this `Packet` will always include the MAC level CRC, AKA +/// the FCS (Frame Control Sequence) -- the CRC is fully computed in hardware and automatically +/// appended on transmission and verified on reception. +/// +/// The API lets users modify the usable part (not the CRC) of the PSDU via the `deref` and +/// `copy_from_slice` methods. These methods will automatically update the PHR. +/// +/// See figure 119 in the Product Specification of the nRF52840 for more details +pub struct Packet { + buffer: [u8; Self::SIZE], +} + +// See figure 124 in nRF52840-PS +impl Packet { + // for indexing purposes + const PHY_HDR: usize = 0; + const DATA: core::ops::RangeFrom = 1..; + + /// Maximum amount of usable payload (CRC excluded) a single packet can contain, in bytes + pub const CAPACITY: u8 = 125; + const CRC: u8 = 2; // size of the CRC, which is *never* copied to / from RAM + const MAX_PSDU_LEN: u8 = Self::CAPACITY + Self::CRC; + const SIZE: usize = 1 /* PHR */ + Self::MAX_PSDU_LEN as usize; + + /// Returns an empty packet (length = 0) + pub fn new() -> Self { + let mut packet = Self { + buffer: [0; Self::SIZE], + }; + packet.set_len(0); + packet + } + + /// Fills the packet payload with given `src` data + /// + /// # Panics + /// + /// This function panics if `src` is larger than `Self::CAPACITY` + pub fn copy_from_slice(&mut self, src: &[u8]) { + assert!(src.len() <= Self::CAPACITY as usize); + let len = src.len() as u8; + self.buffer[Self::DATA][..len as usize].copy_from_slice(&src[..len.into()]); + self.set_len(len); + } + + /// Returns the size of this packet's payload + pub fn len(&self) -> u8 { + self.buffer[Self::PHY_HDR] - Self::CRC + } + + /// Changes the size of the packet's payload + /// + /// # Panics + /// + /// This function panics if `len` is larger than `Self::CAPACITY` + pub fn set_len(&mut self, len: u8) { + assert!(len <= Self::CAPACITY); + self.buffer[Self::PHY_HDR] = len + Self::CRC; + } + + /// Returns the LQI (Link Quality Indicator) of the received packet + /// + /// Note that the LQI is stored in the `Packet`'s internal buffer by the hardware so the value + /// returned by this method is only valid after a `Radio.recv` operation. Operations that + /// modify the `Packet`, like `copy_from_slice` or `set_len`+`deref_mut`, will overwrite the + /// stored LQI value. + /// + /// Also note that the hardware will *not* compute a LQI for packets smaller than 3 bytes so + /// this method will return an invalid value for those packets. + pub fn lqi(&self) -> u8 { + self.buffer[1 /* PHY_HDR */ + self.len() as usize /* data */] + } +} + +impl core::ops::Deref for Packet { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + &self.buffer[Self::DATA][..self.len() as usize] + } +} + +impl core::ops::DerefMut for Packet { + fn deref_mut(&mut self) -> &mut [u8] { + let len = self.len(); + &mut self.buffer[Self::DATA][..len as usize] + } +} + +/// NOTE must be followed by a volatile write operation +fn dma_start_fence() { + compiler_fence(Ordering::Release); +} + +/// NOTE must be preceded by a volatile read operation +fn dma_end_fence() { + compiler_fence(Ordering::Acquire); +} diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 03f967f87..430078e8a 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -7,11 +7,32 @@ /// Bluetooth Low Energy Radio driver. pub mod ble; +mod event; +#[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "_nrf5340-net"))] +/// IEEE 802.15.4 +pub mod ieee802154; + +pub use event::Event; use core::marker::PhantomData; use crate::{interrupt, pac, Peripheral}; +/// RADIO error. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// Buffer was too long. + BufferTooLong, + /// Buffer was too short. + BufferTooShort, + /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. + BufferNotInRAM, + /// Clear channel assessment reported channel in use + ChannelInUse, +} + /// Interrupt handler pub struct InterruptHandler { _phantom: PhantomData, @@ -21,11 +42,10 @@ impl interrupt::typelevel::Handler for InterruptHandl unsafe fn on_interrupt() { let r = T::regs(); let s = T::state(); - - if r.events_end.read().events_end().bit_is_set() { - s.end_waker.wake(); - r.intenclr.write(|w| w.end().clear()); - } + let events = Event::from_radio_masked(r); + // clear active interrupts + r.intenclr.write(|w| w.bits(events.bits())); + s.event_waker.wake(); } } @@ -34,12 +54,12 @@ pub(crate) mod sealed { pub struct State { /// end packet transmission or reception - pub end_waker: AtomicWaker, + pub event_waker: AtomicWaker, } impl State { pub const fn new() -> Self { Self { - end_waker: AtomicWaker::new(), + event_waker: AtomicWaker::new(), } } } From 35febae570ef6b89eb52948ee13684754b23da4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Thu, 29 Feb 2024 01:31:07 +0100 Subject: [PATCH 600/760] Fixed missing nrf52840 in Event --- embassy-nrf/src/radio/event.rs | 29 ++++++++++++++++++++++++++--- embassy-nrf/src/radio/ieee802154.rs | 2 +- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/radio/event.rs b/embassy-nrf/src/radio/event.rs index 11056b4d8..8fb0958d5 100644 --- a/embassy-nrf/src/radio/event.rs +++ b/embassy-nrf/src/radio/event.rs @@ -97,6 +97,7 @@ impl Event { feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", + feature = "nrf52840", feature = "_nrf5340-net" ))] if radio.events_framestart.read().events_framestart().bit_is_set() { @@ -106,6 +107,7 @@ impl Event { feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", + feature = "nrf52840", feature = "_nrf5340-net" ))] if radio.events_edend.read().events_edend().bit_is_set() { @@ -115,20 +117,36 @@ impl Event { feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", + feature = "nrf52840", feature = "_nrf5340-net" ))] if radio.events_edstopped.read().events_edstopped().bit_is_set() { value |= Self::ED_STOPPED; } - #[cfg(any(feature = "nrf52820", feature = "nrf52833", feature = "_nrf5340-net"))] + #[cfg(any( + feature = "nrf52820", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340-net" + ))] if radio.events_ccaidle.read().events_ccaidle().bit_is_set() { value |= Self::CCA_IDLE; } - #[cfg(any(feature = "nrf52820", feature = "nrf52833", feature = "_nrf5340-net"))] + #[cfg(any( + feature = "nrf52820", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340-net" + ))] if radio.events_ccabusy.read().events_ccabusy().bit_is_set() { value |= Self::CCA_BUSY; } - #[cfg(any(feature = "nrf52820", feature = "nrf52833", feature = "_nrf5340-net"))] + #[cfg(any( + feature = "nrf52820", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340-net" + ))] if radio.events_ccastopped.read().events_ccastopped().bit_is_set() { value |= Self::CCA_STOPPED; } @@ -136,6 +154,7 @@ impl Event { feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", + feature = "nrf52840", feature = "_nrf5340-net" ))] if radio.events_rateboost.read().events_rateboost().bit_is_set() { @@ -146,6 +165,7 @@ impl Event { feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", + feature = "nrf52840", feature = "_nrf5340-net" ))] if radio.events_txready.read().events_txready().bit_is_set() { @@ -156,6 +176,7 @@ impl Event { feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", + feature = "nrf52840", feature = "_nrf5340-net" ))] if radio.events_rxready.read().events_rxready().bit_is_set() { @@ -165,6 +186,7 @@ impl Event { feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", + feature = "nrf52840", feature = "_nrf5340-net" ))] if radio.events_mhrmatch.read().events_mhrmatch().bit_is_set() { @@ -179,6 +201,7 @@ impl Event { feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", + feature = "nrf52840", feature = "_nrf5340-net" ))] if radio.events_phyend.read().events_phyend().bit_is_set() { diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 4d7949cb3..adc6f8aaa 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -164,7 +164,7 @@ impl<'d, T: Instance> Radio<'d, T> { } } - /// Changes the Start of Frame Delimiter + /// Changes the Start of Frame Delimiter (SFD) pub fn set_sfd(&mut self, sfd: u8) { let r = T::regs(); r.sfd.write(|w| unsafe { w.sfd().bits(sfd) }); From f0753998bc9379bdb19ef4fcddf96ff19487a52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Thu, 29 Feb 2024 02:02:01 +0100 Subject: [PATCH 601/760] Clear all interrupts --- embassy-nrf/src/radio/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 430078e8a..914e6c438 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -42,9 +42,8 @@ impl interrupt::typelevel::Handler for InterruptHandl unsafe fn on_interrupt() { let r = T::regs(); let s = T::state(); - let events = Event::from_radio_masked(r); - // clear active interrupts - r.intenclr.write(|w| w.bits(events.bits())); + // clear all interrupts + r.intenclr.write(|w| w.bits(0xffff_ffff)); s.event_waker.wake(); } } From 8eac5d07f65e642ca4ad763ffe90bad97803089c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Thu, 29 Feb 2024 09:50:28 +0100 Subject: [PATCH 602/760] Remove Event, which was mostly used for debugging --- embassy-nrf/src/radio/event.rs | 333 ---------------------------- embassy-nrf/src/radio/ieee802154.rs | 3 +- embassy-nrf/src/radio/mod.rs | 3 - 3 files changed, 1 insertion(+), 338 deletions(-) delete mode 100644 embassy-nrf/src/radio/event.rs diff --git a/embassy-nrf/src/radio/event.rs b/embassy-nrf/src/radio/event.rs deleted file mode 100644 index 8fb0958d5..000000000 --- a/embassy-nrf/src/radio/event.rs +++ /dev/null @@ -1,333 +0,0 @@ -use crate::pac; -use bitflags; - -bitflags::bitflags! { - /// Event as bit flags - pub struct Event : u32 { - /// Radio ready - const READY = 1u32 << 0; - /// Address operation done - const ADDRESS = 1u32 << 1; - /// Payload operation done - const PAYLOAD = 1u32 << 2; - /// Packet operation done - const END = 1u32 << 3; - /// Radio has been disabled - const DISABLED = 1u32 << 4; - /// Device address match in last received packet - const DEV_MATCH = 1u32 << 5; - /// No device address match in last received packet - const DEV_MISS = 1u32 << 6; - /// RSSI sampling complete - const RSSI_END = 1u32 << 7; - /// Bit counter reached target - const BC_MATCH = 1u32 << 10; - /// CRC ok in last received packet - const CRC_OK = 1u32 << 12; - /// CRC error in last received packet - const CRC_ERROR = 1u32 << 13; - /// IEEE 802.15.4 length field received - const FRAME_START = 1u32 << 14; - /// Sampling of energy detect complete - const ED_END = 1u32 << 15; - /// Sampling of energy detect stopped - const ED_STOPPED = 1u32 << 16; - /// Wireless medium in idle, ready to sent - const CCA_IDLE = 1u32 << 17; - /// Wireless medium busy, do not send - const CCA_BUSY = 1u32 << 18; - /// Clear channel assessment stopped - const CCA_STOPPED = 1u32 << 19; - /// BLE LR rate boost received - const RATE_BOOST = 1u32 << 20; - /// Radio has ramped up transmitter - const TX_READY = 1u32 << 21; - /// Radio has ramped up receiver - const RX_READY = 1u32 << 22; - /// MAC header match found - const MHR_MATCH = 1u32 << 23; - /// Preamble received, possible false triggering - const SYNC = 1u32 << 26; - /// Last bit sent / received - const PHY_END = 1u32 << 27; - /// Continuous tone extension is present - const CTE_PRESENT = 1u32 << 28; - } -} - -impl Event { - /// Read events from radio - #[cfg(not(feature = "nrf52832"))] - pub fn from_radio(radio: &pac::radio::RegisterBlock) -> Self { - let mut value = Self::empty(); - if radio.events_ready.read().events_ready().bit_is_set() { - value |= Self::READY; - } - if radio.events_address.read().events_address().bit_is_set() { - value |= Self::ADDRESS; - } - if radio.events_payload.read().events_payload().bit_is_set() { - value |= Self::PAYLOAD; - } - if radio.events_end.read().events_end().bit_is_set() { - value |= Self::END; - } - if radio.events_disabled.read().events_disabled().bit_is_set() { - value |= Self::DISABLED; - } - if radio.events_devmatch.read().events_devmatch().bit_is_set() { - value |= Self::DEV_MATCH; - } - if radio.events_devmiss.read().events_devmiss().bit_is_set() { - value |= Self::DEV_MISS; - } - if radio.events_rssiend.read().events_rssiend().bit_is_set() { - value |= Self::RSSI_END; - } - if radio.events_bcmatch.read().events_bcmatch().bit_is_set() { - value |= Self::BC_MATCH; - } - if radio.events_crcok.read().events_crcok().bit_is_set() { - value |= Self::CRC_OK; - } - if radio.events_crcerror.read().events_crcerror().bit_is_set() { - value |= Self::CRC_ERROR; - } - #[cfg(any( - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_framestart.read().events_framestart().bit_is_set() { - value |= Self::FRAME_START; - } - #[cfg(any( - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_edend.read().events_edend().bit_is_set() { - value |= Self::ED_END; - } - #[cfg(any( - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_edstopped.read().events_edstopped().bit_is_set() { - value |= Self::ED_STOPPED; - } - #[cfg(any( - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_ccaidle.read().events_ccaidle().bit_is_set() { - value |= Self::CCA_IDLE; - } - #[cfg(any( - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_ccabusy.read().events_ccabusy().bit_is_set() { - value |= Self::CCA_BUSY; - } - #[cfg(any( - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_ccastopped.read().events_ccastopped().bit_is_set() { - value |= Self::CCA_STOPPED; - } - #[cfg(any( - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_rateboost.read().events_rateboost().bit_is_set() { - value |= Self::RATE_BOOST; - } - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_txready.read().events_txready().bit_is_set() { - value |= Self::TX_READY; - } - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_rxready.read().events_rxready().bit_is_set() { - value |= Self::RX_READY; - } - #[cfg(any( - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_mhrmatch.read().events_mhrmatch().bit_is_set() { - value |= Self::MHR_MATCH; - } - #[cfg(any(feature = "nrf52820", feature = "nrf52833", feature = "_nrf5340-net"))] - if radio.events_sync.read().events_sync().bit_is_set() { - value |= Self::SYNC; - } - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - if radio.events_phyend.read().events_phyend().bit_is_set() { - value |= Self::PHY_END; - } - #[cfg(any( - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "_nrf5340-net" - ))] - if radio.events_ctepresent.read().events_ctepresent().bit_is_set() { - value |= Self::CTE_PRESENT; - } - value - } - // The nRF52832 SVD probably is a bit broken - /// Read events from radio - #[cfg(feature = "nrf52832")] - pub fn from_radio(radio: &pac::radio::RegisterBlock) -> Self { - let mut value = Self::empty(); - if radio.events_ready.read().bits() == 1 { - value |= Self::READY; - } - if radio.events_address.read().bits() == 1 { - value |= Self::ADDRESS; - } - if radio.events_payload.read().bits() == 1 { - value |= Self::PAYLOAD; - } - if radio.events_end.read().bits() == 1 { - value |= Self::END; - } - if radio.events_disabled.read().bits() == 1 { - value |= Self::DISABLED; - } - if radio.events_devmatch.read().bits() == 1 { - value |= Self::DEV_MATCH; - } - if radio.events_devmiss.read().bits() == 1 { - value |= Self::DEV_MISS; - } - if radio.events_rssiend.read().bits() == 1 { - value |= Self::RSSI_END; - } - if radio.events_bcmatch.read().bits() == 1 { - value |= Self::BC_MATCH; - } - if radio.events_crcok.read().bits() == 1 { - value |= Self::CRC_OK; - } - if radio.events_crcerror.read().bits() == 1 { - value |= Self::CRC_ERROR; - } - value - } - - /// Read events from radio, mask with set interrupts - pub fn from_radio_masked(radio: &pac::radio::RegisterBlock) -> Self { - Self::from_radio(radio) & Self::from_bits_truncate(radio.intenset.read().bits()) - } -} - -#[cfg(feature = "defmt")] -impl defmt::Format for Event { - fn format(&self, fmt: defmt::Formatter) { - defmt::write!( - fmt, - "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", - if self.contains(Self::READY) { "RD" } else { "__" }, - if self.contains(Self::ADDRESS) { "AD" } else { "__" }, - if self.contains(Self::PAYLOAD) { "PL" } else { "__" }, - if self.contains(Self::END) { " E" } else { "__" }, - if self.contains(Self::DISABLED) { "DI" } else { "__" }, - if self.contains(Self::DEV_MATCH) { "D+" } else { "__" }, - if self.contains(Self::DEV_MISS) { "D-" } else { "__" }, - if self.contains(Self::RSSI_END) { "RE" } else { "__" }, - if self.contains(Self::BC_MATCH) { "CM" } else { "__" }, - if self.contains(Self::CRC_OK) { "CO" } else { "__" }, - if self.contains(Self::CRC_ERROR) { "CE" } else { "__" }, - if self.contains(Self::FRAME_START) { "FS" } else { "__" }, - if self.contains(Self::ED_END) { "EE" } else { "__" }, - if self.contains(Self::ED_STOPPED) { "ES" } else { "__" }, - if self.contains(Self::CCA_IDLE) { "CI" } else { "__" }, - if self.contains(Self::CCA_BUSY) { "CB" } else { "__" }, - if self.contains(Self::CCA_STOPPED) { "CS" } else { "__" }, - if self.contains(Self::RATE_BOOST) { "RB" } else { "__" }, - if self.contains(Self::TX_READY) { "TX" } else { "__" }, - if self.contains(Self::RX_READY) { "RX" } else { "__" }, - if self.contains(Self::MHR_MATCH) { "MM" } else { "__" }, - if self.contains(Self::SYNC) { "SY" } else { "__" }, - if self.contains(Self::PHY_END) { "PE" } else { "__" }, - if self.contains(Self::CTE_PRESENT) { "CP" } else { "__" }, - ) - } -} - -impl core::fmt::Display for Event { - fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!( - fmt, - "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", - if self.contains(Self::READY) { "RD" } else { "__" }, - if self.contains(Self::ADDRESS) { "AD" } else { "__" }, - if self.contains(Self::PAYLOAD) { "PL" } else { "__" }, - if self.contains(Self::END) { " E" } else { "__" }, - if self.contains(Self::DISABLED) { "DI" } else { "__" }, - if self.contains(Self::DEV_MATCH) { "D+" } else { "__" }, - if self.contains(Self::DEV_MISS) { "D-" } else { "__" }, - if self.contains(Self::RSSI_END) { "RE" } else { "__" }, - if self.contains(Self::BC_MATCH) { "CM" } else { "__" }, - if self.contains(Self::CRC_OK) { "CO" } else { "__" }, - if self.contains(Self::CRC_ERROR) { "CE" } else { "__" }, - if self.contains(Self::FRAME_START) { "FS" } else { "__" }, - if self.contains(Self::ED_END) { "EE" } else { "__" }, - if self.contains(Self::ED_STOPPED) { "ES" } else { "__" }, - if self.contains(Self::CCA_IDLE) { "CI" } else { "__" }, - if self.contains(Self::CCA_BUSY) { "CB" } else { "__" }, - if self.contains(Self::CCA_STOPPED) { "CS" } else { "__" }, - if self.contains(Self::RATE_BOOST) { "RB" } else { "__" }, - if self.contains(Self::TX_READY) { "TX" } else { "__" }, - if self.contains(Self::RX_READY) { "RX" } else { "__" }, - if self.contains(Self::MHR_MATCH) { "MM" } else { "__" }, - if self.contains(Self::SYNC) { "SY" } else { "__" }, - if self.contains(Self::PHY_END) { "PE" } else { "__" }, - if self.contains(Self::CTE_PRESENT) { "CP" } else { "__" }, - ) - } -} diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index adc6f8aaa..32951421b 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -3,7 +3,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; -use super::{Error, Event, Instance, InterruptHandler}; +use super::{Error, Instance, InterruptHandler}; use crate::{ interrupt::{self, typelevel::Interrupt}, pac, Peripheral, @@ -319,7 +319,6 @@ impl<'d, T: Instance> Radio<'d, T> { r.shorts.reset(); if r.events_framestart.read().events_framestart().bit_is_set() { // TODO: Is there a way to finish receiving this frame - trace!("EVENTS {}", Event::from_radio(r)); } r.tasks_stop.write(|w| w.tasks_stop().set_bit()); loop { diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 914e6c438..9b3a6cf49 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -7,13 +7,10 @@ /// Bluetooth Low Energy Radio driver. pub mod ble; -mod event; #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "_nrf5340-net"))] /// IEEE 802.15.4 pub mod ieee802154; -pub use event::Event; - use core::marker::PhantomData; use crate::{interrupt, pac, Peripheral}; From e954d1716a229bae94cd4739d1349a487bdaa8ae Mon Sep 17 00:00:00 2001 From: Andreas Schmidt Date: Thu, 29 Feb 2024 20:27:35 +0100 Subject: [PATCH 603/760] docs: update basic example references in basic_application.adoc --- docs/modules/ROOT/pages/basic_application.adoc | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc index 95792d5a0..02b8981c9 100644 --- a/docs/modules/ROOT/pages/basic_application.adoc +++ b/docs/modules/ROOT/pages/basic_application.adoc @@ -17,15 +17,6 @@ The first thing you’ll notice are two attributes at the top of the file. These include::example$basic/src/main.rs[lines="1..2"] ---- -=== Rust Nightly - -The next declaration is a Rust Unstable feature, which means that Embassy requires Rust Nightly: - -[source,rust] ----- -include::example$basic/src/main.rs[lines="3"] ----- - === Dealing with errors Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal: @@ -41,7 +32,7 @@ After a bit of import declaration, the tasks run by the application should be de [source,rust] ---- -include::example$basic/src/main.rs[lines="12..20"] +include::example$basic/src/main.rs[lines="10..18"] ---- An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking. @@ -56,7 +47,7 @@ We then initialize the HAL with a default config, which gives us a `Peripherals` [source,rust] ---- -include::example$basic/src/main.rs[lines="22..-1"] +include::example$basic/src/main.rs[lines="20..-1"] ---- What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following: From c9cca3c007eb4b85c559f74655c6cb018d9e28f1 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:09:44 -0500 Subject: [PATCH 604/760] Fix H7 CRYP operation. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/cryp/mod.rs | 159 +++++++++++++++++++++------------- tests/stm32/Cargo.toml | 4 +- 3 files changed, 103 insertions(+), 64 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 08ccd35ae..460184920 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-4a0bcec33362449fb733c066936d25cbabab396a" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-4a0bcec33362449fb733c066936d25cbabab396a", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index bb64fa423..8f259520a 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1,5 +1,5 @@ //! Crypto Accelerator (CRYP) -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] use core::cmp::min; use core::marker::PhantomData; @@ -35,7 +35,7 @@ pub trait Cipher<'c> { fn init_phase(&self, _p: &pac::cryp::Cryp) {} /// Called prior to processing the last data block for cipher-specific operations. - fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction) -> [u32; 4] { + fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { return [0; 4]; } @@ -98,7 +98,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(0)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(0)); p.cr().modify(|w| w.set_algomode3(false)); @@ -140,7 +140,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(1)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(1)); p.cr().modify(|w| w.set_algomode3(false)); @@ -182,7 +182,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(2)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(2)); p.cr().modify(|w| w.set_algomode3(false)); @@ -223,7 +223,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(3)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(3)); p.cr().modify(|w| w.set_algomode3(false)); @@ -264,7 +264,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(7)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(7)); p.cr().modify(|w| w.set_algomode3(false)); @@ -278,7 +278,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(2)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(2)); p.cr().modify(|w| w.set_algomode3(false)); @@ -321,7 +321,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(7)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(7)); p.cr().modify(|w| w.set_algomode3(false)); @@ -335,7 +335,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(5)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(5)); p.cr().modify(|w| w.set_algomode3(false)); @@ -377,7 +377,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(6)); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { p.cr().modify(|w| w.set_algomode0(6)); p.cr().modify(|w| w.set_algomode3(false)); @@ -390,14 +390,14 @@ impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {} impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] ///AES-GCM Cipher Mode pub struct AesGcm<'c, const KEY_SIZE: usize> { iv: [u8; 16], key: &'c [u8; KEY_SIZE], } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> { /// Constucts a new AES-GCM cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { @@ -408,7 +408,7 @@ impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> { } } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { const BLOCK_SIZE: usize = AES_BLOCK_SIZE; @@ -431,7 +431,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { while p.cr().read().crypen() {} } - fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] { + #[cfg(cryp_v2)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. if dir == Direction::Encrypt { p.cr().modify(|w| w.set_crypen(false)); @@ -444,6 +445,14 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { [0; 4] } + #[cfg(cryp_v3)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_npblb(padding_len as u8)); + [0; 4] + } + + #[cfg(cryp_v2)] fn post_final_block( &self, p: &pac::cryp::Cryp, @@ -477,25 +486,25 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] /// AES-GMAC Cipher Mode pub struct AesGmac<'c, const KEY_SIZE: usize> { iv: [u8; 16], key: &'c [u8; KEY_SIZE], } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> { /// Constructs a new AES-GMAC cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { @@ -506,7 +515,7 @@ impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> { } } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { const BLOCK_SIZE: usize = AES_BLOCK_SIZE; @@ -529,7 +538,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { while p.cr().read().crypen() {} } - fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] { + #[cfg(cryp_v2)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. if dir == Direction::Encrypt { p.cr().modify(|w| w.set_crypen(false)); @@ -542,6 +552,14 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { [0; 4] } + #[cfg(cryp_v3)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_npblb(padding_len as u8)); + [0; 4] + } + + #[cfg(cryp_v2)] fn post_final_block( &self, p: &pac::cryp::Cryp, @@ -575,18 +593,18 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] /// AES-CCM Cipher Mode pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> { key: &'c [u8; KEY_SIZE], @@ -596,7 +614,7 @@ pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZ ctr: [u8; 16], } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> { /// Constructs a new AES-CCM cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self { @@ -660,7 +678,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Aes } } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> { @@ -699,7 +717,8 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip return &self.aad_header[0..self.aad_header_len]; } - fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] { + #[cfg(cryp_v2)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { //Handle special CCM partial block process. let mut temp1 = [0; 4]; if dir == Direction::Decrypt { @@ -717,6 +736,14 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip return temp1; } + #[cfg(cryp_v3)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_npblb(padding_len as u8)); + [0; 4] + } + + #[cfg(cryp_v2)] fn post_final_block( &self, p: &pac::cryp::Cryp, @@ -753,39 +780,39 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } } -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {} -#[cfg(cryp_v2)] +#[cfg(any(cryp_v2, cryp_v3))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {} #[allow(dead_code)] @@ -909,7 +936,7 @@ impl<'d, T: Instance> Cryp<'d, T> { ctx } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] /// Controls the header phase of cipher processing. /// This function is only valid for GCM, CCM, and GMAC modes. /// It only needs to be called if using one of these modes and there is associated data. @@ -1066,7 +1093,7 @@ impl<'d, T: Instance> Cryp<'d, T> { if !ctx.aad_complete && ctx.header_len > 0 { panic!("Additional associated data must be processed first!"); } else if !ctx.aad_complete { - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] { ctx.aad_complete = true; T::regs().cr().modify(|w| w.set_crypen(false)); @@ -1121,7 +1148,8 @@ impl<'d, T: Instance> Cryp<'d, T> { // Handle the final block, which is incomplete. if last_block_remainder > 0 { - let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir); + let padding_len = C::BLOCK_SIZE - last_block_remainder; + let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir, padding_len); let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; @@ -1162,7 +1190,7 @@ impl<'d, T: Instance> Cryp<'d, T> { self.store_context(ctx); } - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] /// This function only needs to be called for GCM, CCM, and GMAC modes to /// generate an authentication tag. pub fn finish_blocking< @@ -1184,10 +1212,21 @@ impl<'d, T: Instance> Cryp<'d, T> { let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32; let payloadlen2: u32 = (ctx.payload_len * 8) as u32; - T::regs().din().write_value(headerlen1.swap_bytes()); - T::regs().din().write_value(headerlen2.swap_bytes()); - T::regs().din().write_value(payloadlen1.swap_bytes()); - T::regs().din().write_value(payloadlen2.swap_bytes()); + #[cfg(cryp_v2)] + { + T::regs().din().write_value(headerlen1.swap_bytes()); + T::regs().din().write_value(headerlen2.swap_bytes()); + T::regs().din().write_value(payloadlen1.swap_bytes()); + T::regs().din().write_value(payloadlen2.swap_bytes()); + } + + #[cfg(cryp_v3)] + { + T::regs().din().write_value(headerlen1); + T::regs().din().write_value(headerlen2); + T::regs().din().write_value(payloadlen1); + T::regs().din().write_value(payloadlen2); + } while !T::regs().sr().read().ofne() {} @@ -1257,7 +1296,7 @@ impl<'d, T: Instance> Cryp<'d, T> { ctx.iv[2] = T::regs().init(1).ivlr().read(); ctx.iv[3] = T::regs().init(1).ivrr().read(); - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] for i in 0..8 { ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read(); ctx.csgcm[i] = T::regs().csgcmr(i).read(); @@ -1272,7 +1311,7 @@ impl<'d, T: Instance> Cryp<'d, T> { T::regs().init(1).ivlr().write_value(ctx.iv[2]); T::regs().init(1).ivrr().write_value(ctx.iv[3]); - #[cfg(cryp_v2)] + #[cfg(any(cryp_v2, cryp_v3))] for i in 0..8 { T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]); T::regs().csgcmr(i).write_value(ctx.csgcm[i]); diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bfe003a11..3d7db2025 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -10,7 +10,7 @@ stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"] stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"] stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] -stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] +stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng", "cryp"] stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] @@ -18,7 +18,7 @@ stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng" stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] -stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] +stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan", "cryp"] stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] From 27fac380cfe05439adbe4f0256765f906e403733 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:15:32 -0500 Subject: [PATCH 605/760] Remove CRYP from H7A3. --- tests/stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 3d7db2025..c5f605565 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -18,7 +18,7 @@ stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng" stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] -stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan", "cryp"] +stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] From 97e125872e707e96bf81cd8e601f92f0f9f688a1 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:18:25 -0500 Subject: [PATCH 606/760] Remove CRYP from F429. --- tests/stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index c5f605565..bfe003a11 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -10,7 +10,7 @@ stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"] stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"] stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] -stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng", "cryp"] +stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] From 4c0d63ce6188a340bd75388c3e772ba5d89ca8d4 Mon Sep 17 00:00:00 2001 From: Andreas Schmidt Date: Fri, 1 Mar 2024 10:13:59 +0100 Subject: [PATCH 607/760] docs: update broken reference in basic_application.adoc --- docs/modules/ROOT/pages/basic_application.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc index 02b8981c9..d5aad806d 100644 --- a/docs/modules/ROOT/pages/basic_application.adoc +++ b/docs/modules/ROOT/pages/basic_application.adoc @@ -23,7 +23,7 @@ Then, what follows are some declarations on how to deal with panics and faults. [source,rust] ---- -include::example$basic/src/main.rs[lines="10"] +include::example$basic/src/main.rs[lines="8"] ---- === Task declaration From 96af20cf5b1af90029bd5119c2f4918b844d9fc3 Mon Sep 17 00:00:00 2001 From: Siebe Claes Date: Fri, 1 Mar 2024 19:15:49 +0100 Subject: [PATCH 608/760] stm32: can: fd: Fix Frame is_extended() function --- embassy-stm32/src/can/frame.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index 00a441db6..9c293035d 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -206,7 +206,7 @@ impl embedded_can::Frame for ClassicFrame { fn is_extended(&self) -> bool { match self.can_header.id { embedded_can::Id::Extended(_) => true, - embedded_can::Id::Standard(_) => true, + embedded_can::Id::Standard(_) => false, } } fn is_remote_frame(&self) -> bool { @@ -369,7 +369,7 @@ impl embedded_can::Frame for FdFrame { fn is_extended(&self) -> bool { match self.can_header.id { embedded_can::Id::Extended(_) => true, - embedded_can::Id::Standard(_) => true, + embedded_can::Id::Standard(_) => false, } } fn is_remote_frame(&self) -> bool { From 95234cddbac6f21fce0f5df510d49816f343b87d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 26 Feb 2024 03:28:27 +0100 Subject: [PATCH 609/760] stm32: autogenerate mux config for all chips. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/build.rs | 315 +++++++++++++++---------- embassy-stm32/src/ipcc.rs | 19 +- embassy-stm32/src/rcc/c0.rs | 34 +-- embassy-stm32/src/rcc/f013.rs | 6 +- embassy-stm32/src/rcc/f247.rs | 10 +- embassy-stm32/src/rcc/g0.rs | 63 ++--- embassy-stm32/src/rcc/g4.rs | 78 ++---- embassy-stm32/src/rcc/h.rs | 72 +----- embassy-stm32/src/rcc/l.rs | 56 ++--- embassy-stm32/src/rcc/mod.rs | 4 +- embassy-stm32/src/rcc/u5.rs | 7 +- embassy-stm32/src/rcc/wba.rs | 13 +- embassy-stm32/src/usb_otg/usb.rs | 14 -- examples/stm32f334/src/bin/pwm.rs | 2 +- examples/stm32g0/src/bin/hf_timer.rs | 40 ++-- examples/stm32g0/src/bin/usb_serial.rs | 10 +- examples/stm32g4/src/bin/adc.rs | 29 ++- examples/stm32g4/src/bin/can.rs | 21 +- examples/stm32g4/src/bin/pll.rs | 1 + examples/stm32g4/src/bin/usb_serial.rs | 50 ++-- examples/stm32h5/src/bin/can.rs | 2 +- examples/stm32h5/src/bin/usb_serial.rs | 7 +- examples/stm32h7/src/bin/adc.rs | 2 +- examples/stm32h7/src/bin/can.rs | 2 +- examples/stm32h7/src/bin/dac.rs | 2 +- examples/stm32h7/src/bin/dac_dma.rs | 2 +- examples/stm32l4/src/bin/adc.rs | 14 +- tests/stm32/src/bin/fdcan.rs | 4 +- tests/stm32/src/common.rs | 47 ++-- 30 files changed, 412 insertions(+), 518 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 460184920..4bbd43c47 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-d7462d805ef05892531a83cd9ad60c9cba568d54" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-d7462d805ef05892531a83cd9ad60c9cba568d54", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 08c051956..84e8be25d 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -5,7 +5,9 @@ use std::{env, fs}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccKernelClock, StopMode, METADATA}; +use stm32_metapac::metadata::{ + MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA, +}; fn main() { let target = env::var("TARGET").unwrap(); @@ -374,12 +376,130 @@ fn main() { } } - let force_refcount = HashSet::from(["usart"]); - let mut refcount_statics = BTreeSet::new(); + struct ClockGen<'a> { + rcc_registers: &'a PeripheralRegisters, + chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>, + force_refcount: HashSet<&'a str>, - let mut clock_names = BTreeSet::new(); + refcount_statics: BTreeSet, + clock_names: BTreeSet, + muxes: BTreeSet<(Ident, Ident, Ident)>, + } - let mut rcc_cfgr_regs = BTreeSet::new(); + let mut clock_gen = ClockGen { + rcc_registers, + chained_muxes: HashMap::new(), + force_refcount: HashSet::from(["usart"]), + + refcount_statics: BTreeSet::new(), + clock_names: BTreeSet::new(), + muxes: BTreeSet::new(), + }; + if chip_name.starts_with("stm32h5") { + clock_gen.chained_muxes.insert( + "PER", + &PeripheralRccRegister { + register: "CCIPR5", + field: "PERSEL", + }, + ); + } + if chip_name.starts_with("stm32h7") { + clock_gen.chained_muxes.insert( + "PER", + &PeripheralRccRegister { + register: "D1CCIPR", + field: "PERSEL", + }, + ); + } + if chip_name.starts_with("stm32u5") { + clock_gen.chained_muxes.insert( + "ICLK", + &PeripheralRccRegister { + register: "CCIPR1", + field: "ICLKSEL", + }, + ); + } + if chip_name.starts_with("stm32wb") && !chip_name.starts_with("stm32wba") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "CCIPR", + field: "CLK48SEL", + }, + ); + } + if chip_name.starts_with("stm32f7") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "DCKCFGR2", + field: "CLK48SEL", + }, + ); + } + if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "DCKCFGR", + field: "CLK48SEL", + }, + ); + } + + impl<'a> ClockGen<'a> { + fn gen_clock(&mut self, name: &str) -> TokenStream { + let clock_name = format_ident!("{}", name.to_ascii_lowercase()); + self.clock_names.insert(name.to_ascii_lowercase()); + quote!( unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } ) + } + + fn gen_mux(&mut self, mux: &PeripheralRccRegister) -> TokenStream { + let ir = &self.rcc_registers.ir; + let fieldset_name = mux.register.to_ascii_lowercase(); + let fieldset = ir + .fieldsets + .iter() + .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name)) + .unwrap(); + let field_name = mux.field.to_ascii_lowercase(); + let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap(); + let enum_name = field.enumm.unwrap(); + let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap(); + + let fieldset_name = format_ident!("{}", fieldset_name); + let field_name = format_ident!("{}", field_name); + let enum_name = format_ident!("{}", enum_name); + + self.muxes + .insert((fieldset_name.clone(), field_name.clone(), enum_name.clone())); + + let mut match_arms = TokenStream::new(); + + for v in enumm.variants.iter().filter(|v| v.name != "DISABLE") { + let variant_name = format_ident!("{}", v.name); + let expr = if let Some(mux) = self.chained_muxes.get(&v.name) { + self.gen_mux(mux) + } else { + self.gen_clock(&v.name) + }; + match_arms.extend(quote! { + crate::pac::rcc::vals::#enum_name::#variant_name => #expr, + }); + } + + quote! { + match crate::pac::RCC.#fieldset_name().read().#field_name() { + #match_arms + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } + } + } for p in METADATA.peripherals { if !singletons.contains(&p.name.to_string()) { @@ -416,12 +536,12 @@ fn main() { let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); let refcount = - force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; + clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; let (before_enable, before_disable) = if refcount { let refcount_static = format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); - refcount_statics.insert(refcount_static.clone()); + clock_gen.refcount_statics.insert(refcount_static.clone()); ( quote! { @@ -442,63 +562,12 @@ fn main() { }; let clock_frequency = match &rcc.kernel_clock { - PeripheralRccKernelClock::Mux(mux) => { - let ir = &rcc_registers.ir; - let fieldset_name = mux.register.to_ascii_lowercase(); - let fieldset = ir - .fieldsets - .iter() - .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name)) - .unwrap(); - let field_name = mux.field.to_ascii_lowercase(); - let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap(); - let enum_name = field.enumm.unwrap(); - let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap(); - - let fieldset_name = format_ident!("{}", fieldset_name); - let field_name = format_ident!("{}", field_name); - let enum_name = format_ident!("{}", enum_name); - - rcc_cfgr_regs.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone())); - - let match_arms: TokenStream = enumm - .variants - .iter() - .filter(|v| v.name != "DISABLE") - .map(|v| { - let variant_name = format_ident!("{}", v.name); - let clock_name = format_ident!("{}", v.name.to_ascii_lowercase()); - clock_names.insert(v.name.to_ascii_lowercase()); - quote! { - #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }, - } - }) - .collect(); - - quote! { - use crate::pac::rcc::vals::#enum_name; - - #[allow(unreachable_patterns)] - match crate::pac::RCC.#fieldset_name().read().#field_name() { - #match_arms - _ => unreachable!(), - } - } - } - PeripheralRccKernelClock::Clock(clock) => { - let clock = clock.to_ascii_lowercase(); - let clock_name = format_ident!("{}", clock); - clock_names.insert(clock.to_string()); - quote! { - unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } - } - } + PeripheralRccKernelClock::Mux(mux) => clock_gen.gen_mux(mux), + PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(clock), }; - /* - A refcount leak can result if the same field is shared by peripherals with different stop modes - This condition should be checked in stm32-data - */ + // A refcount leak can result if the same field is shared by peripherals with different stop modes + // This condition should be checked in stm32-data let stop_refcount = match rcc.stop_mode { StopMode::Standby => None, StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }), @@ -543,74 +612,79 @@ fn main() { } } - if !rcc_cfgr_regs.is_empty() { - println!("cargo:rustc-cfg=clock_mux"); + let struct_fields: Vec<_> = clock_gen + .muxes + .iter() + .map(|(_fieldset, fieldname, enum_name)| { + quote! { + pub #fieldname: #enum_name + } + }) + .collect(); - let struct_fields: Vec<_> = rcc_cfgr_regs + let mut inits = TokenStream::new(); + for fieldset in clock_gen + .muxes + .iter() + .map(|(f, _, _)| f) + .collect::>() + .into_iter() + { + let setters: Vec<_> = clock_gen + .muxes .iter() - .map(|(_fieldset, fieldname, enum_name)| { - quote! { - pub #fieldname: Option<#enum_name> - } - }) - .collect(); - - let field_names: Vec<_> = rcc_cfgr_regs - .iter() - .map(|(_fieldset, fieldname, _enum_name)| fieldname) - .collect(); - - let inits: Vec<_> = rcc_cfgr_regs - .iter() - .map(|(fieldset, fieldname, _enum_name)| { + .filter(|(f, _, _)| f == fieldset) + .map(|(_, fieldname, _)| { let setter = format_ident!("set_{}", fieldname); quote! { - match self.#fieldname { - None => {} - Some(val) => { - crate::pac::RCC.#fieldset() - .modify(|w| w.#setter(val)); - } - }; + w.#setter(self.#fieldname); } }) .collect(); - let enum_names: BTreeSet<_> = rcc_cfgr_regs - .iter() - .map(|(_fieldset, _fieldname, enum_name)| enum_name) - .collect(); - - g.extend(quote! { - pub mod mux { - #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* - - #[derive(Clone, Copy)] - pub struct ClockMux { - #( #struct_fields, )* - } - - impl Default for ClockMux { - fn default() -> Self { - Self { - #( #field_names: None, )* - } - } - } - - impl ClockMux { - pub fn init(self) { - #( #inits )* - } - } - } - }); + inits.extend(quote! { + crate::pac::RCC.#fieldset().modify(|w| { + #(#setters)* + }); + }) } + let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect(); + + g.extend(quote! { + pub mod mux { + #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* + + #[derive(Clone, Copy)] + pub struct ClockMux { + #( #struct_fields, )* + } + + impl ClockMux { + pub(crate) const fn default() -> Self { + // safety: zero value is valid for all PAC enums. + unsafe { ::core::mem::zeroed() } + } + } + + impl Default for ClockMux { + fn default() -> Self { + Self::default() + } + } + + impl ClockMux { + pub(crate) fn init(&self) { + #inits + } + } + } + }); + // Generate RCC - clock_names.insert("sys".to_string()); - clock_names.insert("rtc".to_string()); - let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect(); + clock_gen.clock_names.insert("sys".to_string()); + clock_gen.clock_names.insert("rtc".to_string()); + let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect(); g.extend(quote! { #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -640,7 +714,8 @@ fn main() { } ); - let refcount_mod: TokenStream = refcount_statics + let refcount_mod: TokenStream = clock_gen + .refcount_statics .iter() .map(|refcount_static| { quote! { diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 663a7f59d..523719bb9 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -7,7 +7,6 @@ use core::task::Poll; use self::sealed::Instance; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; -use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel}; use crate::peripherals::IPCC; use crate::rcc::sealed::RccPeripheral; @@ -105,7 +104,8 @@ impl Ipcc { IPCC::enable_and_reset(); IPCC::set_cpu2(true); - _configure_pwr(); + // set RF wake-up clock = LSE + crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01)); let regs = IPCC::regs(); @@ -271,18 +271,3 @@ pub(crate) mod sealed { fn state() -> &'static State; } } - -fn _configure_pwr() { - // TODO: move the rest of this to rcc - let rcc = crate::pac::RCC; - - // TODO: required - // set RF wake-up clock = LSE - rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); - - // set LPTIM1 & LPTIM2 clock source - rcc.ccipr().modify(|w| { - w.set_lptim1sel(Lptim1sel::PCLK1); - w.set_lptim2sel(Lptim2sel::PCLK1); - }); -} diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index ec6ec34e8..1946c5a15 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -21,6 +21,9 @@ pub struct Config { pub ahb_pre: AHBPrescaler, pub apb_pre: APBPrescaler, pub ls: super::LsConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -31,6 +34,7 @@ impl Default for Config { ahb_pre: AHBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1, ls: Default::default(), + mux: Default::default(), } } } @@ -97,28 +101,25 @@ pub(crate) unsafe fn init(config: Config) { if !set_flash_latency_after { // Spin until the effective flash latency is compatible with the clock change - while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} + while FLASH.acr().read().latency() < target_flash_latency {} } // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once - let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre); RCC.cfgr().modify(|w| { w.set_sw(sw); - w.set_hpre(hpre); - w.set_ppre(ppre); + w.set_hpre(config.ahb_pre); + w.set_ppre(config.apb_pre); }); - - if set_flash_latency_after { - // We can make the flash require fewer wait states - // Spin until the SYSCLK changes have taken effect - loop { - let cfgr = RCC.cfgr().read(); - if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre { - break; - } + // Spin until the SYSCLK changes have taken effect + loop { + let cfgr = RCC.cfgr().read(); + if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre { + break; } + } - // Set the flash latency to require fewer wait states + // Set the flash latency to require fewer wait states + if set_flash_latency_after { FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); } @@ -132,6 +133,11 @@ pub(crate) unsafe fn init(config: Config) { } }; + config.mux.init(); + + // without this, the ringbuffered uart test fails. + cortex_m::asm::dsb(); + set_clocks!( hsi: None, lse: None, diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 5046f0a3a..215f8a3d2 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -98,8 +98,8 @@ pub struct Config { #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] pub adc34: AdcClockSource, - #[cfg(clock_mux)] - pub mux: crate::rcc::mux::ClockMux, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, pub ls: super::LsConfig, } @@ -128,7 +128,6 @@ impl Default for Config { #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), - #[cfg(clock_mux)] mux: Default::default(), } } @@ -370,7 +369,6 @@ pub(crate) unsafe fn init(config: Config) { }; */ - #[cfg(clock_mux)] config.mux.init(); set_clocks!( diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 343d075cd..7b252870c 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -95,6 +95,9 @@ pub struct Config { pub ls: super::LsConfig, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, + #[cfg(stm32f2)] pub voltage: VoltageScale, } @@ -120,6 +123,7 @@ impl Default for Config { #[cfg(stm32f2)] voltage: VoltageScale::Range3, + mux: Default::default(), } } } @@ -256,6 +260,8 @@ pub(crate) unsafe fn init(config: Config) { }); while RCC.cfgr().read().sws() != config.sys {} + config.mux.init(); + set_clocks!( hsi: hsi, hse: hse, @@ -286,7 +292,9 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] pllsai1_r: pllsai.r, - clk48: pll.q, + // TODO workaround until f4 rcc is fixed in stm32-data + #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))] + pllsai1_q: None, hsi_div488: hsi.map(|hsi| hsi/488u32), hsi_hse: None, diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index ae502dd9c..5cfe9953b 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -71,22 +71,6 @@ pub enum PllSource { HSE(Hertz, HseMode), } -/// Sets the source for the 48MHz clock to the USB peripheral. -#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] -pub enum UsbSrc { - /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the - /// oscillator to comply with the USB specification for oscillator tolerance. - #[cfg(any(stm32g0b1, stm32g0c1))] - Hsi48(super::Hsi48Config), - /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The - /// PLL needs to be using the HSE source to comply with the USB specification for oscillator - /// tolerance. - PllQ, - /// Use the HSE source directly. The HSE must be a 48MHz source. The HSE source must comply - /// with the USB specification for oscillator tolerance. - HSE, -} - /// Clocks configutation pub struct Config { pub sys: Sysclk, @@ -94,8 +78,10 @@ pub struct Config { pub apb_pre: APBPrescaler, pub low_power_run: bool, pub ls: super::LsConfig, - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - pub usb_src: Option, + #[cfg(crs)] + pub hsi48: Option, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -107,8 +93,9 @@ impl Default for Config { apb_pre: APBPrescaler::DIV1, low_power_run: false, ls: Default::default(), - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - usb_src: None, + #[cfg(crs)] + hsi48: Some(Default::default()), + mux: Default::default(), } } } @@ -322,34 +309,12 @@ pub(crate) unsafe fn init(config: Config) { let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); let hse_freq = (sw == Sw::HSE).then_some(sys_clk); - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - let hsi48_freq = config.usb_src.and_then(|config| { - match config { - UsbSrc::PllQ => { - // Make sure the PLLQ is enabled and running at 48Mhz - assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q)); - None - } - UsbSrc::HSE => { - // Make sure the HSE is enabled and running at 48Mhz - assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE)); - None - } - #[cfg(any(stm32g0b1, stm32g0c1))] - UsbSrc::Hsi48(config) => { - let freq = super::init_hsi48(config); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)); - Some(freq) - } - } - }); - #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))] - let hsi48_freq: Option = None; + #[cfg(crs)] + let hsi48 = config.hsi48.map(super::init_hsi48); + #[cfg(not(crs))] + let hsi48: Option = None; + + config.mux.init(); set_clocks!( sys: Some(sys_clk), @@ -357,7 +322,7 @@ pub(crate) unsafe fn init(config: Config) { pclk1: Some(apb_freq), pclk1_tim: Some(apb_tim_freq), hsi: hsi_freq, - hsi48: hsi48_freq, + hsi48: hsi48, hsi_div_8: hsi_div_8_freq, hse: hse_freq, lse: lse_freq, diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 6ed266284..79bdbeb77 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,11 +1,10 @@ use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::{Adcsel, Sw}; +use stm32_metapac::rcc::vals::Sw; use stm32_metapac::FLASH; pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Clk48sel as Clk48Src, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, - Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler, - Sw as Sysclk, + Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, + Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{PWR, RCC}; use crate::time::Hertz; @@ -82,24 +81,15 @@ pub struct Config { pub low_power_run: bool, - /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. - pub clk48_src: Clk48Src, - /// Low-Speed Clock Configuration pub ls: super::LsConfig, - /// Clock Source for ADCs 1 and 2 - pub adc12_clock_source: AdcClockSource, - - /// Clock Source for ADCs 3, 4 and 5 - pub adc345_clock_source: AdcClockSource, - - /// Clock Source for FDCAN - pub fdcan_clock_source: FdCanClockSource, - /// Enable range1 boost mode /// Recommended when the SYSCLK frequency is greater than 150MHz. pub boost: bool, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -115,12 +105,9 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, low_power_run: false, - clk48_src: Clk48Src::HSI48, ls: Default::default(), - adc12_clock_source: Adcsel::DISABLE, - adc345_clock_source: Adcsel::DISABLE, - fdcan_clock_source: FdCanClockSource::PCLK1, boost: false, + mux: Default::default(), } } } @@ -165,9 +152,7 @@ pub(crate) unsafe fn init(config: Config) { }; // Configure HSI48 if required - if let Some(hsi48_config) = config.hsi48 { - super::init_hsi48(hsi48_config); - } + let hsi48 = config.hsi48.map(super::init_hsi48); let pll_freq = config.pll.map(|pll_config| { let src_freq = match pll_config.source { @@ -176,13 +161,13 @@ pub(crate) unsafe fn init(config: Config) { _ => unreachable!(), }; - assert!(max::PLL_IN.contains(&src_freq)); - // Disable PLL before configuration RCC.cr().modify(|w| w.set_pllon(false)); while RCC.cr().read().pllrdy() {} - let internal_freq = src_freq / pll_config.prediv * pll_config.mul; + let in_freq = src_freq / pll_config.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let internal_freq = in_freq * pll_config.mul; assert!(max::PLL_VCO.contains(&internal_freq)); @@ -301,42 +286,6 @@ pub(crate) unsafe fn init(config: Config) { let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre); let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre); - // Configure the 48MHz clock source for USB and RNG peripherals. - RCC.ccipr().modify(|w| { - w.set_clk48sel(match config.clk48_src { - Clk48Src::PLL1_Q => { - // Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock. - // Peripherals which require one (USB, RNG) should check that they‘re driven by a valid 48MHz - // clock at init. - crate::pac::rcc::vals::Clk48sel::PLL1_Q - } - Clk48Src::HSI48 => { - // Make sure HSI48 is enabled - assert!(config.hsi48.is_some()); - crate::pac::rcc::vals::Clk48sel::HSI48 - } - _ => unreachable!(), - }) - }); - - RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); - RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); - RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source)); - - let adc12_ck = match config.adc12_clock_source { - AdcClockSource::DISABLE => None, - AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p, - AdcClockSource::SYS => Some(sys_clk), - _ => unreachable!(), - }; - - let adc345_ck = match config.adc345_clock_source { - AdcClockSource::DISABLE => None, - AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p, - AdcClockSource::SYS => Some(sys_clk), - _ => unreachable!(), - }; - if config.low_power_run { assert!(sys_clk <= Hertz(2_000_000)); PWR.cr1().modify(|w| w.set_lpr(true)); @@ -344,6 +293,8 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk), @@ -353,12 +304,11 @@ pub(crate) unsafe fn init(config: Config) { pclk1_tim: Some(apb1_tim_freq), pclk2: Some(apb2_freq), pclk2_tim: Some(apb2_tim_freq), - adc: adc12_ck, - adc34: adc345_ck, pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), hse: hse, + hsi48: hsi48, rtc: rtc, ); } diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 7b2255cc6..bab8bb19e 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -2,15 +2,10 @@ use core::ops::RangeInclusive; use crate::pac; use crate::pac::pwr::vals::Vos; -#[cfg(stm32h5)] -pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; -#[cfg(stm32h7)] -pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; pub use crate::pac::rcc::vals::{ - Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, - Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, + Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, }; -use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; +use crate::pac::rcc::vals::{Pllrge, Pllvcosel, Timpre}; use crate::pac::{FLASH, PWR, RCC}; use crate::time::Hertz; @@ -194,16 +189,15 @@ pub struct Config { #[cfg(stm32h7)] pub apb4_pre: APBPrescaler, - pub per_clock_source: PerClockSource, - pub adc_clock_source: AdcClockSource, - pub fdcan_clock_source: FdCanClockSource, - pub timer_prescaler: TimerPrescaler, pub voltage_scale: VoltageScale, pub ls: super::LsConfig, #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] pub supply_config: SupplyConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -227,21 +221,14 @@ impl Default for Config { #[cfg(stm32h7)] apb4_pre: APBPrescaler::DIV1, - per_clock_source: PerClockSource::HSI, - - #[cfg(stm32h5)] - adc_clock_source: AdcClockSource::HCLK1, - #[cfg(stm32h7)] - adc_clock_source: AdcClockSource::PER, - - fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE - timer_prescaler: TimerPrescaler::DefaultX2, voltage_scale: VoltageScale::Scale0, ls: Default::default(), #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] supply_config: SupplyConfig::Default, + + mux: Default::default(), } } } @@ -504,31 +491,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h7)] assert!(apb4 <= pclk_max); - let _per_ck = match config.per_clock_source { - Ckpersel::HSI => hsi, - Ckpersel::CSI => csi, - Ckpersel::HSE => hse, - _ => unreachable!(), - }; - - #[cfg(stm32h7)] - let adc = match config.adc_clock_source { - AdcClockSource::PLL2_P => pll2.p, - AdcClockSource::PLL3_R => pll3.r, - AdcClockSource::PER => _per_ck, - _ => unreachable!(), - }; - #[cfg(stm32h5)] - let adc = match config.adc_clock_source { - AdcClockSource::HCLK1 => Some(hclk), - AdcClockSource::SYS => Some(sys), - AdcClockSource::PLL2_R => pll2.r, - AdcClockSource::HSE => hse, - AdcClockSource::HSI => hsi, - AdcClockSource::CSI => csi, - _ => unreachable!(), - }; - flash_setup(hclk, config.voltage_scale); let rtc = config.ls.init(); @@ -550,16 +512,6 @@ pub(crate) unsafe fn init(config: Config) { RCC.d3cfgr().modify(|w| { w.set_d3ppre(config.apb4_pre); }); - - RCC.d1ccipr().modify(|w| { - w.set_ckpersel(config.per_clock_source); - }); - RCC.d3ccipr().modify(|w| { - w.set_adcsel(config.adc_clock_source); - }); - RCC.d2ccip1r().modify(|w| { - w.set_fdcansel(config.fdcan_clock_source); - }); } #[cfg(stm32h5)] { @@ -573,12 +525,6 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre); w.set_ppre3(config.apb3_pre); }); - - RCC.ccipr5().modify(|w| { - w.set_ckpersel(config.per_clock_source); - w.set_adcdacsel(config.adc_clock_source); - w.set_fdcan12sel(config.fdcan_clock_source) - }); } RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); @@ -601,6 +547,8 @@ pub(crate) unsafe fn init(config: Config) { while !pac::SYSCFG.cccsr().read().ready() {} } + config.mux.init(); + set_clocks!( sys: Some(sys), hclk1: Some(hclk), @@ -614,7 +562,6 @@ pub(crate) unsafe fn init(config: Config) { pclk4: Some(apb4), pclk1_tim: Some(apb1_tim), pclk2_tim: Some(apb2_tim), - adc: adc, rtc: rtc, hsi: hsi, @@ -646,7 +593,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h5)] audioclk: None, - per: None, i2s_ckin: None, ); } diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index aa4245d4e..9079ddd41 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -1,10 +1,6 @@ #[cfg(any(stm32l0, stm32l1))] pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::regs::Cfgr; -#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] -pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; -#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] -pub use crate::pac::rcc::vals::Clk48sel as Clk48Src; #[cfg(any(stm32wb, stm32wl))] pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk}; @@ -59,18 +55,14 @@ pub struct Config { #[cfg(any(stm32wl, stm32wb))] pub shared_ahb_pre: AHBPrescaler, - // muxes - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - pub clk48_src: Clk48Src, - // low speed LSI/LSE/RTC pub ls: super::LsConfig, - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - pub adc_clock_source: AdcClockSource, - #[cfg(any(stm32l0, stm32l1))] pub voltage_scale: VoltageScale, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -95,13 +87,10 @@ impl Default for Config { pllsai2: None, #[cfg(crs)] hsi48: Some(Default::default()), - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - clk48_src: Clk48Src::HSI48, ls: Default::default(), - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - adc_clock_source: AdcClockSource::SYS, #[cfg(any(stm32l0, stm32l1))] voltage_scale: VoltageScale::RANGE1, + mux: Default::default(), } } } @@ -118,7 +107,6 @@ pub const WPAN_DEFAULT: Config = Config { hsi48: Some(super::Hsi48Config { sync_from_usb: false }), msi: None, hsi: false, - clk48_src: Clk48Src::PLL1_Q, ls: super::LsConfig::default_lse(), @@ -137,7 +125,8 @@ pub const WPAN_DEFAULT: Config = Config { shared_ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, - adc_clock_source: AdcClockSource::SYS, + + mux: super::mux::ClockMux::default(), }; fn msi_enable(range: MSIRange) { @@ -267,21 +256,6 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::PLL1_R => pll.r.unwrap(), }; - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src)); - #[cfg(any(rcc_l0_v2))] - let clk48 = match config.clk48_src { - Clk48Src::HSI48 => hsi48, - Clk48Src::PLL1_VCO_DIV_2 => pll.clk48, - }; - #[cfg(any(stm32l4, stm32l5, stm32wb))] - let clk48 = match config.clk48_src { - Clk48Src::HSI48 => hsi48, - Clk48Src::MSI => msi, - Clk48Src::PLLSAI1_Q => pllsai1.q, - Clk48Src::PLL1_Q => pll.q, - }; - #[cfg(rcc_l4plus)] assert!(sys_clk.0 <= 120_000_000); #[cfg(all(stm32l4, not(rcc_l4plus)))] @@ -357,9 +331,6 @@ pub(crate) unsafe fn init(config: Config) { }); while RCC.cfgr().read().sws() != config.sys {} - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source)); - #[cfg(any(stm32wl, stm32wb))] { RCC.extcfgr().modify(|w| { @@ -372,6 +343,8 @@ pub(crate) unsafe fn init(config: Config) { while !RCC.extcfgr().read().c2hpref() {} } + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk1), @@ -388,10 +361,11 @@ pub(crate) unsafe fn init(config: Config) { hsi: hsi, hse: hse, msi: msi, - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - clk48: clk48, hsi48: hsi48, + #[cfg(any(stm32l0, stm32l1))] + pll1_vco_div_2: pll.vco.map(|c| c/2u32), + #[cfg(not(any(stm32l0, stm32l1)))] pll1_p: pll.p, #[cfg(not(any(stm32l0, stm32l1)))] @@ -511,7 +485,7 @@ mod pll { #[derive(Default)] pub(super) struct PllOutput { pub r: Option, - pub clk48: Option, + pub vco: Option, } pub(super) fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> PllOutput { @@ -528,7 +502,6 @@ mod pll { let vco_freq = pll_src * pll.mul; let r = vco_freq / pll.div; - let clk48 = (vco_freq == Hertz(96_000_000)).then_some(Hertz(48_000_000)); assert!(r <= Hertz(32_000_000)); @@ -541,7 +514,10 @@ mod pll { // Enable PLL pll_enable(instance, true); - PllOutput { r: Some(r), clk48 } + PllOutput { + r: Some(r), + vco: Some(vco_freq), + } } } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c8ca713de..910ebe205 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -31,9 +31,7 @@ mod _version; pub use _version::*; -#[cfg(clock_mux)] -pub use crate::_generated::mux; -pub use crate::_generated::Clocks; +pub use crate::_generated::{mux, Clocks}; #[cfg(feature = "low-power")] /// Must be written within a critical section diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index c8814ed69..9533e16c4 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -85,6 +85,9 @@ pub struct Config { /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits. pub voltage_range: VoltageScale, pub ls: super::LsConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -104,6 +107,7 @@ impl Default for Config { apb3_pre: APBPrescaler::DIV1, voltage_range: VoltageScale::RANGE1, ls: Default::default(), + mux: Default::default(), } } } @@ -259,6 +263,8 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk), @@ -289,7 +295,6 @@ pub(crate) unsafe fn init(config: Config) { lse: None, lsi: None, msik: None, - iclk: None, shsi: None, shsi_div_2: None, ); diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 9d5dcfc4b..8e1779d7c 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -1,8 +1,6 @@ pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::regs::Cfgr1; -pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk, -}; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -32,9 +30,10 @@ pub struct Config { // low speed LSI/LSE/RTC pub ls: super::LsConfig, - pub adc_clock_source: AdcClockSource, - pub voltage_scale: VoltageScale, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -49,8 +48,8 @@ impl Default for Config { apb2_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1, ls: Default::default(), - adc_clock_source: AdcClockSource::HCLK4, voltage_scale: VoltageScale::RANGE2, + mux: Default::default(), } } } @@ -152,7 +151,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre); }); - RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source)); + config.mux.init(); set_clocks!( sys: Some(sys_clk), diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 190fb274f..373697ec8 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -606,13 +606,6 @@ impl<'d, T: Instance> Bus<'d, T> { // Wait for USB power to stabilize while !crate::pac::PWR.cr3().read().usb33rdy() {} - // Use internal 48MHz HSI clock. Should be enabled in RCC by default. - critical_section::with(|_| { - crate::pac::RCC - .d2ccip2r() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) - }); - // Enable ULPI clock if external PHY is used let ulpien = !self.phy_type.internal(); critical_section::with(|_| { @@ -645,13 +638,6 @@ impl<'d, T: Instance> Bus<'d, T> { // Wait for USB power to stabilize while !crate::pac::PWR.svmsr().read().vddusbrdy() {} - - // Select HSI48 as USB clock source. - critical_section::with(|_| { - crate::pac::RCC.ccipr1().modify(|w| { - w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); - }) - }); } ::enable_and_reset(); diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 7c6d6cd71..e6d1a6c02 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; - config.rcc.mux.hrtim1sw = Some(embassy_stm32::rcc::mux::Timsw::PLL1_P); + config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P; } let p = embassy_stm32::init(config); diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 3f63d0dfd..647ff0419 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -4,37 +4,35 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; -use embassy_stm32::pac::rcc::vals::Tim1sel; -use embassy_stm32::rcc::{Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr, Sysclk}; use embassy_stm32::time::khz; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; use embassy_stm32::timer::Channel; -use embassy_stm32::{pac, Config as PeripheralConfig}; +use embassy_stm32::Config as PeripheralConfig; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut rcc_config = RccConfig::default(); - rcc_config.sys = Sysclk::PLL(PllConfig { - source: PllSource::HSI, - m: Pllm::DIV1, - n: Plln::MUL16, - r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) - q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) - p: None, - }); + let mut config = PeripheralConfig::default(); + { + use embassy_stm32::rcc::*; - let mut peripheral_config = PeripheralConfig::default(); - peripheral_config.rcc = rcc_config; + config.rcc.sys = Sysclk::PLL(PllConfig { + source: PllSource::HSI, + m: Pllm::DIV1, + n: Plln::MUL16, + r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) + q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) + p: None, + }); - let p = embassy_stm32::init(peripheral_config); - - // configure TIM1 mux to select PLLQ as clock source - // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - // RM0444 page 210 - // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 - pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q)); + // configure TIM1 mux to select PLLQ as clock source + // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + // RM0444 page 210 + // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 + config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q; + } + let p = embassy_stm32::init(config); let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs index f5aaa5624..8b9915626 100644 --- a/examples/stm32g0/src/bin/usb_serial.rs +++ b/examples/stm32g0/src/bin/usb_serial.rs @@ -4,7 +4,6 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_stm32::rcc::{Hsi48Config, UsbSrc}; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; @@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config { - sync_from_usb: true, - ..Default::default() - })); + { + use embassy_stm32::rcc::*; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); + config.rcc.mux.usbsel = mux::Usbsel::HSI48; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 6c6de1ffe..f81335f93 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::rcc::{AdcClockSource, Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk}; use embassy_stm32::Config; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -12,20 +11,20 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - config.rcc.pll = Some(Pll { - source: Pllsrc::HSI, - prediv: PllPreDiv::DIV4, - mul: PllMul::MUL85, - divp: None, - divq: None, - // Main system clock at 170 MHz - divr: Some(PllRDiv::DIV2), - }); - - config.rcc.adc12_clock_source = AdcClockSource::SYS; - config.rcc.sys = Sysclk::PLL1_R; - + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: Pllsrc::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } let mut p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index a41f765c1..7551b2a55 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; +use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, can, Config}; use embassy_time::Timer; use static_cell::StaticCell; @@ -15,8 +16,24 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let config = Config::default(); - + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL85, + divp: None, + divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan. + divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz + }); + config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q; + config.rcc.sys = Sysclk::PLL1_R; + } let peripherals = embassy_stm32::init(config); let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs index 5274de79d..2609abfa2 100644 --- a/examples/stm32g4/src/bin/pll.rs +++ b/examples/stm32g4/src/bin/pll.rs @@ -12,6 +12,7 @@ use {defmt_rtt as _, panic_probe as _}; async fn main(_spawner: Spawner) { let mut config = Config::default(); + config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: Pllsrc::HSI, prediv: PllPreDiv::DIV4, diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 989fef5b0..90caaae14 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -3,9 +3,6 @@ use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ - Clk48Src, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk, -}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, Config}; @@ -22,38 +19,27 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. - const USE_HSI48: bool = true; - - let plldivq = if USE_HSI48 { None } else { Some(PllQDiv::DIV6) }; - - config.rcc.hse = Some(Hse { - freq: Hertz(8_000_000), - mode: HseMode::Oscillator, - }); - - config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, - prediv: PllPreDiv::DIV2, - mul: PllMul::MUL72, - divp: None, - divq: plldivq, - // Main system clock at 144 MHz - divr: Some(PllRDiv::DIV2), - }); - - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.boost = true; // BOOST! - - if USE_HSI48 { + { + use embassy_stm32::rcc::*; // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); - config.rcc.clk48_src = Clk48Src::HSI48; - } else { - config.rcc.clk48_src = Clk48Src::PLL1_Q; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV2, + mul: PllMul::MUL72, + divp: None, + divq: Some(PllQDiv::DIV6), // 48mhz + divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz + }); + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.boost = true; // BOOST! + config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; + //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead. } - let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index e5ccfe4f7..643df27f9 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE; let peripherals = embassy_stm32::init(config); diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 208493d8c..83477c8fa 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -5,7 +5,7 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) { config.rcc.apb3_pre = APBPrescaler::DIV4; config.rcc.sys = Sysclk::PLL1_P; config.rcc.voltage_scale = VoltageScale::Scale0; + config.rcc.mux.usbsel = mux::Usbsel::HSI48; } let p = embassy_stm32::init(config); info!("Hello World!"); - pac::RCC.ccipr4().write(|w| { - w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); - }); - // Create the driver, from the HAL. let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index f0278239f..a5594d10c 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } let mut p = embassy_stm32::init(config); diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index e5ccfe4f7..13a6a5051 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; let peripherals = embassy_stm32::init(config); diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index a9bf46de0..a6f969aba 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -40,7 +40,7 @@ fn main() -> ! { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } let p = embassy_stm32::init(config); diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index d88bd838f..feec28993 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -42,7 +42,7 @@ async fn main(spawner: Spawner) { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } // Initialize the board and obtain a Peripherals instance diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index 910944673..a9f4604aa 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_stm32::adc::{Adc, Resolution}; -use embassy_stm32::pac; +use embassy_stm32::Config; use embassy_time::Delay; use {defmt_rtt as _, panic_probe as _}; @@ -11,12 +11,12 @@ use {defmt_rtt as _, panic_probe as _}; fn main() -> ! { info!("Hello World!"); - pac::RCC.ccipr().modify(|w| { - w.set_adcsel(pac::rcc::vals::Adcsel::SYS); - }); - pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); - - let p = embassy_stm32::init(Default::default()); + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.mux.adcsel = mux::Adcsel::SYS; + } + let p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1, &mut Delay); //adc.enable_vref(); diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index f21aa797c..dd78d7fb3 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -33,7 +33,7 @@ fn options() -> TestOptions { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; TestOptions { config: c, max_latency: Duration::from_micros(1200), @@ -50,7 +50,7 @@ fn options() -> TestOptions { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; TestOptions { config: c, max_latency: Duration::from_micros(1200), diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 7b9585afd..cf3e04a4b 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -2,6 +2,8 @@ pub use defmt::*; #[allow(unused)] +use embassy_stm32::rcc::*; +#[allow(unused)] use embassy_stm32::time::Hertz; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; @@ -265,7 +267,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f091rc")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -281,7 +282,6 @@ pub fn config() -> Config { } #[cfg(feature = "stm32f103c8")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Oscillator, @@ -298,7 +298,6 @@ pub fn config() -> Config { } #[cfg(feature = "stm32f207zg")] { - use embassy_stm32::rcc::*; // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), @@ -327,7 +326,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f303ze")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -345,7 +343,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f429zi")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -366,7 +363,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f446re")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Oscillator, @@ -387,7 +383,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f767zi")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -408,7 +403,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32h563zi")] { - use embassy_stm32::rcc::*; config.rcc.hsi = None; config.rcc.hsi48 = Some(Default::default()); // needed for RNG config.rcc.hse = Some(Hse { @@ -433,7 +427,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32h503rb")] { - use embassy_stm32::rcc::*; config.rcc.hsi = None; config.rcc.hsi48 = Some(Default::default()); // needed for RNG config.rcc.hse = Some(Hse { @@ -456,9 +449,26 @@ pub fn config() -> Config { config.rcc.voltage_scale = VoltageScale::Scale0; } + #[cfg(feature = "stm32g491re")] + { + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL85, + divp: None, + divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan. + divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz + }); + config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q; + config.rcc.sys = Sysclk::PLL1_R; + } + #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.csi = true; config.rcc.hsi48 = Some(Default::default()); // needed for RNG @@ -485,7 +495,7 @@ pub fn config() -> Config { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; #[cfg(any(feature = "stm32h755zi"))] { config.rcc.supply_config = SupplyConfig::DirectSMPS; @@ -494,7 +504,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32h7a3zi"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.csi = true; config.rcc.hsi48 = Some(Default::default()); // needed for RNG @@ -521,12 +530,11 @@ pub fn config() -> Config { config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz config.rcc.voltage_scale = VoltageScale::Scale0; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] { - use embassy_stm32::rcc::*; config.rcc.sys = Sysclk::PLL1_R; config.rcc.hsi = true; config.rcc.pll = Some(Pll { @@ -541,7 +549,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32wl55jc")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(32_000_000), mode: HseMode::Bypass, @@ -560,7 +567,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32l552ze"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { @@ -576,7 +582,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll1 = Some(Pll { source: PllSource::HSI, // 16 MHz @@ -593,17 +598,12 @@ pub fn config() -> Config { #[cfg(feature = "stm32wba52cg")] { - use embassy_stm32::rcc::*; config.rcc.sys = Sysclk::HSI; - - embassy_stm32::pac::RCC.ccipr2().write(|w| { - w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI); - }); + config.rcc.mux.rngsel = mux::Rngsel::HSI; } #[cfg(feature = "stm32l073rz")] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI, @@ -615,7 +615,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32l152re"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI, From df8f508ffa2bec79f6e3fba4ac3cfe0e5545b5b2 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 2 Mar 2024 09:00:54 +1000 Subject: [PATCH 610/760] Writing to TX buffer also needs to fire an interrupt to kick off transmission if it is idle. Formatting --- embassy-stm32/src/can/fdcan.rs | 62 ++++++++++++++++++++++++++++++--- examples/stm32g4/src/bin/can.rs | 6 +++- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 6a4a25cb7..77db774fc 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -436,7 +436,31 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S } /// Sender that can be used for sending CAN frames. -pub type BufferedCanSender = embassy_sync::channel::DynamicSender<'static, ClassicFrame>; +#[derive(Copy, Clone)] +pub struct BufferedCanSender { + tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>, + waker: fn(), +} + +impl BufferedCanSender { + /// Async write frame to TX buffer. + pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError> { + self.tx_buf.try_send(frame)?; + (self.waker)(); + Ok(()) + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: ClassicFrame) { + self.tx_buf.send(frame).await; + (self.waker)(); + } + + /// Allows a poll_fn to poll until the channel is ready to write + pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { + self.tx_buf.poll_ready_to_send(cx) + } +} /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (ClassicFrame, Timestamp)>; @@ -489,7 +513,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedCanSender { - self.tx_buf.sender().into() + BufferedCanSender { + tx_buf: self.tx_buf.sender().into(), + waker: T::IT0Interrupt::pend, + } } /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. @@ -525,7 +552,31 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF } /// Sender that can be used for sending CAN frames. -pub type BufferedFdCanSender = embassy_sync::channel::DynamicSender<'static, FdFrame>; +#[derive(Copy, Clone)] +pub struct BufferedFdCanSender { + tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>, + waker: fn(), +} + +impl BufferedFdCanSender { + /// Async write frame to TX buffer. + pub fn try_write(&mut self, frame: FdFrame) -> Result<(), embassy_sync::channel::TrySendError> { + self.tx_buf.try_send(frame)?; + (self.waker)(); + Ok(()) + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: FdFrame) { + self.tx_buf.send(frame).await; + (self.waker)(); + } + + /// Allows a poll_fn to poll until the channel is ready to write + pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { + self.tx_buf.poll_ready_to_send(cx) + } +} /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub type BufferedFdCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (FdFrame, Timestamp)>; @@ -578,7 +629,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedFdCanSender { - self.tx_buf.sender().into() + BufferedFdCanSender { + tx_buf: self.tx_buf.sender().into(), + waker: T::IT0Interrupt::pend, + } } /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index a41f765c1..11e96361e 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -184,7 +184,11 @@ async fn main(_spawner: Spawner) { let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); - _ = can.write(frame).await; + // You can use any of these approaches to send. The writer makes it + // easy to share sending from multiple tasks. + //_ = can.write(frame).await; + //can.writer().try_write(frame).unwrap(); + can.writer().write(frame).await; match can.read().await { Ok((rx_frame, ts)) => { From 2c42463205dae7e38535fb18f58e872df99e125a Mon Sep 17 00:00:00 2001 From: Zheng Li <875543533@qq.com> Date: Sat, 2 Mar 2024 00:21:56 +0100 Subject: [PATCH 611/760] executor: remove portable-atomic for riscv. --- embassy-executor/Cargo.toml | 5 ++--- embassy-executor/src/arch/riscv32.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 409df0d75..431165cee 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -40,8 +40,7 @@ critical-section = "1.1" document-features = "0.2.7" -# needed for riscv and avr -# remove when https://github.com/rust-lang/rust/pull/114499 lands on stable (on 1.76) +# needed for AVR portable-atomic = { version = "1.5", optional = true } # arch-cortex-m dependencies @@ -78,7 +77,7 @@ arch-std = ["_arch", "critical-section/std"] ## Cortex-M arch-cortex-m = ["_arch", "dep:cortex-m"] ## RISC-V 32 -arch-riscv32 = ["_arch", "dep:portable-atomic"] +arch-riscv32 = ["_arch"] ## WASM arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] ## AVR diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index c56f502d3..01e63a9fd 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -6,9 +6,9 @@ pub use thread::*; #[cfg(feature = "executor-thread")] mod thread { use core::marker::PhantomData; + use core::sync::atomic::{AtomicBool, Ordering}; pub use embassy_executor_macros::main_riscv as main; - use portable_atomic::{AtomicBool, Ordering}; use crate::{raw, Spawner}; From 30606f9782247b7f0e485b39042100ec3286aaa2 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 27 Feb 2024 14:59:02 +0000 Subject: [PATCH 612/760] stm32: can: fd: allow TX buffers in FIFO mode --- embassy-stm32/src/can/fd/config.rs | 21 +++++++++++++++++++++ embassy-stm32/src/can/fd/peripheral.rs | 6 ++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index f2401d92f..e959913e4 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -287,6 +287,24 @@ impl Default for GlobalFilter { } } +/// TX buffer operation mode +#[derive(Clone, Copy, Debug)] +pub enum TxBufferMode { + /// TX FIFO operation + Fifo, + /// TX queue operation + Queue, +} + +impl From for crate::pac::can::vals::Tfqm { + fn from(value: TxBufferMode) -> Self { + match value { + TxBufferMode::Queue => Self::QUEUE, + TxBufferMode::Fifo => Self::FIFO, + } + } +} + /// FdCan Config Struct #[derive(Clone, Copy, Debug)] pub struct FdCanConfig { @@ -327,6 +345,8 @@ pub struct FdCanConfig { pub timestamp_source: TimestampSource, /// Configures the Global Filter pub global_filter: GlobalFilter, + /// TX buffer mode (FIFO or queue) + pub tx_buffer_mode: TxBufferMode, } impl FdCanConfig { @@ -433,6 +453,7 @@ impl Default for FdCanConfig { clock_divider: ClockDivider::_1, timestamp_source: TimestampSource::None, global_filter: GlobalFilter::default(), + tx_buffer_mode: TxBufferMode::Queue, } } } diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index e87a3c213..0ebbdb3b7 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -302,10 +302,8 @@ impl Registers { // Framework specific settings are set here - // set TxBuffer to Queue Mode - self.regs - .txbc() - .write(|w| w.set_tfqm(crate::pac::can::vals::Tfqm::QUEUE)); + // set TxBuffer Mode + self.regs.txbc().write(|w| w.set_tfqm(_config.tx_buffer_mode.into())); // set standard filters list size to 28 // set extended filters list size to 8 From befbb2845aebde5aa879bbe6dd0bdb08c277e492 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Wed, 28 Feb 2024 10:10:15 +0000 Subject: [PATCH 613/760] stm32: can: fd: write: if in TX FIFO mode & bufs full, then abort --- embassy-stm32/src/can/fd/config.rs | 11 ++++++++++- embassy-stm32/src/can/fd/peripheral.rs | 21 ++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index e959913e4..338e4979d 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -288,7 +288,7 @@ impl Default for GlobalFilter { } /// TX buffer operation mode -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum TxBufferMode { /// TX FIFO operation Fifo, @@ -305,6 +305,15 @@ impl From for crate::pac::can::vals::Tfqm { } } +impl From for TxBufferMode { + fn from(value: crate::pac::can::vals::Tfqm) -> Self { + match value { + crate::pac::can::vals::Tfqm::QUEUE => Self::Queue, + crate::pac::can::vals::Tfqm::FIFO => Self::Fifo, + } + } +} + /// FdCan Config Struct #[derive(Clone, Copy, Debug)] pub struct FdCanConfig { diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 0ebbdb3b7..2a183d2e8 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -114,6 +114,12 @@ impl Registers { self.regs.txfqs().read().tfqf() } + /// Returns the current TX buffer operation mode (queue or FIFO) + #[inline] + pub fn tx_queue_mode(&self) -> TxBufferMode { + self.regs.txbc().read().tfqm().into() + } + #[inline] pub fn has_pending_frame(&self, idx: usize) -> bool { self.regs.txbrp().read().trp(idx) @@ -197,13 +203,14 @@ impl Registers { } pub fn write(&self, frame: &F) -> nb::Result, Infallible> { - let queue_is_full = self.tx_queue_is_full(); - - let id = frame.header().id(); - - // If the queue is full, - // Discard the first slot with a lower priority message - let (idx, pending_frame) = if queue_is_full { + let (idx, pending_frame) = if self.tx_queue_is_full() { + if self.tx_queue_mode() == TxBufferMode::Fifo { + // Does not make sense to cancel a pending frame when using FIFO + return Err(nb::Error::WouldBlock); + } + // If the queue is full, + // Discard the first slot with a lower priority message + let id = frame.header().id(); if self.is_available(0, id) { (0, self.abort_pending_mailbox_generic(0)) } else if self.is_available(1, id) { From 9e403fa89aae1d13948fcc15d1cc1f3c709dca88 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Wed, 28 Feb 2024 10:12:22 +0000 Subject: [PATCH 614/760] stm32: can: fd: rename abort_pending_mailbox, rm pub qualifier --- embassy-stm32/src/can/fd/peripheral.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 2a183d2e8..3a95b2659 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -170,7 +170,7 @@ impl Registers { } #[inline] - pub fn abort_pending_mailbox_generic(&self, bufidx: usize) -> Option { + fn abort_pending_mailbox(&self, bufidx: usize) -> Option { if self.abort(bufidx) { let mailbox = self.tx_buffer_element(bufidx); @@ -212,11 +212,11 @@ impl Registers { // Discard the first slot with a lower priority message let id = frame.header().id(); if self.is_available(0, id) { - (0, self.abort_pending_mailbox_generic(0)) + (0, self.abort_pending_mailbox(0)) } else if self.is_available(1, id) { - (1, self.abort_pending_mailbox_generic(1)) + (1, self.abort_pending_mailbox(1)) } else if self.is_available(2, id) { - (2, self.abort_pending_mailbox_generic(2)) + (2, self.abort_pending_mailbox(2)) } else { // For now we bail when there is no lower priority slot available // Can this lead to priority inversion? From bf06d10534fcf6e6f2fd34c1517500a59ed4b626 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 2 Mar 2024 09:45:30 +1000 Subject: [PATCH 615/760] Delay setting TX buffer mode until user had a chance to configure it. --- embassy-stm32/src/can/fd/config.rs | 4 ++-- embassy-stm32/src/can/fd/peripheral.rs | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index 338e4979d..adaffe9cc 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -290,9 +290,9 @@ impl Default for GlobalFilter { /// TX buffer operation mode #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum TxBufferMode { - /// TX FIFO operation + /// TX FIFO operation - In this mode CAN frames are trasmitted strictly in write order. Fifo, - /// TX queue operation + /// TX queue operation - In this mode CAN frames are transmitted according to CAN priority. Queue, } diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 3a95b2659..f0aab132b 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -307,11 +307,6 @@ impl Registers { "Error reading endianness test value from FDCAN core" ); - // Framework specific settings are set here - - // set TxBuffer Mode - self.regs.txbc().write(|w| w.set_tfqm(_config.tx_buffer_mode.into())); - // set standard filters list size to 28 // set extended filters list size to 8 // REQUIRED: we use the memory map as if these settings are set @@ -357,6 +352,7 @@ impl Registers { /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] #[inline] pub fn apply_config(&mut self, config: FdCanConfig) { + self.set_tx_buffer_mode(config.tx_buffer_mode); self.set_data_bit_timing(config.dbtr); self.set_nominal_bit_timing(config.nbtr); self.set_automatic_retransmit(config.automatic_retransmit); @@ -504,6 +500,12 @@ impl Registers { self.regs.cccr().modify(|w| w.set_efbi(enabled)); } + /// Configures TX Buffer Mode + #[inline] + pub fn set_tx_buffer_mode(&mut self, tbm: TxBufferMode) { + self.regs.txbc().write(|w| w.set_tfqm(tbm.into())); + } + /// Configures frame transmission mode. See /// [`FdCanConfig::set_frame_transmit`] #[inline] From b693ab9b34fad5844401bc80b9968940e750680e Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 2 Mar 2024 12:57:03 +1000 Subject: [PATCH 616/760] Restore init order to restore H7. Previous commit broke H7 support in HIL farm. Restore previous order by moving a bunch of config from new and into_config_mode to apply_config. This is a cleanup that I had considered to move more register access into peripheral.rs. --- embassy-stm32/src/can/fd/peripheral.rs | 133 +++++++++++++++++++++---- embassy-stm32/src/can/fdcan.rs | 92 +---------------- 2 files changed, 113 insertions(+), 112 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index f0aab132b..8ec09ac12 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -22,6 +22,7 @@ enum LoopbackMode { pub struct Registers { pub regs: &'static crate::pac::can::Fdcan, pub msgram: &'static crate::pac::fdcanram::Fdcanram, + pub msg_ram_offset: usize, } impl Registers { @@ -294,7 +295,6 @@ impl Registers { pub fn into_config_mode(mut self, _config: FdCanConfig) { self.set_power_down_mode(false); self.enter_init_mode(); - self.reset_msg_ram(); // check the FDCAN core matches our expections @@ -307,27 +307,6 @@ impl Registers { "Error reading endianness test value from FDCAN core" ); - // set standard filters list size to 28 - // set extended filters list size to 8 - // REQUIRED: we use the memory map as if these settings are set - // instead of re-calculating them. - #[cfg(not(stm32h7))] - { - self.regs.rxgfc().modify(|w| { - w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX); - w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX); - }); - } - #[cfg(stm32h7)] - { - self.regs - .sidfc() - .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX)); - self.regs - .xidfc() - .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX)); - } - /* for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX { self.set_standard_filter((fid as u8).into(), StandardFilter::disable()); @@ -353,6 +332,51 @@ impl Registers { #[inline] pub fn apply_config(&mut self, config: FdCanConfig) { self.set_tx_buffer_mode(config.tx_buffer_mode); + + // set standard filters list size to 28 + // set extended filters list size to 8 + // REQUIRED: we use the memory map as if these settings are set + // instead of re-calculating them. + #[cfg(not(stm32h7))] + { + self.regs.rxgfc().modify(|w| { + w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX); + w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX); + }); + } + #[cfg(stm32h7)] + { + self.regs + .sidfc() + .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX)); + self.regs + .xidfc() + .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX)); + } + + self.configure_msg_ram(); + + // Enable timestamping + #[cfg(not(stm32h7))] + self.regs + .tscc() + .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); + #[cfg(stm32h7)] + self.regs.tscc().write(|w| w.set_tss(0x01)); + + // this isn't really documented in the reference manual + // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire + self.regs.txbtie().write(|w| w.0 = 0xffff_ffff); + self.regs.ie().modify(|w| { + w.set_rfne(0, true); // Rx Fifo 0 New Msg + w.set_rfne(1, true); // Rx Fifo 1 New Msg + w.set_tce(true); // Tx Complete + }); + self.regs.ile().modify(|w| { + w.set_eint0(true); // Interrupt Line 0 + w.set_eint1(true); // Interrupt Line 1 + }); + self.set_data_bit_timing(config.dbtr); self.set_nominal_bit_timing(config.nbtr); self.set_automatic_retransmit(config.automatic_retransmit); @@ -600,6 +624,71 @@ impl Registers { w.set_rrfe(filter.reject_remote_extended_frames); }); } + + #[cfg(not(stm32h7))] + fn configure_msg_ram(&mut self) {} + + #[cfg(stm32h7)] + fn configure_msg_ram(&mut self) { + let r = self.regs; + + use crate::can::fd::message_ram::*; + //use fdcan::message_ram::*; + let mut offset_words = self.msg_ram_offset as u16; + + // 11-bit filter + r.sidfc().modify(|w| w.set_flssa(offset_words)); + offset_words += STANDARD_FILTER_MAX as u16; + + // 29-bit filter + r.xidfc().modify(|w| w.set_flesa(offset_words)); + offset_words += 2 * EXTENDED_FILTER_MAX as u16; + + // Rx FIFO 0 and 1 + for i in 0..=1 { + r.rxfc(i).modify(|w| { + w.set_fsa(offset_words); + w.set_fs(RX_FIFO_MAX); + w.set_fwm(RX_FIFO_MAX); + }); + offset_words += 18 * RX_FIFO_MAX as u16; + } + + // Rx buffer - see below + // Tx event FIFO + r.txefc().modify(|w| { + w.set_efsa(offset_words); + w.set_efs(TX_EVENT_MAX); + w.set_efwm(TX_EVENT_MAX); + }); + offset_words += 2 * TX_EVENT_MAX as u16; + + // Tx buffers + r.txbc().modify(|w| { + w.set_tbsa(offset_words); + w.set_tfqs(TX_FIFO_MAX); + }); + offset_words += 18 * TX_FIFO_MAX as u16; + + // Rx Buffer - not used + r.rxbc().modify(|w| { + w.set_rbsa(offset_words); + }); + + // TX event FIFO? + // Trigger memory? + + // Set the element sizes to 16 bytes + r.rxesc().modify(|w| { + w.set_rbds(0b111); + for i in 0..=1 { + w.set_fds(i, 0b111); + } + }); + r.txesc().modify(|w| { + w.set_tbds(0b111); + }) + } } fn make_id(id: u32, extended: bool) -> embedded_can::Id { diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 77db774fc..20d00ccb5 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -184,43 +184,20 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { T::enable_and_reset(); let mut config = crate::can::fd::config::FdCanConfig::default(); + config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); T::registers().into_config_mode(config); rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - T::configure_msg_ram(); unsafe { - // Enable timestamping - #[cfg(not(stm32h7))] - T::regs() - .tscc() - .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); - #[cfg(stm32h7)] - T::regs().tscc().write(|w| w.set_tss(0x01)); - config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); - T::IT0Interrupt::unpend(); // Not unsafe T::IT0Interrupt::enable(); T::IT1Interrupt::unpend(); // Not unsafe T::IT1Interrupt::enable(); - - // this isn't really documented in the reference manual - // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire - T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); } - T::regs().ie().modify(|w| { - w.set_rfne(0, true); // Rx Fifo 0 New Msg - w.set_rfne(1, true); // Rx Fifo 1 New Msg - w.set_tce(true); // Tx Complete - }); - T::regs().ile().modify(|w| { - w.set_eint0(true); // Interrupt Line 0 - w.set_eint1(true); // Interrupt Line 1 - }); - Self { config, instance: FdcanInstance(peri), @@ -869,71 +846,6 @@ pub(crate) mod sealed { fn state() -> &'static State; unsafe fn mut_state() -> &'static mut State; fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; - - #[cfg(not(stm32h7))] - fn configure_msg_ram() {} - - #[cfg(stm32h7)] - fn configure_msg_ram() { - let r = Self::regs(); - - use crate::can::fd::message_ram::*; - //use fdcan::message_ram::*; - let mut offset_words = Self::MSG_RAM_OFFSET as u16; - - // 11-bit filter - r.sidfc().modify(|w| w.set_flssa(offset_words)); - offset_words += STANDARD_FILTER_MAX as u16; - - // 29-bit filter - r.xidfc().modify(|w| w.set_flesa(offset_words)); - offset_words += 2 * EXTENDED_FILTER_MAX as u16; - - // Rx FIFO 0 and 1 - for i in 0..=1 { - r.rxfc(i).modify(|w| { - w.set_fsa(offset_words); - w.set_fs(RX_FIFO_MAX); - w.set_fwm(RX_FIFO_MAX); - }); - offset_words += 18 * RX_FIFO_MAX as u16; - } - - // Rx buffer - see below - // Tx event FIFO - r.txefc().modify(|w| { - w.set_efsa(offset_words); - w.set_efs(TX_EVENT_MAX); - w.set_efwm(TX_EVENT_MAX); - }); - offset_words += 2 * TX_EVENT_MAX as u16; - - // Tx buffers - r.txbc().modify(|w| { - w.set_tbsa(offset_words); - w.set_tfqs(TX_FIFO_MAX); - }); - offset_words += 18 * TX_FIFO_MAX as u16; - - // Rx Buffer - not used - r.rxbc().modify(|w| { - w.set_rbsa(offset_words); - }); - - // TX event FIFO? - // Trigger memory? - - // Set the element sizes to 16 bytes - r.rxesc().modify(|w| { - w.set_rbds(0b111); - for i in 0..=1 { - w.set_fds(i, 0b111); - } - }); - r.txesc().modify(|w| { - w.set_tbds(0b111); - }) - } } } @@ -957,7 +869,7 @@ macro_rules! impl_fdcan { &crate::pac::$inst } fn registers() -> Registers { - Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst} + Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} } fn ram() -> &'static crate::pac::fdcanram::Fdcanram { &crate::pac::$msg_ram_inst From 69d37503c22be73c3d8283f39155cfa1559a37eb Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Sat, 2 Mar 2024 13:13:26 +0100 Subject: [PATCH 617/760] Add constructor for dynamic channel --- embassy-sync/src/channel.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index ff7129303..01db0d09a 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -507,6 +507,16 @@ where Receiver { channel: self } } + /// Get a sender for this channel using dynamic dispatch. + pub fn dyn_sender(&self) -> DynamicSender<'_, T> { + DynamicSender { channel: self } + } + + /// Get a receiver for this channel using dynamic dispatch. + pub fn dyn_receiver(&self) -> DynamicReceiver<'_, T> { + DynamicReceiver { channel: self } + } + /// Send a value, waiting until there is capacity. /// /// Sending completes when the value has been pushed to the channel's queue. @@ -648,7 +658,7 @@ mod tests { } #[test] - fn dynamic_dispatch() { + fn dynamic_dispatch_into() { let c = Channel::::new(); let s: DynamicSender<'_, u32> = c.sender().into(); let r: DynamicReceiver<'_, u32> = c.receiver().into(); @@ -657,6 +667,16 @@ mod tests { assert_eq!(r.try_receive().unwrap(), 1); } + #[test] + fn dynamic_dispatch_constructor() { + let c = Channel::::new(); + let s = c.dyn_sender(); + let r = c.dyn_receiver(); + + assert!(s.try_send(1).is_ok()); + assert_eq!(r.try_receive().unwrap(), 1); + } + #[futures_test::test] async fn receiver_receives_given_try_send_async() { let executor = ThreadPool::new().unwrap(); From 047b20cee42e4438bcf054c4f94812c4895508e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Sun, 3 Mar 2024 01:12:08 +0100 Subject: [PATCH 618/760] Export Error in BLE module --- embassy-nrf/src/radio/ble.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index ecf8cc5eb..93c701de0 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -12,6 +12,7 @@ use pac::radio::state::STATE_A as RadioState; pub use pac::radio::txpower::TXPOWER_A as TxPower; use crate::interrupt::typelevel::Interrupt; +pub use crate::radio::Error; use crate::radio::*; use crate::util::slice_in_ram_or; From 0c4c996339ea7e70f40b0ad77a8850728ef9dcf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Sun, 3 Mar 2024 02:15:16 +0100 Subject: [PATCH 619/760] Fixed formatting --- embassy-nrf/src/radio/ieee802154.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 32951421b..91c6dbd3b 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -3,15 +3,15 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; -use super::{Error, Instance, InterruptHandler}; -use crate::{ - interrupt::{self, typelevel::Interrupt}, - pac, Peripheral, -}; -use pac::radio::{state::STATE_A as RadioState, txpower::TXPOWER_A as TxPower}; - use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; +use pac::radio::state::STATE_A as RadioState; +use pac::radio::txpower::TXPOWER_A as TxPower; + +use super::{Error, Instance, InterruptHandler}; +use crate::interrupt::typelevel::Interrupt; +use crate::interrupt::{self}; +use crate::{pac, Peripheral}; /// Default Start of Frame Delimiter = `0xA7` (IEEE compliant) pub const DEFAULT_SFD: u8 = 0xA7; From 4bbcc2a7fbf1a363719d224dd80dfbcbbee6f26e Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Sun, 3 Mar 2024 15:35:52 +0100 Subject: [PATCH 620/760] Add OnceLock sync primitive --- embassy-sync/src/lib.rs | 1 + embassy-sync/src/once_lock.rs | 237 ++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 embassy-sync/src/once_lock.rs diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index d88c76db5..61b173e80 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -13,6 +13,7 @@ mod ring_buffer; pub mod blocking_mutex; pub mod channel; pub mod mutex; +pub mod once_lock; pub mod pipe; pub mod priority_channel; pub mod pubsub; diff --git a/embassy-sync/src/once_lock.rs b/embassy-sync/src/once_lock.rs new file mode 100644 index 000000000..f83577a6d --- /dev/null +++ b/embassy-sync/src/once_lock.rs @@ -0,0 +1,237 @@ +//! Syncronization primitive for initializing a value once, allowing others to await a reference to the value. + +use core::cell::Cell; +use core::future::poll_fn; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicBool, Ordering}; +use core::task::Poll; + +/// The `OnceLock` is a synchronization primitive that allows for +/// initializing a value once, and allowing others to `.await` a +/// reference to the value. This is useful for lazy initialization of +/// a static value. +/// +/// **Note**: this implementation uses a busy loop to poll the value, +/// which is not as efficient as registering a dedicated `Waker`. +/// However, the if the usecase for is to initialize a static variable +/// relatively early in the program life cycle, it should be fine. +/// +/// # Example +/// ``` +/// use futures_executor::block_on; +/// use embassy_sync::once_lock::OnceLock; +/// +/// // Define a static value that will be lazily initialized +/// static VALUE: OnceLock = OnceLock::new(); +/// +/// let f = async { +/// +/// // Initialize the value +/// let reference = VALUE.get_or_init(|| 20); +/// assert_eq!(reference, &20); +/// +/// // Wait for the value to be initialized +/// // and get a static reference it +/// assert_eq!(VALUE.get().await, &20); +/// +/// }; +/// block_on(f) +/// ``` +pub struct OnceLock { + init: AtomicBool, + data: Cell>, +} + +unsafe impl Sync for OnceLock {} + +impl OnceLock { + /// Create a new uninitialized `OnceLock`. + pub const fn new() -> Self { + Self { + init: AtomicBool::new(false), + data: Cell::new(MaybeUninit::zeroed()), + } + } + + /// Get a reference to the underlying value, waiting for it to be set. + /// If the value is already set, this will return immediately. + pub async fn get(&self) -> &T { + + poll_fn(|cx| match self.try_get() { + Some(data) => Poll::Ready(data), + None => { + cx.waker().wake_by_ref(); + Poll::Pending + } + }) + .await + } + + /// Try to get a reference to the underlying value if it exists. + pub fn try_get(&self) -> Option<&T> { + if self.init.load(Ordering::Relaxed) { + Some(unsafe { self.get_ref_unchecked() }) + } else { + None + } + } + + /// Set the underlying value. If the value is already set, this will return an error with the given value. + pub fn init(&self, value: T) -> Result<(), T> { + // Critical section is required to ensure that the value is + // not simultaniously initialized elsewhere at the same time. + critical_section::with(|_| { + // If the value is not set, set it and return Ok. + if !self.init.load(Ordering::Relaxed) { + self.data.set(MaybeUninit::new(value)); + self.init.store(true, Ordering::Relaxed); + Ok(()) + + // Otherwise return an error with the given value. + } else { + Err(value) + } + }) + } + + /// Get a reference to the underlying value, initializing it if it does not exist. + pub fn get_or_init(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + // Critical section is required to ensure that the value is + // not simultaniously initialized elsewhere at the same time. + critical_section::with(|_| { + // If the value is not set, set it. + if !self.init.load(Ordering::Relaxed) { + self.data.set(MaybeUninit::new(f())); + self.init.store(true, Ordering::Relaxed); + } + }); + + // Return a reference to the value. + unsafe { self.get_ref_unchecked() } + } + + /// Consume the `OnceLock`, returning the underlying value if it was initialized. + pub fn into_inner(self) -> Option { + if self.init.load(Ordering::Relaxed) { + Some(unsafe { self.data.into_inner().assume_init() }) + } else { + None + } + } + + /// Take the underlying value if it was initialized, uninitializing the `OnceLock` in the process. + pub fn take(&mut self) -> Option { + // If the value is set, uninitialize the lock and return the value. + critical_section::with(|_| { + if self.init.load(Ordering::Relaxed) { + let val = unsafe { self.data.replace(MaybeUninit::zeroed()).assume_init() }; + self.init.store(false, Ordering::Relaxed); + Some(val) + + // Otherwise return None. + } else { + None + } + }) + } + + /// Check if the value has been set. + pub fn is_set(&self) -> bool { + self.init.load(Ordering::Relaxed) + } + + /// Get a reference to the underlying value. + /// # Safety + /// Must only be used if a value has been set. + unsafe fn get_ref_unchecked(&self) -> &T { + (*self.data.as_ptr()).assume_init_ref() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn once_lock() { + let lock = OnceLock::new(); + assert_eq!(lock.try_get(), None); + assert_eq!(lock.is_set(), false); + + let v = 42; + assert_eq!(lock.init(v), Ok(())); + assert_eq!(lock.is_set(), true); + assert_eq!(lock.try_get(), Some(&v)); + assert_eq!(lock.try_get(), Some(&v)); + + let v = 43; + assert_eq!(lock.init(v), Err(v)); + assert_eq!(lock.is_set(), true); + assert_eq!(lock.try_get(), Some(&42)); + } + + #[test] + fn once_lock_get_or_init() { + let lock = OnceLock::new(); + assert_eq!(lock.try_get(), None); + assert_eq!(lock.is_set(), false); + + let v = lock.get_or_init(|| 42); + assert_eq!(v, &42); + assert_eq!(lock.is_set(), true); + assert_eq!(lock.try_get(), Some(&42)); + + let v = lock.get_or_init(|| 43); + assert_eq!(v, &42); + assert_eq!(lock.is_set(), true); + assert_eq!(lock.try_get(), Some(&42)); + } + + #[test] + fn once_lock_static() { + static LOCK: OnceLock = OnceLock::new(); + + let v: &'static i32 = LOCK.get_or_init(|| 42); + assert_eq!(v, &42); + + let v: &'static i32 = LOCK.get_or_init(|| 43); + assert_eq!(v, &42); + } + + #[futures_test::test] + async fn once_lock_async() { + static LOCK: OnceLock = OnceLock::new(); + + assert!(LOCK.init(42).is_ok()); + + let v: &'static i32 = LOCK.get().await; + assert_eq!(v, &42); + } + + #[test] + fn once_lock_into_inner() { + let lock: OnceLock = OnceLock::new(); + + let v = lock.get_or_init(|| 42); + assert_eq!(v, &42); + + assert_eq!(lock.into_inner(), Some(42)); + } + + #[test] + fn once_lock_take_init() { + let mut lock: OnceLock = OnceLock::new(); + + assert_eq!(lock.get_or_init(|| 42), &42); + assert_eq!(lock.is_set(), true); + + assert_eq!(lock.take(), Some(42)); + assert_eq!(lock.is_set(), false); + + assert_eq!(lock.get_or_init(|| 43), &43); + assert_eq!(lock.is_set(), true); + } +} From 245e7d3bc20d66fa77f6763ce5e5bec0ea6ddeff Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Sun, 3 Mar 2024 15:43:01 +0100 Subject: [PATCH 621/760] This one is for ci/rustfmt --- embassy-sync/src/once_lock.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-sync/src/once_lock.rs b/embassy-sync/src/once_lock.rs index f83577a6d..31cc99711 100644 --- a/embassy-sync/src/once_lock.rs +++ b/embassy-sync/src/once_lock.rs @@ -33,7 +33,7 @@ use core::task::Poll; /// // Wait for the value to be initialized /// // and get a static reference it /// assert_eq!(VALUE.get().await, &20); -/// +/// /// }; /// block_on(f) /// ``` @@ -56,7 +56,6 @@ impl OnceLock { /// Get a reference to the underlying value, waiting for it to be set. /// If the value is already set, this will return immediately. pub async fn get(&self) -> &T { - poll_fn(|cx| match self.try_get() { Some(data) => Poll::Ready(data), None => { From b4567bb8c56dced1c64177d727ebb32ee4680ea3 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 3 Mar 2024 23:18:29 +0100 Subject: [PATCH 622/760] stm32/rcc: g4: consistent PllSource, add pll pqr limits, simplify a bit. --- embassy-stm32/src/rcc/g4.rs | 206 +++++++++++++------------ examples/stm32g4/src/bin/adc.rs | 2 +- examples/stm32g4/src/bin/can.rs | 2 +- examples/stm32g4/src/bin/pll.rs | 29 ++-- examples/stm32g4/src/bin/usb_serial.rs | 2 +- tests/stm32/src/common.rs | 2 +- 6 files changed, 123 insertions(+), 120 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 79bdbeb77..cd2d2a8a2 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,12 +1,9 @@ -use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::Sw; -use stm32_metapac::FLASH; - +use crate::pac::flash::vals::Latency; pub use crate::pac::rcc::vals::{ - Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, - Ppre as APBPrescaler, Sw as Sysclk, + Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, + Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; -use crate::pac::{PWR, RCC}; +use crate::pac::{FLASH, PWR, RCC}; use crate::time::Hertz; /// HSI speed @@ -37,7 +34,7 @@ pub struct Hse { /// frequency ranges for each of these settings. pub struct Pll { /// PLL Source clock selection. - pub source: Pllsrc, + pub source: PllSource, /// PLL pre-divider pub prediv: PllPreDiv, @@ -73,7 +70,7 @@ pub struct Config { /// PLL Configuration pub pll: Option, - /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration + /// If PLL is requested as the main clock source in the `sys` field then the PLL configuration /// MUST turn on the PLLR output. pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -112,6 +109,7 @@ impl Default for Config { } } +#[derive(Default)] pub struct PllFreq { pub pll_p: Option, pub pll_q: Option, @@ -154,91 +152,91 @@ pub(crate) unsafe fn init(config: Config) { // Configure HSI48 if required let hsi48 = config.hsi48.map(super::init_hsi48); - let pll_freq = config.pll.map(|pll_config| { - let src_freq = match pll_config.source { - Pllsrc::HSI => unwrap!(hsi), - Pllsrc::HSE => unwrap!(hse), - _ => unreachable!(), - }; + let pll = config + .pll + .map(|pll_config| { + let src_freq = match pll_config.source { + PllSource::HSI => unwrap!(hsi), + PllSource::HSE => unwrap!(hse), + _ => unreachable!(), + }; - // Disable PLL before configuration - RCC.cr().modify(|w| w.set_pllon(false)); - while RCC.cr().read().pllrdy() {} + // Disable PLL before configuration + RCC.cr().modify(|w| w.set_pllon(false)); + while RCC.cr().read().pllrdy() {} - let in_freq = src_freq / pll_config.prediv; - assert!(max::PLL_IN.contains(&in_freq)); - let internal_freq = in_freq * pll_config.mul; + let in_freq = src_freq / pll_config.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let internal_freq = in_freq * pll_config.mul; - assert!(max::PLL_VCO.contains(&internal_freq)); + assert!(max::PLL_VCO.contains(&internal_freq)); - RCC.pllcfgr().write(|w| { - w.set_plln(pll_config.mul); - w.set_pllm(pll_config.prediv); - w.set_pllsrc(pll_config.source.into()); - }); - - let pll_p_freq = pll_config.divp.map(|div_p| { - RCC.pllcfgr().modify(|w| { - w.set_pllp(div_p); - w.set_pllpen(true); + RCC.pllcfgr().write(|w| { + w.set_plln(pll_config.mul); + w.set_pllm(pll_config.prediv); + w.set_pllsrc(pll_config.source.into()); }); - let freq = internal_freq / div_p; - assert!(max::PCLK.contains(&freq)); - freq - }); - let pll_q_freq = pll_config.divq.map(|div_q| { - RCC.pllcfgr().modify(|w| { - w.set_pllq(div_q); - w.set_pllqen(true); + let pll_p_freq = pll_config.divp.map(|div_p| { + RCC.pllcfgr().modify(|w| { + w.set_pllp(div_p); + w.set_pllpen(true); + }); + let freq = internal_freq / div_p; + assert!(max::PLL_P.contains(&freq)); + freq }); - let freq = internal_freq / div_q; - assert!(max::PCLK.contains(&freq)); - freq - }); - let pll_r_freq = pll_config.divr.map(|div_r| { - RCC.pllcfgr().modify(|w| { - w.set_pllr(div_r); - w.set_pllren(true); + let pll_q_freq = pll_config.divq.map(|div_q| { + RCC.pllcfgr().modify(|w| { + w.set_pllq(div_q); + w.set_pllqen(true); + }); + let freq = internal_freq / div_q; + assert!(max::PLL_Q.contains(&freq)); + freq }); - let freq = internal_freq / div_r; - assert!(max::PCLK.contains(&freq)); - freq - }); - // Enable the PLL - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} + let pll_r_freq = pll_config.divr.map(|div_r| { + RCC.pllcfgr().modify(|w| { + w.set_pllr(div_r); + w.set_pllren(true); + }); + let freq = internal_freq / div_r; + assert!(max::PLL_R.contains(&freq)); + freq + }); - PllFreq { - pll_p: pll_p_freq, - pll_q: pll_q_freq, - pll_r: pll_r_freq, - } - }); + // Enable the PLL + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} - let (sys_clk, sw) = match config.sys { - Sysclk::HSI => (HSI_FREQ, Sw::HSI), - Sysclk::HSE => (unwrap!(hse), Sw::HSE), - Sysclk::PLL1_R => { - assert!(pll_freq.is_some()); - assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); + PllFreq { + pll_p: pll_p_freq, + pll_q: pll_q_freq, + pll_r: pll_r_freq, + } + }) + .unwrap_or_default(); - let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0; - - assert!(max::SYSCLK.contains(&Hertz(freq))); - - (Hertz(freq), Sw::PLL1_R) - } + let sys = match config.sys { + Sysclk::HSI => unwrap!(hsi), + Sysclk::HSE => unwrap!(hse), + Sysclk::PLL1_R => unwrap!(pll.pll_r), _ => unreachable!(), }; - // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. - let hclk = sys_clk / config.ahb_pre; + assert!(max::SYSCLK.contains(&sys)); + // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. + let hclk = sys / config.ahb_pre; assert!(max::HCLK.contains(&hclk)); + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); + assert!(max::PCLK.contains(&pclk2)); + assert!(max::PCLK.contains(&pclk2)); + // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) if config.boost { // RM0440 p235 @@ -253,23 +251,28 @@ pub(crate) unsafe fn init(config: Config) { // 4. Configure and switch to new frequency } + let latency = match (config.boost, hclk.0) { + (true, ..=34_000_000) => Latency::WS0, + (true, ..=68_000_000) => Latency::WS1, + (true, ..=102_000_000) => Latency::WS2, + (true, ..=136_000_000) => Latency::WS3, + (true, _) => Latency::WS4, + + (false, ..=36_000_000) => Latency::WS0, + (false, ..=60_000_000) => Latency::WS1, + (false, ..=90_000_000) => Latency::WS2, + (false, ..=120_000_000) => Latency::WS3, + (false, _) => Latency::WS4, + }; + // Configure flash read access latency based on boost mode and frequency (RM0440 p98) FLASH.acr().modify(|w| { - w.set_latency(match (config.boost, hclk.0) { - (true, ..=34_000_000) => Latency::WS0, - (true, ..=68_000_000) => Latency::WS1, - (true, ..=102_000_000) => Latency::WS2, - (true, ..=136_000_000) => Latency::WS3, - (true, _) => Latency::WS4, - - (false, ..=36_000_000) => Latency::WS0, - (false, ..=60_000_000) => Latency::WS1, - (false, ..=90_000_000) => Latency::WS2, - (false, ..=120_000_000) => Latency::WS3, - (false, _) => Latency::WS4, - }) + w.set_latency(latency); }); + // Spin until the effective flash latency is set. + while FLASH.acr().read().latency() != latency {} + if config.boost { // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency. cortex_m::asm::delay(16); @@ -277,17 +280,14 @@ pub(crate) unsafe fn init(config: Config) { // Now that boost mode and flash read access latency are configured, set up SYSCLK RCC.cfgr().modify(|w| { - w.set_sw(sw); + w.set_sw(config.sys); w.set_hpre(config.ahb_pre); w.set_ppre1(config.apb1_pre); w.set_ppre2(config.apb2_pre); }); - let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre); - let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre); - if config.low_power_run { - assert!(sys_clk <= Hertz(2_000_000)); + assert!(sys <= Hertz(2_000_000)); PWR.cr1().modify(|w| w.set_lpr(true)); } @@ -296,17 +296,18 @@ pub(crate) unsafe fn init(config: Config) { config.mux.init(); set_clocks!( - sys: Some(sys_clk), + sys: Some(sys), hclk1: Some(hclk), hclk2: Some(hclk), hclk3: Some(hclk), - pclk1: Some(apb1_freq), - pclk1_tim: Some(apb1_tim_freq), - pclk2: Some(apb2_freq), - pclk2_tim: Some(apb2_tim_freq), - pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), - pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), - pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), + pclk1: Some(pclk1), + pclk1_tim: Some(pclk1_tim), + pclk2: Some(pclk2), + pclk2_tim: Some(pclk2_tim), + pll1_p: pll.pll_p, + pll1_q: pll.pll_q, + pll1_r: pll.pll_r, + hsi: hsi, hse: hse, hsi48: hsi48, rtc: rtc, @@ -342,4 +343,7 @@ mod max { /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46) pub(crate) const PLL_VCO: RangeInclusive = Hertz(96_000_000)..=Hertz(344_000_000); + pub(crate) const PLL_P: RangeInclusive = Hertz(2_064_500)..=Hertz(170_000_000); + pub(crate) const PLL_Q: RangeInclusive = Hertz(8_000_000)..=Hertz(170_000_000); + pub(crate) const PLL_R: RangeInclusive = Hertz(8_000_000)..=Hertz(170_000_000); } diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index f81335f93..ae64bc8e4 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { { use embassy_stm32::rcc::*; config.rcc.pll = Some(Pll { - source: Pllsrc::HSI, + source: PllSource::HSI, prediv: PllPreDiv::DIV4, mul: PllMul::MUL85, divp: None, diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 93b206de8..4373a89a8 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { mode: HseMode::Oscillator, }); config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, + source: PllSource::HSE, prediv: PllPreDiv::DIV6, mul: PllMul::MUL85, divp: None, diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs index 2609abfa2..08ed95b34 100644 --- a/examples/stm32g4/src/bin/pll.rs +++ b/examples/stm32g4/src/bin/pll.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk}; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -11,20 +10,20 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - config.rcc.hsi = true; - config.rcc.pll = Some(Pll { - source: Pllsrc::HSI, - prediv: PllPreDiv::DIV4, - mul: PllMul::MUL85, - divp: None, - divq: None, - // Main system clock at 170 MHz - divr: Some(PllRDiv::DIV2), - }); - - config.rcc.sys = Sysclk::PLL1_R; - + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.sys = Sysclk::PLL1_R; + } let _p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 90caaae14..dc95aa6e5 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { mode: HseMode::Oscillator, }); config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, + source: PllSource::HSE, prediv: PllPreDiv::DIV2, mul: PllMul::MUL72, divp: None, diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index cf3e04a4b..c3f39c04f 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -456,7 +456,7 @@ pub fn config() -> Config { mode: HseMode::Oscillator, }); config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, + source: PllSource::HSE, prediv: PllPreDiv::DIV6, mul: PllMul::MUL85, divp: None, From c8c4b0b701ecfbb146c6f651bebd43f053f55ac2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 3 Mar 2024 23:19:54 +0100 Subject: [PATCH 623/760] stm32/rcc: port g0 to new api. --- embassy-stm32/src/rcc/g0.rs | 512 +++++++++++++-------------- examples/stm32g0/src/bin/hf_timer.rs | 15 +- tests/stm32/src/common.rs | 13 + 3 files changed, 264 insertions(+), 276 deletions(-) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 5cfe9953b..ea4422ccc 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -1,7 +1,8 @@ use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::{self, Sw}; +pub use crate::pac::pwr::vals::Vos as VoltageRange; pub use crate::pac::rcc::vals::{ - Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler, + Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, + Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{FLASH, PWR, RCC}; use crate::time::Hertz; @@ -9,6 +10,7 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(16_000_000); +/// HSE Mode #[derive(Clone, Copy, Eq, PartialEq)] pub enum HseMode { /// crystal/ceramic oscillator (HSEBYP=0) @@ -17,69 +19,71 @@ pub enum HseMode { Bypass, } -/// System clock mux source -#[derive(Clone, Copy)] -pub enum Sysclk { - HSE(Hertz, HseMode), - HSI(HSIPrescaler), - PLL(PllConfig), - LSI, -} - -/// The PLL configuration. -/// -/// * `VCOCLK = source / m * n` -/// * `PLLRCLK = VCOCLK / r` -/// * `PLLQCLK = VCOCLK / q` -/// * `PLLPCLK = VCOCLK / p` -#[derive(Clone, Copy)] -pub struct PllConfig { - /// The source from which the PLL receives a clock signal - pub source: PllSource, - /// The initial divisor of that clock signal - pub m: Pllm, - /// The PLL VCO multiplier, which must be in the range `8..=86`. - pub n: Plln, - /// The final divisor for `PLLRCLK` output which drives the system clock - pub r: Pllr, - - /// The divisor for the `PLLQCLK` output, if desired - pub q: Option, - - /// The divisor for the `PLLPCLK` output, if desired - pub p: Option, -} - -impl Default for PllConfig { - #[inline] - fn default() -> PllConfig { - // HSI / 1 * 8 / 2 = 64 MHz - PllConfig { - source: PllSource::HSI, - m: Pllm::DIV1, - n: Plln::MUL8, - r: Pllr::DIV2, - q: None, - p: None, - } - } -} - +/// HSE Configuration #[derive(Clone, Copy, Eq, PartialEq)] -pub enum PllSource { - HSI, - HSE(Hertz, HseMode), +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +/// PLL Configuration +/// +/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output +/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate +/// frequency ranges for each of these settings. +pub struct Pll { + /// PLL Source clock selection. + pub source: PllSource, + + /// PLL pre-divider + pub prediv: PllPreDiv, + + /// PLL multiplication factor for VCO + pub mul: PllMul, + + /// PLL division factor for P clock (ADC Clock) + pub divp: Option, + + /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI) + pub divq: Option, + + /// PLL division factor for R clock (SYSCLK) + pub divr: Option, } /// Clocks configutation +#[non_exhaustive] pub struct Config { + /// HSI Enable + pub hsi: bool, + + /// HSE Configuration + pub hse: Option, + + /// System Clock Configuration pub sys: Sysclk, - pub ahb_pre: AHBPrescaler, - pub apb_pre: APBPrescaler, - pub low_power_run: bool, - pub ls: super::LsConfig, + + /// HSI48 Configuration #[cfg(crs)] pub hsi48: Option, + + /// PLL Configuration + pub pll: Option, + + /// If PLL is requested as the main clock source in the `sys` field then the PLL configuration + /// MUST turn on the PLLR output. + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + + /// Low-Speed Clock Configuration + pub ls: super::LsConfig, + + pub low_power_run: bool, + + pub voltage_range: VoltageRange, + /// Per-peripheral kernel clock selection muxes pub mux: super::mux::ClockMux, } @@ -88,248 +92,218 @@ impl Default for Config { #[inline] fn default() -> Config { Config { - sys: Sysclk::HSI(HSIPrescaler::DIV1), - ahb_pre: AHBPrescaler::DIV1, - apb_pre: APBPrescaler::DIV1, - low_power_run: false, - ls: Default::default(), + hsi: true, + hse: None, + sys: Sysclk::HSI, #[cfg(crs)] hsi48: Some(Default::default()), + pll: None, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + low_power_run: false, + ls: Default::default(), + voltage_range: VoltageRange::RANGE1, mux: Default::default(), } } } -impl PllConfig { - pub(crate) fn init(self) -> (Hertz, Option, Option) { - let (src, input_freq) = match self.source { - PllSource::HSI => (vals::Pllsrc::HSI, HSI_FREQ), - PllSource::HSE(freq, _) => (vals::Pllsrc::HSE, freq), - }; - - let m_freq = input_freq / self.m; - // RM0454 § 5.4.4: - // > Caution: The software must set these bits so that the PLL input frequency after the - // > /M divider is between 2.66 and 16 MHz. - debug_assert!(m_freq.0 >= 2_660_000 && m_freq.0 <= 16_000_000); - - let n_freq = m_freq * self.n as u32; - // RM0454 § 5.4.4: - // > Caution: The software must set these bits so that the VCO output frequency is between - // > 64 and 344 MHz. - debug_assert!(n_freq.0 >= 64_000_000 && n_freq.0 <= 344_000_000); - - let r_freq = n_freq / self.r; - // RM0454 § 5.4.4: - // > Caution: The software must set this bitfield so as not to exceed 64 MHz on this clock. - debug_assert!(r_freq.0 <= 64_000_000); - - let q_freq = self.q.map(|q| n_freq / q); - let p_freq = self.p.map(|p| n_freq / p); - - // RM0454 § 5.2.3: - // > To modify the PLL configuration, proceed as follows: - // > 1. Disable the PLL by setting PLLON to 0 in Clock control register (RCC_CR). - RCC.cr().modify(|w| w.set_pllon(false)); - - // > 2. Wait until PLLRDY is cleared. The PLL is now fully stopped. - while RCC.cr().read().pllrdy() {} - - // > 3. Change the desired parameter. - // Enable whichever clock source we're using, and wait for it to become ready - match self.source { - PllSource::HSI => { - RCC.cr().write(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - } - PllSource::HSE(_, mode) => { - RCC.cr().write(|w| { - w.set_hsebyp(mode != HseMode::Oscillator); - w.set_hseon(true); - }); - while !RCC.cr().read().hserdy() {} - } - } - - // Configure PLLCFGR - RCC.pllcfgr().modify(|w| { - w.set_pllr(self.r); - w.set_pllren(false); - w.set_pllq(self.q.unwrap_or(Pllq::DIV2)); - w.set_pllqen(false); - w.set_pllp(self.p.unwrap_or(Pllp::DIV2)); - w.set_pllpen(false); - w.set_plln(self.n); - w.set_pllm(self.m); - w.set_pllsrc(src) - }); - - // > 4. Enable the PLL again by setting PLLON to 1. - RCC.cr().modify(|w| w.set_pllon(true)); - - // Wait for the PLL to become ready - while !RCC.cr().read().pllrdy() {} - - // > 5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN, and PLLREN in PLL - // > configuration register (RCC_PLLCFGR). - RCC.pllcfgr().modify(|w| { - // We'll use R for system clock, so enable that unconditionally - w.set_pllren(true); - - // We may also use Q or P - w.set_pllqen(self.q.is_some()); - w.set_pllpen(self.p.is_some()); - }); - - (r_freq, q_freq, p_freq) - } +#[derive(Default)] +pub struct PllFreq { + pub pll_p: Option, + pub pll_q: Option, + pub pll_r: Option, } pub(crate) unsafe fn init(config: Config) { - let mut pll1_q_freq = None; - let mut pll1_p_freq = None; - - let (sys_clk, sw) = match config.sys { - Sysclk::HSI(div) => { - // Enable HSI - RCC.cr().write(|w| { - w.set_hsidiv(div); - w.set_hsion(true) - }); + // Configure HSI + let hsi = match config.hsi { + false => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + true => { + RCC.cr().modify(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - - (HSI_FREQ / div, Sw::HSI) - } - Sysclk::HSE(freq, mode) => { - // Enable HSE - RCC.cr().write(|w| { - w.set_hseon(true); - w.set_hsebyp(mode != HseMode::Oscillator); - }); - while !RCC.cr().read().hserdy() {} - - (freq, Sw::HSE) - } - Sysclk::PLL(pll) => { - let (r_freq, q_freq, p_freq) = pll.init(); - - pll1_q_freq = q_freq; - pll1_p_freq = p_freq; - - (r_freq, Sw::PLL1_R) - } - Sysclk::LSI => { - // Enable LSI - RCC.csr().write(|w| w.set_lsion(true)); - while !RCC.csr().read().lsirdy() {} - (super::LSI_FREQ, Sw::LSI) + Some(HSI_FREQ) } }; - // Determine the flash latency implied by the target clock speed - // RM0454 § 3.3.4: - let target_flash_latency = if sys_clk.0 <= 24_000_000 { - Latency::WS0 - } else if sys_clk.0 <= 48_000_000 { - Latency::WS1 - } else { - Latency::WS2 - }; - - // Increase the number of cycles we wait for flash if the new value is higher - // There's no harm in waiting a little too much before the clock change, but we'll - // crash immediately if we don't wait enough after the clock change - let mut set_flash_latency_after = false; - FLASH.acr().modify(|w| { - // Is the current flash latency less than what we need at the new SYSCLK? - if w.latency().to_bits() <= target_flash_latency.to_bits() { - // We must increase the number of wait states now - w.set_latency(target_flash_latency) - } else { - // We may decrease the number of wait states later - set_flash_latency_after = true; + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None } - - // RM0454 § 3.3.5: - // > Prefetch is enabled by setting the PRFTEN bit of the FLASH access control register - // > (FLASH_ACR). This feature is useful if at least one wait state is needed to access the - // > Flash memory. - // - // Enable flash prefetching if we have at least one wait state, and disable it otherwise. - w.set_prften(target_flash_latency.to_bits() > 0); - }); - - if !set_flash_latency_after { - // Spin until the effective flash latency is compatible with the clock change - while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} - } - - // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once - let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre); - RCC.cfgr().modify(|w| { - w.set_sw(sw); - w.set_hpre(hpre); - w.set_ppre(ppre); - }); - - if set_flash_latency_after { - // We can make the flash require fewer wait states - // Spin until the SYSCLK changes have taken effect - loop { - let cfgr = RCC.cfgr().read(); - if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre { - break; + Some(hse) => { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), } - } - // Set the flash latency to require fewer wait states - FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); - } - - let ahb_freq = sys_clk / config.ahb_pre; - - let (apb_freq, apb_tim_freq) = match config.apb_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) + RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) } }; + // Configure HSI48 if required + #[cfg(crs)] + let hsi48 = config.hsi48.map(super::init_hsi48); + + let pll = config + .pll + .map(|pll_config| { + let src_freq = match pll_config.source { + PllSource::HSI => unwrap!(hsi), + PllSource::HSE => unwrap!(hse), + _ => unreachable!(), + }; + + // Disable PLL before configuration + RCC.cr().modify(|w| w.set_pllon(false)); + while RCC.cr().read().pllrdy() {} + + let in_freq = src_freq / pll_config.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let internal_freq = in_freq * pll_config.mul; + + assert!(max::PLL_VCO.contains(&internal_freq)); + + RCC.pllcfgr().write(|w| { + w.set_plln(pll_config.mul); + w.set_pllm(pll_config.prediv); + w.set_pllsrc(pll_config.source.into()); + }); + + let pll_p_freq = pll_config.divp.map(|div_p| { + RCC.pllcfgr().modify(|w| { + w.set_pllp(div_p); + w.set_pllpen(true); + }); + let freq = internal_freq / div_p; + assert!(max::PLL_P.contains(&freq)); + freq + }); + + let pll_q_freq = pll_config.divq.map(|div_q| { + RCC.pllcfgr().modify(|w| { + w.set_pllq(div_q); + w.set_pllqen(true); + }); + let freq = internal_freq / div_q; + assert!(max::PLL_Q.contains(&freq)); + freq + }); + + let pll_r_freq = pll_config.divr.map(|div_r| { + RCC.pllcfgr().modify(|w| { + w.set_pllr(div_r); + w.set_pllren(true); + }); + let freq = internal_freq / div_r; + assert!(max::PLL_R.contains(&freq)); + freq + }); + + // Enable the PLL + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + + PllFreq { + pll_p: pll_p_freq, + pll_q: pll_q_freq, + pll_r: pll_r_freq, + } + }) + .unwrap_or_default(); + + let sys = match config.sys { + Sysclk::HSI => unwrap!(hsi), + Sysclk::HSE => unwrap!(hse), + Sysclk::PLL1_R => unwrap!(pll.pll_r), + _ => unreachable!(), + }; + + assert!(max::SYSCLK.contains(&sys)); + + // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. + let hclk = sys / config.ahb_pre; + assert!(max::HCLK.contains(&hclk)); + + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + assert!(max::PCLK.contains(&pclk1)); + + let latency = match (config.voltage_range, hclk.0) { + (VoltageRange::RANGE1, ..=24_000_000) => Latency::WS0, + (VoltageRange::RANGE1, ..=48_000_000) => Latency::WS1, + (VoltageRange::RANGE1, _) => Latency::WS2, + (VoltageRange::RANGE2, ..=8_000_000) => Latency::WS0, + (VoltageRange::RANGE2, ..=16_000_000) => Latency::WS1, + (VoltageRange::RANGE2, _) => Latency::WS2, + _ => unreachable!(), + }; + + // Configure flash read access latency based on voltage scale and frequency (RM0444 3.3.4) + FLASH.acr().modify(|w| { + w.set_latency(latency); + }); + + // Spin until the effective flash latency is set. + while FLASH.acr().read().latency() != latency {} + + // Now that boost mode and flash read access latency are configured, set up SYSCLK + RCC.cfgr().modify(|w| { + w.set_sw(config.sys); + w.set_hpre(config.ahb_pre); + w.set_ppre(config.apb1_pre); + }); + if config.low_power_run { - assert!(sys_clk.0 <= 2_000_000); + assert!(sys <= Hertz(2_000_000)); PWR.cr1().modify(|w| w.set_lpr(true)); } let rtc = config.ls.init(); - let lse_freq = config.ls.lse.map(|lse| lse.frequency); - - let hsi_freq = (sw == Sw::HSI).then_some(HSI_FREQ); - let hsi_div_8_freq = hsi_freq.map(|f| f / 8u32); - let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); - let hse_freq = (sw == Sw::HSE).then_some(sys_clk); - - #[cfg(crs)] - let hsi48 = config.hsi48.map(super::init_hsi48); - #[cfg(not(crs))] - let hsi48: Option = None; config.mux.init(); set_clocks!( - sys: Some(sys_clk), - hclk1: Some(ahb_freq), - pclk1: Some(apb_freq), - pclk1_tim: Some(apb_tim_freq), - hsi: hsi_freq, + sys: Some(sys), + hclk1: Some(hclk), + pclk1: Some(pclk1), + pclk1_tim: Some(pclk1_tim), + pll1_p: pll.pll_p, + pll1_q: pll.pll_q, + pll1_r: pll.pll_r, + hsi: hsi, + hse: hse, + #[cfg(crs)] hsi48: hsi48, - hsi_div_8: hsi_div_8_freq, - hse: hse_freq, - lse: lse_freq, - lsi: lsi_freq, - pll1_q: pll1_q_freq, - pll1_p: pll1_p_freq, rtc: rtc, - hsi_div_488: None, + hsi_div_8: hsi.map(|h| h / 8u32), + hsi_div_488: hsi.map(|h| h / 488u32), + + // TODO + lsi: None, + lse: None, ); } + +mod max { + use core::ops::RangeInclusive; + + use crate::time::Hertz; + + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(48_000_000); + pub(crate) const HSE_BYP: RangeInclusive = Hertz(0)..=Hertz(48_000_000); + pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(64_000_000); + pub(crate) const PCLK: RangeInclusive = Hertz(8)..=Hertz(64_000_000); + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(64_000_000); + pub(crate) const PLL_IN: RangeInclusive = Hertz(2_660_000)..=Hertz(16_000_000); + pub(crate) const PLL_VCO: RangeInclusive = Hertz(96_000_000)..=Hertz(344_000_000); + pub(crate) const PLL_P: RangeInclusive = Hertz(3_090_000)..=Hertz(122_000_000); + pub(crate) const PLL_Q: RangeInclusive = Hertz(12_000_000)..=Hertz(128_000_000); + pub(crate) const PLL_R: RangeInclusive = Hertz(12_000_000)..=Hertz(64_000_000); +} diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 647ff0419..3ea06cdee 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -16,15 +16,16 @@ async fn main(_spawner: Spawner) { let mut config = PeripheralConfig::default(); { use embassy_stm32::rcc::*; - - config.rcc.sys = Sysclk::PLL(PllConfig { + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { source: PllSource::HSI, - m: Pllm::DIV1, - n: Plln::MUL16, - r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) - q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) - p: None, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL16, + divp: None, + divq: Some(PllQDiv::DIV2), // 16 / 1 * 16 / 2 = 128 Mhz + divr: Some(PllRDiv::DIV4), // 16 / 1 * 16 / 4 = 64 Mhz }); + config.rcc.sys = Sysclk::PLL1_R; // configure TIM1 mux to select PLLQ as clock source // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index c3f39c04f..1587a6fb4 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -260,6 +260,19 @@ pub fn config() -> Config { #[allow(unused_mut)] let mut config = Config::default(); + #[cfg(feature = "stm32g071rb")] + { + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL16, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV4), // 16 / 1 * 16 / 4 = 64 Mhz + }); + config.rcc.sys = Sysclk::PLL1_R; + } #[cfg(feature = "stm32wb55rg")] { config.rcc = embassy_stm32::rcc::WPAN_DEFAULT; From ae266f3bf528c334c4712cd37305d2bcb71c0936 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 4 Mar 2024 00:03:07 +0100 Subject: [PATCH 624/760] stm32/rcc: port c0 to new api. Add c0 HSIKER/HSISYS support. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/c0.rs | 248 ++++++++++++++++++++---------------- tests/stm32/src/common.rs | 11 ++ 3 files changed, 154 insertions(+), 109 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4bbd43c47..b326c26fd 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-e853cf944b150898312984d092d63926970c340d" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e7f91751fbbf856e0cb30e50ae6db79f0409b085" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e7f91751fbbf856e0cb30e50ae6db79f0409b085", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 1946c5a15..7ca737bf0 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -1,25 +1,56 @@ use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::Sw; -pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler}; +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Hsidiv as HsiSysDiv, Hsikerdiv as HsiKerDiv, Ppre as APBPrescaler, Sw as Sysclk, +}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; /// HSI speed -pub const HSI_FREQ: Hertz = Hertz(48_000_000); +pub const HSI_FREQ: Hertz = Hertz(16_000_000); -/// System clock mux source -#[derive(Clone, Copy)] -pub enum Sysclk { - HSE(Hertz), - HSI(HSIPrescaler), - LSI, +/// HSE Mode +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1) + Bypass, +} + +/// HSE Configuration +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +/// HSI Configuration +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hsi { + /// Division factor for HSISYS clock. Default is 4. + pub sys_div: HsiSysDiv, + /// Division factor for HSIKER clock. Default is 3. + pub ker_div: HsiKerDiv, } /// Clocks configutation +#[non_exhaustive] pub struct Config { + /// HSI Configuration + pub hsi: Option, + + /// HSE Configuration + pub hse: Option, + + /// System Clock Configuration pub sys: Sysclk, + pub ahb_pre: AHBPrescaler, - pub apb_pre: APBPrescaler, + pub apb1_pre: APBPrescaler, + + /// Low-Speed Clock Configuration pub ls: super::LsConfig, /// Per-peripheral kernel clock selection muxes @@ -30,9 +61,14 @@ impl Default for Config { #[inline] fn default() -> Config { Config { - sys: Sysclk::HSI(HSIPrescaler::DIV1), + hsi: Some(Hsi { + sys_div: HsiSysDiv::DIV4, + ker_div: HsiKerDiv::DIV3, + }), + hse: None, + sys: Sysclk::HSISYS, ahb_pre: AHBPrescaler::DIV1, - apb_pre: APBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, ls: Default::default(), mux: Default::default(), } @@ -40,111 +76,109 @@ impl Default for Config { } pub(crate) unsafe fn init(config: Config) { - let (sys_clk, sw) = match config.sys { - Sysclk::HSI(div) => { - // Enable HSI - RCC.cr().write(|w| { - w.set_hsidiv(div); - w.set_hsion(true) + // Configure HSI + let (hsi, hsisys, hsiker) = match config.hsi { + None => { + RCC.cr().modify(|w| w.set_hsion(false)); + (None, None, None) + } + Some(hsi) => { + RCC.cr().modify(|w| { + w.set_hsidiv(hsi.sys_div); + w.set_hsikerdiv(hsi.ker_div); + w.set_hsion(true); }); while !RCC.cr().read().hsirdy() {} - - (HSI_FREQ / div, Sw::HSI) - } - Sysclk::HSE(freq) => { - // Enable HSE - RCC.cr().write(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - - (freq, Sw::HSE) - } - Sysclk::LSI => { - // Enable LSI - RCC.csr2().write(|w| w.set_lsion(true)); - while !RCC.csr2().read().lsirdy() {} - (super::LSI_FREQ, Sw::LSI) + ( + Some(HSI_FREQ), + Some(HSI_FREQ / hsi.sys_div), + Some(HSI_FREQ / hsi.ker_div), + ) } }; + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } + + RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } + }; + + let sys = match config.sys { + Sysclk::HSISYS => unwrap!(hsisys), + Sysclk::HSE => unwrap!(hse), + _ => unreachable!(), + }; + + assert!(max::SYSCLK.contains(&sys)); + + // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. + let hclk = sys / config.ahb_pre; + assert!(max::HCLK.contains(&hclk)); + + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + assert!(max::PCLK.contains(&pclk1)); + + let latency = match hclk.0 { + ..=24_000_000 => Latency::WS0, + _ => Latency::WS1, + }; + + // Configure flash read access latency based on voltage scale and frequency + FLASH.acr().modify(|w| { + w.set_latency(latency); + }); + + // Spin until the effective flash latency is set. + while FLASH.acr().read().latency() != latency {} + + // Now that boost mode and flash read access latency are configured, set up SYSCLK + RCC.cfgr().modify(|w| { + w.set_sw(config.sys); + w.set_hpre(config.ahb_pre); + w.set_ppre(config.apb1_pre); + }); + let rtc = config.ls.init(); - // Determine the flash latency implied by the target clock speed - // RM0454 § 3.3.4: - let target_flash_latency = if sys_clk <= Hertz(24_000_000) { - Latency::WS0 - } else { - Latency::WS1 - }; - - // Increase the number of cycles we wait for flash if the new value is higher - // There's no harm in waiting a little too much before the clock change, but we'll - // crash immediately if we don't wait enough after the clock change - let mut set_flash_latency_after = false; - FLASH.acr().modify(|w| { - // Is the current flash latency less than what we need at the new SYSCLK? - if w.latency().to_bits() <= target_flash_latency.to_bits() { - // We must increase the number of wait states now - w.set_latency(target_flash_latency) - } else { - // We may decrease the number of wait states later - set_flash_latency_after = true; - } - - // RM0490 § 3.3.4: - // > Prefetch is enabled by setting the PRFTEN bit of the FLASH access control register - // > (FLASH_ACR). This feature is useful if at least one wait state is needed to access the - // > Flash memory. - // - // Enable flash prefetching if we have at least one wait state, and disable it otherwise. - w.set_prften(target_flash_latency.to_bits() > 0); - }); - - if !set_flash_latency_after { - // Spin until the effective flash latency is compatible with the clock change - while FLASH.acr().read().latency() < target_flash_latency {} - } - - // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once - RCC.cfgr().modify(|w| { - w.set_sw(sw); - w.set_hpre(config.ahb_pre); - w.set_ppre(config.apb_pre); - }); - // Spin until the SYSCLK changes have taken effect - loop { - let cfgr = RCC.cfgr().read(); - if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre { - break; - } - } - - // Set the flash latency to require fewer wait states - if set_flash_latency_after { - FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); - } - - let ahb_freq = sys_clk / config.ahb_pre; - - let (apb_freq, apb_tim_freq) = match config.apb_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, freq * 2u32) - } - }; - config.mux.init(); - // without this, the ringbuffered uart test fails. - cortex_m::asm::dsb(); - set_clocks!( - hsi: None, - lse: None, - sys: Some(sys_clk), - hclk1: Some(ahb_freq), - pclk1: Some(apb_freq), - pclk1_tim: Some(apb_tim_freq), + sys: Some(sys), + hclk1: Some(hclk), + pclk1: Some(pclk1), + pclk1_tim: Some(pclk1_tim), + hsi: hsi, + hsiker: hsiker, + hse: hse, rtc: rtc, + + // TODO + lsi: None, + lse: None, ); } + +mod max { + use core::ops::RangeInclusive; + + use crate::time::Hertz; + + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(48_000_000); + pub(crate) const HSE_BYP: RangeInclusive = Hertz(0)..=Hertz(48_000_000); + pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(48_000_000); + pub(crate) const PCLK: RangeInclusive = Hertz(8)..=Hertz(48_000_000); + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(48_000_000); +} diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 1587a6fb4..3297ea7e2 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -260,6 +260,17 @@ pub fn config() -> Config { #[allow(unused_mut)] let mut config = Config::default(); + #[cfg(feature = "stm32c031c6")] + { + config.rcc.hsi = Some(Hsi { + sys_div: HsiSysDiv::DIV1, // 48Mhz + ker_div: HsiKerDiv::DIV3, // 16Mhz + }); + config.rcc.sys = Sysclk::HSISYS; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + } + #[cfg(feature = "stm32g071rb")] { config.rcc.hsi = true; From 873934aae5dd320133c383891b7b334d34d6454d Mon Sep 17 00:00:00 2001 From: William Yager Date: Sun, 3 Mar 2024 18:43:44 -0500 Subject: [PATCH 625/760] ok --- embassy-boot-stm32/src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/embassy-boot-stm32/src/lib.rs b/embassy-boot-stm32/src/lib.rs index 4b4091ac9..708441835 100644 --- a/embassy-boot-stm32/src/lib.rs +++ b/embassy-boot-stm32/src/lib.rs @@ -4,8 +4,8 @@ mod fmt; pub use embassy_boot::{ - AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareState, FirmwareUpdater, - FirmwareUpdaterConfig, State, + AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootError, BootLoaderConfig, FirmwareState, + FirmwareUpdater, FirmwareUpdaterConfig, State, }; use embedded_storage::nor_flash::NorFlash; @@ -20,10 +20,17 @@ impl BootLoader { pub fn prepare( config: BootLoaderConfig, ) -> Self { + Self::try_prepare::(config).expect("Boot prepare error") + } + + /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware + pub fn try_prepare( + config: BootLoaderConfig, + ) -> Result { let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); let mut boot = embassy_boot::BootLoader::new(config); - let state = boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); - Self { state } + let state = boot.prepare_boot(aligned_buf.as_mut())?; + Ok(Self { state }) } /// Boots the application. From cde6e2b58be4910c73b3738bb3b0e264c8ac6049 Mon Sep 17 00:00:00 2001 From: William Yager Date: Sun, 3 Mar 2024 18:50:27 -0500 Subject: [PATCH 626/760] ok --- embassy-boot-nrf/src/lib.rs | 17 ++++++++++++----- embassy-boot-rp/src/lib.rs | 15 +++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/embassy-boot-nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs index 5b20a93c6..6996a92f8 100644 --- a/embassy-boot-nrf/src/lib.rs +++ b/embassy-boot-nrf/src/lib.rs @@ -4,8 +4,8 @@ mod fmt; pub use embassy_boot::{ - AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareState, FirmwareUpdater, - FirmwareUpdaterConfig, + AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootError, BootLoaderConfig, FirmwareState, + FirmwareUpdater, FirmwareUpdaterConfig, }; use embassy_nrf::nvmc::PAGE_SIZE; use embassy_nrf::peripherals::WDT; @@ -16,14 +16,21 @@ use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; pub struct BootLoader; impl BootLoader { - /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware. + /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware pub fn prepare( config: BootLoaderConfig, ) -> Self { + Self::try_prepare::(config).expect("Boot prepare error") + } + + /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware + pub fn try_prepare( + config: BootLoaderConfig, + ) -> Result { let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); let mut boot = embassy_boot::BootLoader::new(config); - boot.prepare_boot(&mut aligned_buf.0).expect("Boot prepare error"); - Self + let state = boot.prepare_boot(aligned_buf.as_mut())?; + Ok(Self) } /// Boots the application without softdevice mechanisms. diff --git a/embassy-boot-rp/src/lib.rs b/embassy-boot-rp/src/lib.rs index 07a5b3f4d..d88e6dfc6 100644 --- a/embassy-boot-rp/src/lib.rs +++ b/embassy-boot-rp/src/lib.rs @@ -4,8 +4,8 @@ mod fmt; pub use embassy_boot::{ - AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareState, FirmwareUpdater, - FirmwareUpdaterConfig, State, + AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootError, BootLoaderConfig, FirmwareState, + FirmwareUpdater, FirmwareUpdaterConfig, State, }; use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE}; use embassy_rp::peripherals::{FLASH, WATCHDOG}; @@ -21,10 +21,17 @@ impl BootLoader { pub fn prepare( config: BootLoaderConfig, ) -> Self { + Self::try_prepare::(config).expect("Boot prepare error") + } + + /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware + pub fn try_prepare( + config: BootLoaderConfig, + ) -> Result { let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); let mut boot = embassy_boot::BootLoader::new(config); - boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); - Self + let state = boot.prepare_boot(aligned_buf.as_mut())?; + Ok(Self { state }) } /// Boots the application. From 0813f42d082c6dd8ec1714c1a1ed18c4f64d9590 Mon Sep 17 00:00:00 2001 From: William Yager Date: Sun, 3 Mar 2024 21:07:08 -0500 Subject: [PATCH 627/760] ci --- embassy-boot-nrf/src/lib.rs | 2 +- embassy-boot-rp/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-boot-nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs index 6996a92f8..d53e78895 100644 --- a/embassy-boot-nrf/src/lib.rs +++ b/embassy-boot-nrf/src/lib.rs @@ -29,7 +29,7 @@ impl BootLoader { ) -> Result { let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); let mut boot = embassy_boot::BootLoader::new(config); - let state = boot.prepare_boot(aligned_buf.as_mut())?; + let _state = boot.prepare_boot(aligned_buf.as_mut())?; Ok(Self) } diff --git a/embassy-boot-rp/src/lib.rs b/embassy-boot-rp/src/lib.rs index d88e6dfc6..d0a393bed 100644 --- a/embassy-boot-rp/src/lib.rs +++ b/embassy-boot-rp/src/lib.rs @@ -30,8 +30,8 @@ impl BootLoader { ) -> Result { let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); let mut boot = embassy_boot::BootLoader::new(config); - let state = boot.prepare_boot(aligned_buf.as_mut())?; - Ok(Self { state }) + let _state = boot.prepare_boot(aligned_buf.as_mut())?; + Ok(Self) } /// Boots the application. From 72c6cdc5d5bd851855975061b1c6713cf482e6fb Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Mon, 4 Mar 2024 12:22:18 +0000 Subject: [PATCH 628/760] stm32: can: fd: rename TxBufferMode::Queue -> ::Priority for clarity --- embassy-stm32/src/can/fd/config.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index adaffe9cc..68161ca50 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -292,14 +292,14 @@ impl Default for GlobalFilter { pub enum TxBufferMode { /// TX FIFO operation - In this mode CAN frames are trasmitted strictly in write order. Fifo, - /// TX queue operation - In this mode CAN frames are transmitted according to CAN priority. - Queue, + /// TX priority queue operation - In this mode CAN frames are transmitted according to CAN priority. + Priority, } impl From for crate::pac::can::vals::Tfqm { fn from(value: TxBufferMode) -> Self { match value { - TxBufferMode::Queue => Self::QUEUE, + TxBufferMode::Priority => Self::QUEUE, TxBufferMode::Fifo => Self::FIFO, } } @@ -308,7 +308,7 @@ impl From for crate::pac::can::vals::Tfqm { impl From for TxBufferMode { fn from(value: crate::pac::can::vals::Tfqm) -> Self { match value { - crate::pac::can::vals::Tfqm::QUEUE => Self::Queue, + crate::pac::can::vals::Tfqm::QUEUE => Self::Priority, crate::pac::can::vals::Tfqm::FIFO => Self::Fifo, } } @@ -354,7 +354,7 @@ pub struct FdCanConfig { pub timestamp_source: TimestampSource, /// Configures the Global Filter pub global_filter: GlobalFilter, - /// TX buffer mode (FIFO or queue) + /// TX buffer mode (FIFO or priority queue) pub tx_buffer_mode: TxBufferMode, } @@ -445,6 +445,13 @@ impl FdCanConfig { self.global_filter = filter; self } + + /// Sets the TX buffer mode (FIFO or priority queue) + #[inline] + pub const fn set_tx_buffer_mode(mut self, txbm: TxBufferMode) -> Self { + self.tx_buffer_mode = txbm; + self + } } impl Default for FdCanConfig { @@ -462,7 +469,7 @@ impl Default for FdCanConfig { clock_divider: ClockDivider::_1, timestamp_source: TimestampSource::None, global_filter: GlobalFilter::default(), - tx_buffer_mode: TxBufferMode::Queue, + tx_buffer_mode: TxBufferMode::Priority, } } } From e0018c6f4f56cdef286934fb368cd4053c209461 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Mon, 4 Mar 2024 12:22:59 +0000 Subject: [PATCH 629/760] stm32: can:fd: merge read impls; buffered RX returns Result<_, BusError> --- embassy-stm32/src/can/fdcan.rs | 65 +++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 20d00ccb5..fe8969a5a 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -398,7 +398,8 @@ impl<'d, T: Instance> Fdcan<'d, T> { } /// User supplied buffer for RX Buffering -pub type RxBuf = Channel; +pub type RxBuf = + Channel, BUF_SIZE>; /// User supplied buffer for TX buffering pub type TxBuf = Channel; @@ -440,7 +441,8 @@ impl BufferedCanSender { } /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. -pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (ClassicFrame, Timestamp)>; +pub type BufferedCanReceiver = + embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> @@ -485,7 +487,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> /// Async read frame from RX buffer. pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { - Ok(self.rx_buf.receive().await) + self.rx_buf.receive().await } /// Returns a sender that can be used for sending CAN frames. @@ -514,7 +516,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr } /// User supplied buffer for RX Buffering -pub type RxFdBuf = Channel; +pub type RxFdBuf = + Channel, BUF_SIZE>; /// User supplied buffer for TX buffering pub type TxFdBuf = Channel; @@ -556,7 +559,8 @@ impl BufferedFdCanSender { } /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. -pub type BufferedFdCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (FdFrame, Timestamp)>; +pub type BufferedFdCanReceiver = + embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>; impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> @@ -601,7 +605,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> /// Async read frame from RX buffer. pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> { - Ok(self.rx_buf.receive().await) + self.rx_buf.receive().await } /// Returns a sender that can be used for sending CAN frames. @@ -685,14 +689,14 @@ pub(crate) mod sealed { use crate::can::frame::{ClassicFrame, FdFrame}; pub struct ClassicBufferedRxInner { - pub rx_sender: DynamicSender<'static, (ClassicFrame, Timestamp)>, + pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, } pub struct ClassicBufferedTxInner { pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, } pub struct FdBufferedRxInner { - pub rx_sender: DynamicSender<'static, (FdFrame, Timestamp)>, + pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, } pub struct FdBufferedTxInner { pub tx_receiver: DynamicReceiver<'static, FdFrame>, @@ -721,46 +725,51 @@ pub(crate) mod sealed { waker.wake(); } RxMode::ClassicBuffered(buf) => { - if let Some(r) = T::registers().read(fifonr) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); - let _ = buf.rx_sender.try_send((r.0, ts)); + if let Some(result) = self.read::() { + let _ = buf.rx_sender.try_send(result); } } RxMode::FdBuffered(buf) => { - if let Some(r) = T::registers().read(fifonr) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); - let _ = buf.rx_sender.try_send((r.0, ts)); + if let Some(result) = self.read::() { + let _ = buf.rx_sender.try_send(result); } } } } - async fn read(&self) -> Result<(F, Timestamp), BusError> { + fn read(&self) -> Option> { + if let Some((msg, ts)) = T::registers().read(0) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + Some(Ok((msg, ts))) + } else if let Some((msg, ts)) = T::registers().read(1) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + Some(Ok((msg, ts))) + } else if let Some(err) = T::registers().curr_error() { + // TODO: this is probably wrong + Some(Err(err)) + } else { + None + } + } + + async fn read_async(&self) -> Result<(F, Timestamp), BusError> { poll_fn(|cx| { T::state().err_waker.register(cx.waker()); self.register(cx.waker()); - - if let Some((msg, ts)) = T::registers().read(0) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some((msg, ts)) = T::registers().read(1) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); - return Poll::Ready(Ok((msg, ts))); - } else if let Some(err) = T::registers().curr_error() { - // TODO: this is probably wrong - return Poll::Ready(Err(err)); + match self.read::() { + Some(result) => Poll::Ready(result), + None => Poll::Pending, } - Poll::Pending }) .await } pub async fn read_classic(&self) -> Result<(ClassicFrame, Timestamp), BusError> { - self.read::().await + self.read_async::().await } pub async fn read_fd(&self) -> Result<(FdFrame, Timestamp), BusError> { - self.read::().await + self.read_async::().await } } From 2a257573773f3dabdf16ea6a44ba0dadef786f37 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 4 Mar 2024 18:36:34 +0100 Subject: [PATCH 630/760] docs: clarify capabilities of zerocopy channel --- embassy-sync/src/zerocopy_channel.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index f704cbd5d..cfce9a571 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -1,10 +1,7 @@ //! A zero-copy queue for sending values between asynchronous tasks. //! -//! It can be used concurrently by multiple producers (senders) and multiple -//! consumers (receivers), i.e. it is an "MPMC channel". -//! -//! Receivers are competing for messages. So a message that is received by -//! one receiver is not received by any other. +//! It can be used concurrently by a producer (sender) and a +//! consumer (receiver), i.e. it is an "SPSC channel". //! //! This queue takes a Mutex type so that various //! targets can be attained. For example, a ThreadModeMutex can be used From c00f014f18e7ade176ed29cc06070466079d8268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Tue, 5 Mar 2024 01:03:10 +0100 Subject: [PATCH 631/760] Some more unifying, documentation --- embassy-nrf/src/radio/ble.rs | 14 +--- embassy-nrf/src/radio/ieee802154.rs | 109 ++++++++-------------------- embassy-nrf/src/radio/mod.rs | 28 +++++++ 3 files changed, 61 insertions(+), 90 deletions(-) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 93c701de0..846ac98af 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -8,8 +8,6 @@ use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; pub use pac::radio::mode::MODE_A as Mode; use pac::radio::pcnf0::PLEN_A as PreambleLength; -use pac::radio::state::STATE_A as RadioState; -pub use pac::radio::txpower::TXPOWER_A as TxPower; use crate::interrupt::typelevel::Interrupt; pub use crate::radio::Error; @@ -111,17 +109,7 @@ impl<'d, T: Instance> Radio<'d, T> { #[allow(dead_code)] fn trace_state(&self) { - match self.state() { - RadioState::DISABLED => trace!("radio:state:DISABLED"), - RadioState::RX_RU => trace!("radio:state:RX_RU"), - RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"), - RadioState::RX => trace!("radio:state:RX"), - RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"), - RadioState::TX_RU => trace!("radio:state:TX_RU"), - RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"), - RadioState::TX => trace!("radio:state:TX"), - RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"), - } + super::trace_state(T::regs()) } /// Set the radio mode diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 91c6dbd3b..2de53b392 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -1,19 +1,17 @@ -//! IEEE 802.15.4 radio +//! IEEE 802.15.4 radio driver use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; -use pac::radio::state::STATE_A as RadioState; -use pac::radio::txpower::TXPOWER_A as TxPower; -use super::{Error, Instance, InterruptHandler}; +use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; -use crate::{pac, Peripheral}; +use crate::Peripheral; -/// Default Start of Frame Delimiter = `0xA7` (IEEE compliant) +/// Default (IEEE compliant) Start of Frame Delimiter pub const DEFAULT_SFD: u8 = 0xA7; // TODO expose the other variants in `pac::CCAMODE_A` @@ -32,35 +30,14 @@ pub enum Cca { }, } -fn get_state(radio: &pac::radio::RegisterBlock) -> RadioState { - match radio.state.read().state().variant() { - Some(state) => state, - None => unreachable!(), - } -} - -fn trace_state(state: RadioState) { - match state { - RadioState::DISABLED => trace!("radio:state:DISABLED"), - RadioState::RX_RU => trace!("radio:state:RX_RU"), - RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"), - RadioState::RX => trace!("radio:state:RX"), - RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"), - RadioState::TX_RU => trace!("radio:state:TX_RU"), - RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"), - RadioState::TX => trace!("radio:state:TX"), - RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"), - } -} - -/// Radio driver. +/// IEEE 802.15.4 radio driver. pub struct Radio<'d, T: Instance> { _p: PeripheralRef<'d, T>, needs_enable: bool, } impl<'d, T: Instance> Radio<'d, T> { - /// Create a new radio driver. + /// Create a new IEEE 802.15.4 radio driver. pub fn new( radio: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -81,40 +58,43 @@ impl<'d, T: Instance> Radio<'d, T> { // Configure CRC polynomial and init r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021)); r.crcinit.write(|w| w.crcinit().bits(0)); - // Configure packet layout - // 8-bit on air length - // S0 length, zero bytes - // S1 length, zero bytes - // S1 included in RAM if S1 length > 0, No. - // Code Indicator length, 0 - // Preamble length 32-bit zero - // Exclude CRC - // No TERM field r.pcnf0.write(|w| { + // 8-bit on air length w.lflen() .bits(8) + // Zero bytes S0 field length .s0len() .clear_bit() + // Zero bytes S1 field length .s1len() .bits(0) + // Do not include S1 field in RAM if S1 length > 0 .s1incl() .clear_bit() + // Zero code Indicator length .cilen() .bits(0) + // 32-bit zero preamble .plen() ._32bit_zero() + // Include CRC in length .crcinc() .include() }); r.pcnf1.write(|w| { + // Maximum packet length w.maxlen() .bits(Packet::MAX_PSDU_LEN) + // Zero static length .statlen() .bits(0) + // Zero base address length .balen() .bits(0) + // Little-endian .endian() .clear_bit() + // Disable packet whitening .whiteen() .clear_bit() }); @@ -208,16 +188,9 @@ impl<'d, T: Instance> Radio<'d, T> { while self.state() != state {} } + /// Get the current radio state fn state(&self) -> RadioState { - let r = T::regs(); - match r.state.read().state().variant() { - Some(state) => state, - None => unreachable!(), - } - } - - fn trace_state(&self) { - trace_state(self.state()); + state(T::regs()) } /// Moves the radio from any state to the DISABLED state @@ -227,20 +200,17 @@ impl<'d, T: Instance> Radio<'d, T> { loop { match self.state() { RadioState::DISABLED => return, - + // idle or ramping up RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => { r.tasks_disable.write(|w| w.tasks_disable().set_bit()); - self.wait_for_radio_state(RadioState::DISABLED); return; } - // ramping down RadioState::RX_DISABLE | RadioState::TX_DISABLE => { self.wait_for_radio_state(RadioState::DISABLED); return; } - // cancel ongoing transfer or ongoing CCA RadioState::RX => { r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit()); @@ -262,35 +232,27 @@ impl<'d, T: Instance> Radio<'d, T> { /// Moves the radio to the RXIDLE state fn receive_prepare(&mut self) { - let state = self.state(); - - let disable = match state { + // clear related events + T::regs().events_ccabusy.reset(); + T::regs().events_phyend.reset(); + // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE + let disable = match self.state() { RadioState::DISABLED => false, - RadioState::RX_DISABLE => true, - RadioState::TX_DISABLE => true, RadioState::RX_IDLE => self.needs_enable, - // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE - RadioState::TX_IDLE => true, - _ => unreachable!(), + _ => true, }; if disable { - trace!("Receive Setup"); - self.trace_state(); self.disable(); } self.needs_enable = false; } + /// Prepare radio for receiving a packet fn receive_start(&mut self, packet: &mut Packet) { // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's // allocated in RAM let r = T::regs(); - // clear related events - r.events_framestart.reset(); - r.events_ccabusy.reset(); - r.events_phyend.reset(); - self.receive_prepare(); // Configure shortcuts @@ -314,15 +276,13 @@ impl<'d, T: Instance> Radio<'d, T> { } } + /// Cancel receiving packet fn receive_cancel() { let r = T::regs(); r.shorts.reset(); - if r.events_framestart.read().events_framestart().bit_is_set() { - // TODO: Is there a way to finish receiving this frame - } r.tasks_stop.write(|w| w.tasks_stop().set_bit()); loop { - match get_state(r) { + match state(r) { RadioState::DISABLED | RadioState::RX_IDLE => break, _ => (), } @@ -336,7 +296,7 @@ impl<'d, T: Instance> Radio<'d, T> { /// This methods returns the `Ok` variant if the CRC included the packet was successfully /// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet` /// will be updated with the received packet's data - pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), u16> { + pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), Error> { let s = T::state(); let r = T::regs(); @@ -369,7 +329,7 @@ impl<'d, T: Instance> Radio<'d, T> { if r.crcstatus.read().crcstatus().bit_is_set() { Ok(()) } else { - Err(crc) + Err(Error::CrcFailed(crc)) } } @@ -387,11 +347,6 @@ impl<'d, T: Instance> Radio<'d, T> { let s = T::state(); let r = T::regs(); - // clear related events - r.events_framestart.reset(); - r.events_ccabusy.reset(); - r.events_phyend.reset(); - // enable radio to perform cca self.receive_prepare(); diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 9b3a6cf49..333dfb33d 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -15,6 +15,9 @@ use core::marker::PhantomData; use crate::{interrupt, pac, Peripheral}; +use pac::radio::state::STATE_A as RadioState; +use pac::radio::txpower::TXPOWER_A as TxPower; + /// RADIO error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -28,6 +31,8 @@ pub enum Error { BufferNotInRAM, /// Clear channel assessment reported channel in use ChannelInUse, + /// CRC check failed + CrcFailed(u16), } /// Interrupt handler @@ -89,3 +94,26 @@ pub trait Instance: Peripheral

+ sealed::Instance + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } + +/// Get the state of the radio +pub(crate) fn state(radio: &pac::radio::RegisterBlock) -> RadioState { + match radio.state.read().state().variant() { + Some(state) => state, + None => unreachable!(), + } +} + +#[allow(dead_code)] +pub(crate) fn trace_state(radio: &pac::radio::RegisterBlock) { + match state(radio) { + RadioState::DISABLED => trace!("radio:state:DISABLED"), + RadioState::RX_RU => trace!("radio:state:RX_RU"), + RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"), + RadioState::RX => trace!("radio:state:RX"), + RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"), + RadioState::TX_RU => trace!("radio:state:TX_RU"), + RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"), + RadioState::TX => trace!("radio:state:TX"), + RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"), + } +} From 84935fbfab6a053113c135110ec4a1f4373ccfb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Tue, 5 Mar 2024 01:06:04 +0100 Subject: [PATCH 632/760] More formatting --- embassy-nrf/src/radio/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 333dfb33d..487e52d79 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -13,11 +13,11 @@ pub mod ieee802154; use core::marker::PhantomData; -use crate::{interrupt, pac, Peripheral}; - use pac::radio::state::STATE_A as RadioState; use pac::radio::txpower::TXPOWER_A as TxPower; +use crate::{interrupt, pac, Peripheral}; + /// RADIO error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] From bc258b322b3828b5e52cba3e51c7de4ec014268e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Tue, 5 Mar 2024 11:39:15 +0100 Subject: [PATCH 633/760] Support nearly all nRF5 RADIOs --- embassy-nrf/src/chips/nrf51.rs | 5 ++++ embassy-nrf/src/chips/nrf52805.rs | 5 ++++ embassy-nrf/src/chips/nrf52810.rs | 5 ++++ embassy-nrf/src/chips/nrf52811.rs | 5 ++++ embassy-nrf/src/chips/nrf52820.rs | 5 ++++ embassy-nrf/src/chips/nrf52832.rs | 5 ++++ embassy-nrf/src/chips/nrf5340_net.rs | 5 ++++ embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/radio/ble.rs | 35 +++++++++++++++++++++++++++- embassy-nrf/src/radio/ieee802154.rs | 19 +++++++++++++++ embassy-nrf/src/radio/mod.rs | 7 +++++- 11 files changed, 95 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index 016352fb8..cc1cbc8a0 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -99,6 +99,9 @@ embassy_hal_internal::peripherals! { // TEMP TEMP, + + // Radio + RADIO, } impl_timer!(TIMER0, TIMER0, TIMER0); @@ -140,6 +143,8 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 624d6613d..14c3f9b1a 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -129,6 +129,9 @@ embassy_hal_internal::peripherals! { // QDEC QDEC, + + // Radio + RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -209,6 +212,8 @@ impl_ppi_channel!(PPI_CH31, 31 => static); impl_saadc_input!(P0_04, ANALOG_INPUT2); impl_saadc_input!(P0_05, ANALOG_INPUT3); +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 002feab3b..c607586db 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -135,6 +135,9 @@ embassy_hal_internal::peripherals! { // PDM PDM, + + // Radio + RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -235,6 +238,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); impl_saadc_input!(P0_30, ANALOG_INPUT6); impl_saadc_input!(P0_31, ANALOG_INPUT7); +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 5952907f8..5f70365b4 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -135,6 +135,9 @@ embassy_hal_internal::peripherals! { // PDM PDM, + + // Radio + RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -237,6 +240,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); impl_saadc_input!(P0_30, ANALOG_INPUT6); impl_saadc_input!(P0_31, ANALOG_INPUT7); +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index c2f792cb9..82d097407 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -130,6 +130,9 @@ embassy_hal_internal::peripherals! { // QDEC QDEC, + + // Radio + RADIO, } impl_usb!(USBD, USBD, USBD); @@ -224,6 +227,8 @@ impl_ppi_channel!(PPI_CH29, 29 => static); impl_ppi_channel!(PPI_CH30, 30 => static); impl_ppi_channel!(PPI_CH31, 31 => static); +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 65d52364d..67b32fe5f 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -150,6 +150,9 @@ embassy_hal_internal::peripherals! { // PDM PDM, + + // Radio + RADIO, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -264,6 +267,8 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_i2s!(I2S, I2S, I2S); +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index a7cf82872..65e8f9653 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -248,6 +248,9 @@ embassy_hal_internal::peripherals! { P1_13, P1_14, P1_15, + + // Radio + RADIO, } impl_uarte!(SERIAL0, UARTE0, SERIAL0); @@ -345,6 +348,8 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable); impl_ppi_channel!(PPI_CH30, 30 => configurable); impl_ppi_channel!(PPI_CH31, 31 => configurable); +impl_radio!(RADIO, RADIO, RADIO); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 132bffa8b..06a25a36d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -47,7 +47,7 @@ pub mod gpio; pub mod gpiote; // TODO: tested on other chips -#[cfg(any(feature = "nrf52833", feature = "nrf52840"))] +#[cfg(not(any(feature = "nrf51", feature = "_nrf9160")))] pub mod radio; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 846ac98af..a306971b0 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -7,6 +7,7 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; pub use pac::radio::mode::MODE_A as Mode; +#[cfg(not(feature = "nrf51"))] use pac::radio::pcnf0::PLEN_A as PreambleLength; use crate::interrupt::typelevel::Interrupt; @@ -84,6 +85,7 @@ impl<'d, T: Instance> Radio<'d, T> { // Ch map between 2400 MHZ .. 2500 MHz // All modes use this range + #[cfg(not(feature = "nrf51"))] r.frequency.write(|w| w.map().default()); // Configure shortcuts to simplify and speed up sending and receiving packets. @@ -121,10 +123,18 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); r.mode.write(|w| w.mode().variant(mode)); + #[cfg(not(feature = "nrf51"))] r.pcnf0.write(|w| { w.plen().variant(match mode { Mode::BLE_1MBIT => PreambleLength::_8BIT, Mode::BLE_2MBIT => PreambleLength::_16BIT, + #[cfg(any( + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340-net" + ))] Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE, _ => unimplemented!(), }) @@ -307,7 +317,11 @@ impl<'d, T: Instance> Radio<'d, T> { self.trigger_and_wait_end(move || { // Initialize the transmission // trace!("txen"); + + #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] r.tasks_txen.write(|w| w.tasks_txen().set_bit()); + #[cfg(any(feature = "nrf51", feature = "nrf52832"))] + r.tasks_txen.write(|w| unsafe { w.bits(1) }); }) .await; @@ -324,7 +338,10 @@ impl<'d, T: Instance> Radio<'d, T> { self.trigger_and_wait_end(move || { // Initialize the transmission // trace!("rxen"); + #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()); + #[cfg(any(feature = "nrf51", feature = "nrf52832"))] + r.tasks_rxen.write(|w| unsafe { w.bits(1) }); }) .await; @@ -346,10 +363,16 @@ impl<'d, T: Instance> Radio<'d, T> { r.intenclr.write(|w| w.end().clear()); r.events_end.reset(); + #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + #[cfg(any(feature = "nrf51", feature = "nrf52832"))] + r.tasks_stop.write(|w| unsafe { w.bits(1) }); // The docs don't explicitly mention any event to acknowledge the stop task + #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] while r.events_end.read().events_end().bit_is_clear() {} + #[cfg(any(feature = "nrf51", feature = "nrf52832"))] + while r.events_end.read().bits() == 0 {} trace!("radio drop: stopped"); }); @@ -370,7 +393,11 @@ impl<'d, T: Instance> Radio<'d, T> { // On poll check if interrupt happen poll_fn(|cx| { s.event_waker.register(cx.waker()); - if r.events_end.read().events_end().bit_is_set() { + #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] + let end_event = r.events_end.read().events_end().bit_is_set(); + #[cfg(any(feature = "nrf51", feature = "nrf52832"))] + let end_event = r.events_end.read().bits() == 1; + if end_event { // trace!("radio:end"); return core::task::Poll::Ready(()); } @@ -394,10 +421,16 @@ impl<'d, T: Instance> Radio<'d, T> { if self.state() != RadioState::DISABLED { trace!("radio:disable"); // Trigger the disable task + #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] r.tasks_disable.write(|w| w.tasks_disable().set_bit()); + #[cfg(any(feature = "nrf51", feature = "nrf52832"))] + r.tasks_disable.write(|w| unsafe { w.bits(1) }); // Wait until the radio is disabled + #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] while r.events_disabled.read().events_disabled().bit_is_clear() {} + #[cfg(any(feature = "nrf51", feature = "nrf52832"))] + while r.events_disabled.read().bits() == 0 {} compiler_fence(Ordering::SeqCst); diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 2de53b392..7bec4cb8c 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -162,15 +162,34 @@ impl<'d, T: Instance> Radio<'d, T> { self.needs_enable = true; let tx_power: TxPower = match power { + #[cfg(not(feature = "_nrf5340-net"))] 8 => TxPower::POS8D_BM, + #[cfg(not(feature = "_nrf5340-net"))] 7 => TxPower::POS7D_BM, + #[cfg(not(feature = "_nrf5340-net"))] 6 => TxPower::POS6D_BM, + #[cfg(not(feature = "_nrf5340-net"))] 5 => TxPower::POS5D_BM, + #[cfg(not(feature = "_nrf5340-net"))] 4 => TxPower::POS4D_BM, + #[cfg(not(feature = "_nrf5340-net"))] 3 => TxPower::POS3D_BM, + #[cfg(not(feature = "_nrf5340-net"))] 2 => TxPower::POS2D_BM, 0 => TxPower::_0D_BM, + #[cfg(feature = "_nrf5340-net")] + -1 => TxPower::NEG1D_BM, + #[cfg(feature = "_nrf5340-net")] + -2 => TxPower::NEG2D_BM, + #[cfg(feature = "_nrf5340-net")] + -3 => TxPower::NEG3D_BM, -4 => TxPower::NEG4D_BM, + #[cfg(feature = "_nrf5340-net")] + -5 => TxPower::NEG5D_BM, + #[cfg(feature = "_nrf5340-net")] + -6 => TxPower::NEG6D_BM, + #[cfg(feature = "_nrf5340-net")] + -7 => TxPower::NEG7D_BM, -8 => TxPower::NEG8D_BM, -12 => TxPower::NEG12D_BM, -16 => TxPower::NEG16D_BM, diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 487e52d79..adb8e1206 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -7,7 +7,12 @@ /// Bluetooth Low Energy Radio driver. pub mod ble; -#[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "_nrf5340-net"))] +#[cfg(any( + feature = "nrf52820", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340-net" +))] /// IEEE 802.15.4 pub mod ieee802154; From 5408f21e993c0f94f04ed0c891b050d9a762289a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Tue, 5 Mar 2024 11:47:06 +0100 Subject: [PATCH 634/760] Fixed nrf51 radio build --- embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/radio/mod.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 06a25a36d..e59a7bd5d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -47,7 +47,7 @@ pub mod gpio; pub mod gpiote; // TODO: tested on other chips -#[cfg(not(any(feature = "nrf51", feature = "_nrf9160")))] +#[cfg(not(any(feature = "_nrf9160")))] pub mod radio; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index adb8e1206..5a2982d89 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -6,6 +6,7 @@ #![macro_use] /// Bluetooth Low Energy Radio driver. +#[cfg(not(feature = "nrf51"))] pub mod ble; #[cfg(any( feature = "nrf52820", @@ -19,6 +20,7 @@ pub mod ieee802154; use core::marker::PhantomData; use pac::radio::state::STATE_A as RadioState; +#[cfg(not(feature = "nrf51"))] use pac::radio::txpower::TXPOWER_A as TxPower; use crate::{interrupt, pac, Peripheral}; From 5b5d54c0c75e8a7fbe5370af4932c9845f4ce123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Tue, 5 Mar 2024 11:58:32 +0100 Subject: [PATCH 635/760] Do not build radio for nrf5340-app --- embassy-nrf/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index e59a7bd5d..718f229a3 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -47,7 +47,7 @@ pub mod gpio; pub mod gpiote; // TODO: tested on other chips -#[cfg(not(any(feature = "_nrf9160")))] +#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340-app")))] pub mod radio; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] From 869d590301c840cbb378a576f7c8268eec990b92 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 5 Mar 2024 21:38:05 +0800 Subject: [PATCH 636/760] ci stm32: update U5 H5 WBA target to Armv8-M --- ci.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ci.sh b/ci.sh index b2170a225..b5850aa9d 100755 --- a/ci.sh +++ b/ci.sh @@ -144,8 +144,8 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103re,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32h503rb,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32h562ag,defmt,exti,time-driver-any,time \ + --- 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 thumbv7m-none-eabi --features stm32wb35ce,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' \ @@ -178,7 +178,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \ --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \ --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \ - --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h5 \ + --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \ --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ @@ -216,10 +216,10 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --out-dir out/tests/stm32h753zi \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --out-dir out/tests/stm32h7a3zi \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u5a5zj --out-dir out/tests/stm32u5a5zj \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wba52cg --out-dir out/tests/stm32wba52cg \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h563zi --out-dir out/tests/stm32h563zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u585ai --out-dir out/tests/stm32u585ai \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5a5zj --out-dir out/tests/stm32u5a5zj \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba52cg --out-dir out/tests/stm32wba52cg \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \ From bb73d6b3fe81f26cb527d45bd700d2aef9b07090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=A5nvik?= Date: Tue, 5 Mar 2024 15:01:05 +0100 Subject: [PATCH 637/760] Fixed suggestions, added nRF51 to BLE --- embassy-nrf/src/radio/ble.rs | 36 +++-------------------------- embassy-nrf/src/radio/ieee802154.rs | 10 ++++---- embassy-nrf/src/radio/mod.rs | 20 ++-------------- embassy-nrf/src/util.rs | 1 - 4 files changed, 10 insertions(+), 57 deletions(-) diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index a306971b0..93003fb19 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -11,8 +11,8 @@ pub use pac::radio::mode::MODE_A as Mode; use pac::radio::pcnf0::PLEN_A as PreambleLength; use crate::interrupt::typelevel::Interrupt; -pub use crate::radio::Error; use crate::radio::*; +pub use crate::radio::{Error, TxPower}; use crate::util::slice_in_ram_or; /// Radio driver. @@ -103,15 +103,7 @@ impl<'d, T: Instance> Radio<'d, T> { } fn state(&self) -> RadioState { - match T::regs().state.read().state().variant() { - Some(s) => s, - None => unreachable!(), - } - } - - #[allow(dead_code)] - fn trace_state(&self) { - super::trace_state(T::regs()) + super::state(T::regs()) } /// Set the radio mode @@ -318,9 +310,6 @@ impl<'d, T: Instance> Radio<'d, T> { // Initialize the transmission // trace!("txen"); - #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] - r.tasks_txen.write(|w| w.tasks_txen().set_bit()); - #[cfg(any(feature = "nrf51", feature = "nrf52832"))] r.tasks_txen.write(|w| unsafe { w.bits(1) }); }) .await; @@ -338,9 +327,6 @@ impl<'d, T: Instance> Radio<'d, T> { self.trigger_and_wait_end(move || { // Initialize the transmission // trace!("rxen"); - #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] - r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()); - #[cfg(any(feature = "nrf51", feature = "nrf52832"))] r.tasks_rxen.write(|w| unsafe { w.bits(1) }); }) .await; @@ -363,15 +349,9 @@ impl<'d, T: Instance> Radio<'d, T> { r.intenclr.write(|w| w.end().clear()); r.events_end.reset(); - #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] - r.tasks_stop.write(|w| w.tasks_stop().set_bit()); - #[cfg(any(feature = "nrf51", feature = "nrf52832"))] r.tasks_stop.write(|w| unsafe { w.bits(1) }); // The docs don't explicitly mention any event to acknowledge the stop task - #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] - while r.events_end.read().events_end().bit_is_clear() {} - #[cfg(any(feature = "nrf51", feature = "nrf52832"))] while r.events_end.read().bits() == 0 {} trace!("radio drop: stopped"); @@ -393,11 +373,7 @@ impl<'d, T: Instance> Radio<'d, T> { // On poll check if interrupt happen poll_fn(|cx| { s.event_waker.register(cx.waker()); - #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] - let end_event = r.events_end.read().events_end().bit_is_set(); - #[cfg(any(feature = "nrf51", feature = "nrf52832"))] - let end_event = r.events_end.read().bits() == 1; - if end_event { + if r.events_end.read().bits() == 1 { // trace!("radio:end"); return core::task::Poll::Ready(()); } @@ -421,15 +397,9 @@ impl<'d, T: Instance> Radio<'d, T> { if self.state() != RadioState::DISABLED { trace!("radio:disable"); // Trigger the disable task - #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] - r.tasks_disable.write(|w| w.tasks_disable().set_bit()); - #[cfg(any(feature = "nrf51", feature = "nrf52832"))] r.tasks_disable.write(|w| unsafe { w.bits(1) }); // Wait until the radio is disabled - #[cfg(not(any(feature = "nrf51", feature = "nrf52832")))] - while r.events_disabled.read().events_disabled().bit_is_clear() {} - #[cfg(any(feature = "nrf51", feature = "nrf52832"))] while r.events_disabled.read().bits() == 0 {} compiler_fence(Ordering::SeqCst); diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 7bec4cb8c..298f8a574 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -162,19 +162,19 @@ impl<'d, T: Instance> Radio<'d, T> { self.needs_enable = true; let tx_power: TxPower = match power { - #[cfg(not(feature = "_nrf5340-net"))] + #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] 8 => TxPower::POS8D_BM, - #[cfg(not(feature = "_nrf5340-net"))] + #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] 7 => TxPower::POS7D_BM, - #[cfg(not(feature = "_nrf5340-net"))] + #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] 6 => TxPower::POS6D_BM, - #[cfg(not(feature = "_nrf5340-net"))] + #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] 5 => TxPower::POS5D_BM, #[cfg(not(feature = "_nrf5340-net"))] 4 => TxPower::POS4D_BM, #[cfg(not(feature = "_nrf5340-net"))] 3 => TxPower::POS3D_BM, - #[cfg(not(feature = "_nrf5340-net"))] + #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] 2 => TxPower::POS2D_BM, 0 => TxPower::_0D_BM, #[cfg(feature = "_nrf5340-net")] diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 5a2982d89..4c0cc3280 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -6,9 +6,9 @@ #![macro_use] /// Bluetooth Low Energy Radio driver. -#[cfg(not(feature = "nrf51"))] pub mod ble; #[cfg(any( + feature = "nrf52811", feature = "nrf52820", feature = "nrf52833", feature = "nrf52840", @@ -20,8 +20,7 @@ pub mod ieee802154; use core::marker::PhantomData; use pac::radio::state::STATE_A as RadioState; -#[cfg(not(feature = "nrf51"))] -use pac::radio::txpower::TXPOWER_A as TxPower; +pub use pac::radio::txpower::TXPOWER_A as TxPower; use crate::{interrupt, pac, Peripheral}; @@ -109,18 +108,3 @@ pub(crate) fn state(radio: &pac::radio::RegisterBlock) -> RadioState { None => unreachable!(), } } - -#[allow(dead_code)] -pub(crate) fn trace_state(radio: &pac::radio::RegisterBlock) { - match state(radio) { - RadioState::DISABLED => trace!("radio:state:DISABLED"), - RadioState::RX_RU => trace!("radio:state:RX_RU"), - RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"), - RadioState::RX => trace!("radio:state:RX"), - RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"), - RadioState::TX_RU => trace!("radio:state:TX_RU"), - RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"), - RadioState::TX => trace!("radio:state:TX"), - RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"), - } -} diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs index 6cdb97f08..13aba7dec 100644 --- a/embassy-nrf/src/util.rs +++ b/embassy-nrf/src/util.rs @@ -34,7 +34,6 @@ pub(crate) fn slice_in_ram(slice: *const [T]) -> bool { } /// Return an error if slice is not in RAM. Skips check if slice is zero-length. -#[cfg(not(feature = "nrf51"))] pub(crate) fn slice_in_ram_or(slice: *const [T], err: E) -> Result<(), E> { let (_, len) = slice_ptr_parts(slice); if len == 0 || slice_in_ram(slice) { From 6d35e3f63ca04e648a2ee33a1737f10704b388b3 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Wed, 6 Mar 2024 00:58:04 +0800 Subject: [PATCH 638/760] ci stm32: build target fix --- ci.sh | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/ci.sh b/ci.sh index b5850aa9d..cd82af2f1 100755 --- a/ci.sh +++ b/ci.sh @@ -15,7 +15,8 @@ if [ $TARGET = "x86_64-unknown-linux-gnu" ]; then BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std" fi -cargo batch \ +# CI intentionally does not use -eabihf on thumbv7em to minimize dep compile time. +cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ @@ -87,16 +88,16 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f030r8,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f031k6,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f030rc,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f070f6,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f078vb,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f042g4,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f072c8,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030r8,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f031k6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030rc,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f070f6,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f078vb,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f042g4,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f072c8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f407zg,defmt,exti,time-driver-any \ @@ -132,9 +133,9 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l051k8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073cz,defmt,exti,time-driver-any,low-power,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f303c8,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f398ve,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303c8,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f398ve,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,low-power,time \ @@ -146,7 +147,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \ --- 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 thumbv7m-none-eabi --features stm32wb35ce,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 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' \ @@ -171,10 +172,10 @@ cargo batch \ --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \ - --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \ - --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f334 \ + --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f3 \ + --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f334 \ --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \ - --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \ + --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f7 \ --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \ --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \ --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \ @@ -185,10 +186,10 @@ cargo batch \ --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ - --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ + --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \ --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ - --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ - --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ + --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \ --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \ --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \ @@ -197,14 +198,14 @@ cargo batch \ --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \ --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \ --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \ - --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \ - --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/boot/stm32wb-dfu \ + --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32wl \ + --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32wb-dfu \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ - --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf --features embassy-stm32/stm32wb55rg \ - --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabihf --features embassy-stm32/stm32h747xi-cm7 \ + --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \ + --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h747xi-cm7 \ --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ From 315fb040ee15306158d1c7c24249ee08cd22e36a Mon Sep 17 00:00:00 2001 From: Vo Trung Chi Date: Thu, 7 Mar 2024 00:45:01 +0700 Subject: [PATCH 639/760] stm32: add usb_hid_mouse example Signed-off-by: Vo Trung Chi --- examples/stm32f4/Cargo.toml | 1 + examples/stm32f4/src/bin/usb_hid_mouse.rs | 148 ++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 examples/stm32f4/src/bin/usb_hid_mouse.rs diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index cd46fc85b..512158bef 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -27,6 +27,7 @@ heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" micromath = "2.0.0" +usbd-hid = "0.7.0" static_cell = "2" chrono = { version = "^0.4", default-features = false} diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs new file mode 100644 index 000000000..add1ef306 --- /dev/null +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -0,0 +1,148 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::time::Hertz; +use embassy_stm32::usb_otg::Driver; +use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_time::Timer; +use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; +use embassy_usb::control::OutResponse; +use embassy_usb::Builder; +use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; +use futures::future::join; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + OTG_FS => usb_otg::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL168, + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. + divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV4; + config.rcc.apb2_pre = APBPrescaler::DIV2; + config.rcc.sys = Sysclk::PLL1_P; + } + let p = embassy_stm32::init(config); + + // Create the driver, from the HAL. + let mut ep_out_buffer = [0u8; 256]; + let mut config = embassy_stm32::usb_otg::Config::default(); + config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); + + // Create embassy-usb Config + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("HID mouse example"); + config.serial_number = Some("12345678"); + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let request_handler = MyRequestHandler {}; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder. + let config = embassy_usb::class::hid::Config { + report_descriptor: MouseReport::desc(), + request_handler: Some(&request_handler), + poll_ms: 60, + max_packet_size: 8, + }; + + let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do stuff with the class! + let hid_fut = async { + let mut y: i8 = 5; + loop { + Timer::after_millis(500).await; + + y = -y; + let report = MouseReport { + buttons: 0, + x: 0, + y, + wheel: 0, + pan: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + } + } + }; + +// Run everything concurrently. +// If we had made everything `'static` above instead, we could do this using separate tasks instead. +join(usb_fut, hid_fut).await; +} + +struct MyRequestHandler {} + +impl RequestHandler for MyRequestHandler { +fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + info!("Get report for {:?}", id); + None +} + +fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + info!("Set report for {:?}: {=[u8]}", id, data); + OutResponse::Accepted +} + +fn set_idle_ms(&self, id: Option, dur: u32) { + info!("Set idle rate for {:?} to {:?}", id, dur); +} + +fn get_idle_ms(&self, id: Option) -> Option { + info!("Get idle rate for {:?}", id); + None +} +} From 61653229b6c0c77235704dc3b4283f57deabc02b Mon Sep 17 00:00:00 2001 From: Vo Trung Chi Date: Thu, 7 Mar 2024 00:57:18 +0700 Subject: [PATCH 640/760] stm32: add usb_hid_mouse example Signed-off-by: Vo Trung Chi --- examples/stm32f4/src/bin/usb_hid_mouse.rs | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index add1ef306..0dc5f5804 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -10,8 +10,8 @@ use embassy_time::Timer; use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::Builder; -use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use futures::future::join; +use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -127,22 +127,22 @@ join(usb_fut, hid_fut).await; struct MyRequestHandler {} impl RequestHandler for MyRequestHandler { -fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { - info!("Get report for {:?}", id); - None -} + fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + info!("Get report for {:?}", id); + None + } -fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { - info!("Set report for {:?}: {=[u8]}", id, data); - OutResponse::Accepted -} + fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + info!("Set report for {:?}: {=[u8]}", id, data); + OutResponse::Accepted + } -fn set_idle_ms(&self, id: Option, dur: u32) { - info!("Set idle rate for {:?} to {:?}", id, dur); -} + fn set_idle_ms(&self, id: Option, dur: u32) { + info!("Set idle rate for {:?} to {:?}", id, dur); + } -fn get_idle_ms(&self, id: Option) -> Option { - info!("Get idle rate for {:?}", id); - None -} + fn get_idle_ms(&self, id: Option) -> Option { + info!("Get idle rate for {:?}", id); + None + } } From 5d53348c76242a83cdd42a69ec2ae418d43f6238 Mon Sep 17 00:00:00 2001 From: Vo Trung Chi Date: Thu, 7 Mar 2024 00:59:49 +0700 Subject: [PATCH 641/760] stm32: add usb_hid_mouse example Signed-off-by: Vo Trung Chi --- examples/stm32f4/src/bin/usb_hid_mouse.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 0dc5f5804..c98792880 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -119,9 +119,9 @@ async fn main(_spawner: Spawner) { } }; -// Run everything concurrently. -// If we had made everything `'static` above instead, we could do this using separate tasks instead. -join(usb_fut, hid_fut).await; + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, hid_fut).await; } struct MyRequestHandler {} From f3efa4ee3ba562fd51cd49b70a6c5305a1aaac6a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 6 Mar 2024 19:45:57 +0100 Subject: [PATCH 642/760] stm32/rtc: remove use of deprecated .timestamp() --- examples/stm32f4/src/bin/rtc.rs | 2 +- examples/stm32h7/src/bin/rtc.rs | 4 ++-- examples/stm32l4/src/bin/rtc.rs | 4 ++-- examples/stm32wl/src/bin/rtc.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index abab07b6b..82d8a37ba 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { loop { let now: NaiveDateTime = rtc.now().unwrap().into(); - info!("{}", now.timestamp()); + info!("{}", now.and_utc().timestamp()); Timer::after_millis(1000).await; } diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs index c6b9cf57e..0adb48877 100644 --- a/examples/stm32h7/src/bin/rtc.rs +++ b/examples/stm32h7/src/bin/rtc.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { .unwrap(); let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); - info!("Got RTC! {:?}", now.timestamp()); + info!("Got RTC! {:?}", now.and_utc().timestamp()); rtc.set_datetime(now.into()).expect("datetime not set"); @@ -32,5 +32,5 @@ async fn main(_spawner: Spawner) { Timer::after_millis(20000).await; let then: NaiveDateTime = rtc.now().unwrap().into(); - info!("Got RTC! {:?}", then.timestamp()); + info!("Got RTC! {:?}", then.and_utc().timestamp()); } diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index a8a375ab4..f554f0f78 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) { .unwrap(); let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); - info!("Got RTC! {:?}", now.timestamp()); + info!("Got RTC! {:?}", now.and_utc().timestamp()); rtc.set_datetime(now.into()).expect("datetime not set"); @@ -48,5 +48,5 @@ async fn main(_spawner: Spawner) { Timer::after_millis(20000).await; let then: NaiveDateTime = rtc.now().unwrap().into(); - info!("Got RTC! {:?}", then.timestamp()); + info!("Got RTC! {:?}", then.and_utc().timestamp()); } diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index 0c26426ef..cf7d6d220 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) { .unwrap(); let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); - info!("Got RTC! {:?}", now.timestamp()); + info!("Got RTC! {:?}", now.and_utc().timestamp()); rtc.set_datetime(now.into()).expect("datetime not set"); @@ -48,5 +48,5 @@ async fn main(_spawner: Spawner) { Timer::after_millis(20000).await; let then: NaiveDateTime = rtc.now().unwrap().into(); - info!("Got RTC! {:?}", then.timestamp()); + info!("Got RTC! {:?}", then.and_utc().timestamp()); } From f736f1b27fa71b3f9339aae876c51f381f89914a Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 3 Mar 2024 16:21:29 +1000 Subject: [PATCH 643/760] RAW copy of files from BXCAN crate. No changes whatsoever. --- embassy-stm32/src/can/bx/filter.rs | 510 ++++++++ embassy-stm32/src/can/bx/frame.rs | 255 ++++ embassy-stm32/src/can/bx/id.rs | 113 ++ embassy-stm32/src/can/bx/interrupt.rs | 130 ++ embassy-stm32/src/can/bx/mod.rs | 1100 +++++++++++++++++ embassy-stm32/src/can/bx/pac/can.rs | 213 ++++ embassy-stm32/src/can/bx/pac/can/btr.rs | 282 +++++ embassy-stm32/src/can/bx/pac/can/esr.rs | 206 ++++ embassy-stm32/src/can/bx/pac/can/fa1r.rs | 492 ++++++++ embassy-stm32/src/can/bx/pac/can/fb.rs | 22 + embassy-stm32/src/can/bx/pac/can/fb/fr1.rs | 40 + embassy-stm32/src/can/bx/pac/can/fb/fr2.rs | 40 + embassy-stm32/src/can/bx/pac/can/ffa1r.rs | 492 ++++++++ embassy-stm32/src/can/bx/pac/can/fm1r.rs | 492 ++++++++ embassy-stm32/src/can/bx/pac/can/fmr.rs | 74 ++ embassy-stm32/src/can/bx/pac/can/fs1r.rs | 492 ++++++++ embassy-stm32/src/can/bx/pac/can/ier.rs | 1218 +++++++++++++++++++ embassy-stm32/src/can/bx/pac/can/mcr.rs | 356 ++++++ embassy-stm32/src/can/bx/pac/can/msr.rs | 160 +++ embassy-stm32/src/can/bx/pac/can/rfr.rs | 281 +++++ embassy-stm32/src/can/bx/pac/can/rx.rs | 36 + embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs | 32 + embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs | 32 + embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs | 25 + embassy-stm32/src/can/bx/pac/can/rx/rir.rs | 100 ++ embassy-stm32/src/can/bx/pac/can/tsr.rs | 575 +++++++++ embassy-stm32/src/can/bx/pac/can/tx.rs | 44 + embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs | 112 ++ embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs | 112 ++ embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs | 98 ++ embassy-stm32/src/can/bx/pac/can/tx/tir.rs | 268 ++++ embassy-stm32/src/can/bx/pac/generic.rs | 256 ++++ embassy-stm32/src/can/bx/pac/mod.rs | 9 + 33 files changed, 8667 insertions(+) create mode 100644 embassy-stm32/src/can/bx/filter.rs create mode 100644 embassy-stm32/src/can/bx/frame.rs create mode 100644 embassy-stm32/src/can/bx/id.rs create mode 100644 embassy-stm32/src/can/bx/interrupt.rs create mode 100644 embassy-stm32/src/can/bx/mod.rs create mode 100644 embassy-stm32/src/can/bx/pac/can.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/btr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/esr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/fa1r.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/fb.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/fb/fr1.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/fb/fr2.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/ffa1r.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/fm1r.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/fmr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/fs1r.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/ier.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/mcr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/msr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/rfr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/rx.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/rx/rir.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/tsr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/tx.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs create mode 100644 embassy-stm32/src/can/bx/pac/can/tx/tir.rs create mode 100644 embassy-stm32/src/can/bx/pac/generic.rs create mode 100644 embassy-stm32/src/can/bx/pac/mod.rs diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bx/filter.rs new file mode 100644 index 000000000..acd2e4688 --- /dev/null +++ b/embassy-stm32/src/can/bx/filter.rs @@ -0,0 +1,510 @@ +//! Filter bank API. + +use core::marker::PhantomData; + +use crate::pac::can::RegisterBlock; +use crate::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; + +const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames +const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers +const F16_RTR: u16 = 0b10000; +const F16_IDE: u16 = 0b01000; + +/// A 16-bit filter list entry. +/// +/// This can match data and remote frames using standard IDs. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub struct ListEntry16(u16); + +/// A 32-bit filter list entry. +/// +/// This can match data and remote frames using extended or standard IDs. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub struct ListEntry32(u32); + +/// A 16-bit identifier mask. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub struct Mask16 { + id: u16, + mask: u16, +} + +/// A 32-bit identifier mask. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub struct Mask32 { + id: u32, + mask: u32, +} + +impl ListEntry16 { + /// Creates a filter list entry that accepts data frames with the given standard ID. + /// + /// This entry will *not* accept remote frames with the same ID. + pub fn data_frames_with_id(id: StandardId) -> Self { + Self(id.as_raw() << 5) + } + + /// Creates a filter list entry that accepts remote frames with the given standard ID. + pub fn remote_frames_with_id(id: StandardId) -> Self { + Self(id.as_raw() << 5 | F16_RTR) + } +} + +impl ListEntry32 { + /// Creates a filter list entry that accepts data frames with the given ID. + /// + /// This entry will *not* accept remote frames with the same ID. + /// + /// The filter will only accept *either* standard *or* extended frames, depending on `id`. + pub fn data_frames_with_id(id: impl Into) -> Self { + match id.into() { + Id::Standard(id) => Self(u32::from(id.as_raw()) << 21), + Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE), + } + } + + /// Creates a filter list entry that accepts remote frames with the given ID. + pub fn remote_frames_with_id(id: impl Into) -> Self { + match id.into() { + Id::Standard(id) => Self(u32::from(id.as_raw()) << 21 | F32_RTR), + Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE | F32_RTR), + } + } +} + +impl Mask16 { + /// Creates a 16-bit identifier mask that accepts all frames. + /// + /// This will accept both standard and extended data and remote frames with any ID. + pub fn accept_all() -> Self { + Self { id: 0, mask: 0 } + } + + /// Creates a 16-bit identifier mask that accepts all frames with the given standard + /// ID and mask combination. + /// + /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` + /// + /// A mask of all all ones (`0x7FF`) matches an exact ID, a mask of 0 matches all IDs. + /// + /// Both data and remote frames with `id` will be accepted. Any extended frames will be + /// rejected. + pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self { + Self { + id: id.as_raw() << 5, + mask: mask.as_raw() << 5 | F16_IDE, // also require IDE = 0 + } + } + + /// Make the filter accept data frames only. + pub fn data_frames_only(&mut self) -> &mut Self { + self.id &= !F16_RTR; // RTR = 0 + self.mask |= F16_RTR; + self + } + + /// Make the filter accept remote frames only. + pub fn remote_frames_only(&mut self) -> &mut Self { + self.id |= F16_RTR; // RTR = 1 + self.mask |= F16_RTR; + self + } +} + +impl Mask32 { + /// Creates a 32-bit identifier mask that accepts all frames. + /// + /// This will accept both standard and extended data and remote frames with any ID. + pub fn accept_all() -> Self { + Self { id: 0, mask: 0 } + } + + /// Creates a 32-bit identifier mask that accepts all frames with the given extended + /// ID and mask combination. + /// + /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` + /// + /// A mask of all all ones (`0x1FFF_FFFF`) matches an exact ID, a mask of 0 matches all IDs. + /// + /// Both data and remote frames with `id` will be accepted. Standard frames will be rejected. + pub fn frames_with_ext_id(id: ExtendedId, mask: ExtendedId) -> Self { + Self { + id: id.as_raw() << 3 | F32_IDE, + mask: mask.as_raw() << 3 | F32_IDE, // also require IDE = 1 + } + } + + /// Creates a 32-bit identifier mask that accepts all frames with the given standard + /// ID and mask combination. + /// + /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` + /// + /// A mask of all all ones (`0x7FF`) matches the exact ID, a mask of 0 matches all IDs. + /// + /// Both data and remote frames with `id` will be accepted. Extended frames will be rejected. + pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self { + Self { + id: u32::from(id.as_raw()) << 21, + mask: u32::from(mask.as_raw()) << 21 | F32_IDE, // also require IDE = 0 + } + } + + /// Make the filter accept data frames only. + pub fn data_frames_only(&mut self) -> &mut Self { + self.id &= !F32_RTR; // RTR = 0 + self.mask |= F32_RTR; + self + } + + /// Make the filter accept remote frames only. + pub fn remote_frames_only(&mut self) -> &mut Self { + self.id |= F32_RTR; // RTR = 1 + self.mask |= F32_RTR; + self + } +} + +/// The configuration of a filter bank. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum BankConfig { + List16([ListEntry16; 4]), + List32([ListEntry32; 2]), + Mask16([Mask16; 2]), + Mask32(Mask32), +} + +impl From<[ListEntry16; 4]> for BankConfig { + #[inline] + fn from(entries: [ListEntry16; 4]) -> Self { + Self::List16(entries) + } +} + +impl From<[ListEntry32; 2]> for BankConfig { + #[inline] + fn from(entries: [ListEntry32; 2]) -> Self { + Self::List32(entries) + } +} + +impl From<[Mask16; 2]> for BankConfig { + #[inline] + fn from(entries: [Mask16; 2]) -> Self { + Self::Mask16(entries) + } +} + +impl From for BankConfig { + #[inline] + fn from(filter: Mask32) -> Self { + Self::Mask32(filter) + } +} + +/// Interface to the filter banks of a CAN peripheral. +pub struct MasterFilters<'a, I: FilterOwner> { + /// Number of assigned filter banks. + /// + /// On chips with splittable filter banks, this value can be dynamic. + bank_count: u8, + _can: PhantomData<&'a mut I>, +} + +// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it +// exists. +impl MasterFilters<'_, I> { + pub(crate) unsafe fn new() -> Self { + let can = &*I::REGISTERS; + + // Enable initialization mode. + can.fmr.modify(|_, w| w.finit().set_bit()); + + // Read the filter split value. + let bank_count = can.fmr.read().can2sb().bits(); + + // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all + // of them to the master peripheral, and in devices with 28, assigns them 50/50 to + // master/slave instances) + + Self { + bank_count, + _can: PhantomData, + } + } + + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } + + fn banks_imm(&self) -> FilterBanks<'_> { + FilterBanks { + start_idx: 0, + bank_count: self.bank_count, + can: self.registers(), + } + } + + /// Returns the number of filter banks currently assigned to this instance. + /// + /// Chips with splittable filter banks may start out with some banks assigned to the master + /// instance and some assigned to the slave instance. + pub fn num_banks(&self) -> u8 { + self.bank_count + } + + /// Disables all enabled filter banks. + /// + /// This causes all incoming frames to be disposed. + pub fn clear(&mut self) -> &mut Self { + self.banks_imm().clear(); + self + } + + /// Disables a filter bank. + /// + /// If `index` is out of bounds, this will panic. + pub fn disable_bank(&mut self, index: u8) -> &mut Self { + self.banks_imm().disable(index); + self + } + + /// Configures a filter bank according to `config` and enables it. + /// + /// Each filter bank is associated with one of the two RX FIFOs, configured by the [`Fifo`] + /// passed to this function. In the event that both FIFOs are configured to accept an incoming + /// frame, the accepting filter bank with the lowest index wins. The FIFO state is ignored, so + /// if the FIFO is full, it will overflow, even if the other FIFO is also configured to accept + /// the frame. + /// + /// # Parameters + /// + /// - `index`: the filter index. + /// - `fifo`: the receive FIFO the filter should pass accepted messages to. + /// - `config`: the filter configuration. + pub fn enable_bank( + &mut self, + index: u8, + fifo: Fifo, + config: impl Into, + ) -> &mut Self { + self.banks_imm().enable(index, fifo, config.into()); + self + } +} + +impl MasterFilters<'_, I> { + /// Sets the index at which the filter banks owned by the slave peripheral start. + pub fn set_split(&mut self, split_index: u8) -> &mut Self { + assert!(split_index <= I::NUM_FILTER_BANKS); + self.registers() + .fmr + .modify(|_, w| unsafe { w.can2sb().bits(split_index) }); + self.bank_count = split_index; + self + } + + /// Accesses the filters assigned to the slave peripheral. + pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> { + // NB: This mutably borrows `self`, so it has full access to the filter bank registers. + SlaveFilters { + start_idx: self.bank_count, + bank_count: I::NUM_FILTER_BANKS - self.bank_count, + _can: PhantomData, + } + } +} + +impl Drop for MasterFilters<'_, I> { + #[inline] + fn drop(&mut self) { + let can = self.registers(); + + // Leave initialization mode. + can.fmr.modify(|_, w| w.finit().clear_bit()); + } +} + +/// Interface to the filter banks assigned to a slave peripheral. +pub struct SlaveFilters<'a, I: Instance> { + start_idx: u8, + bank_count: u8, + _can: PhantomData<&'a mut I>, +} + +impl SlaveFilters<'_, I> { + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } + + fn banks_imm(&self) -> FilterBanks<'_> { + FilterBanks { + start_idx: self.start_idx, + bank_count: self.bank_count, + can: self.registers(), + } + } + + /// Returns the number of filter banks currently assigned to this instance. + /// + /// Chips with splittable filter banks may start out with some banks assigned to the master + /// instance and some assigned to the slave instance. + pub fn num_banks(&self) -> u8 { + self.bank_count + } + + /// Disables all enabled filter banks. + /// + /// This causes all incoming frames to be disposed. + pub fn clear(&mut self) -> &mut Self { + self.banks_imm().clear(); + self + } + + /// Disables a filter bank. + /// + /// If `index` is out of bounds, this will panic. + pub fn disable_bank(&mut self, index: u8) -> &mut Self { + self.banks_imm().disable(index); + self + } + + /// Configures a filter bank according to `config` and enables it. + /// + /// # Parameters + /// + /// - `index`: the filter index. + /// - `fifo`: the receive FIFO the filter should pass accepted messages to. + /// - `config`: the filter configuration. + pub fn enable_bank( + &mut self, + index: u8, + fifo: Fifo, + config: impl Into, + ) -> &mut Self { + self.banks_imm().enable(index, fifo, config.into()); + self + } +} + +struct FilterBanks<'a> { + start_idx: u8, + bank_count: u8, + can: &'a RegisterBlock, +} + +impl FilterBanks<'_> { + fn clear(&mut self) { + let mask = filter_bitmask(self.start_idx, self.bank_count); + + self.can.fa1r.modify(|r, w| { + let bits = r.bits(); + // Clear all bits in `mask`. + unsafe { w.bits(bits & !mask) } + }); + } + + fn assert_bank_index(&self, index: u8) { + assert!((self.start_idx..self.start_idx + self.bank_count).contains(&index)); + } + + fn disable(&mut self, index: u8) { + self.assert_bank_index(index); + + self.can + .fa1r + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << index)) }) + } + + fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) { + self.assert_bank_index(index); + + // Configure mode. + let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_)); + self.can.fm1r.modify(|r, w| { + let mut bits = r.bits(); + if mode { + bits |= 1 << index; + } else { + bits &= !(1 << index); + } + unsafe { w.bits(bits) } + }); + + // Configure scale. + let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_)); + self.can.fs1r.modify(|r, w| { + let mut bits = r.bits(); + if scale { + bits |= 1 << index; + } else { + bits &= !(1 << index); + } + unsafe { w.bits(bits) } + }); + + // Configure filter register. + let (fxr1, fxr2); + match config { + BankConfig::List16([a, b, c, d]) => { + fxr1 = (u32::from(b.0) << 16) | u32::from(a.0); + fxr2 = (u32::from(d.0) << 16) | u32::from(c.0); + } + BankConfig::List32([a, b]) => { + fxr1 = a.0; + fxr2 = b.0; + } + BankConfig::Mask16([a, b]) => { + fxr1 = (u32::from(a.mask) << 16) | u32::from(a.id); + fxr2 = (u32::from(b.mask) << 16) | u32::from(b.id); + } + BankConfig::Mask32(a) => { + fxr1 = a.id; + fxr2 = a.mask; + } + }; + let bank = &self.can.fb[usize::from(index)]; + bank.fr1.write(|w| unsafe { w.bits(fxr1) }); + bank.fr2.write(|w| unsafe { w.bits(fxr2) }); + + // Assign to the right FIFO + self.can.ffa1r.modify(|r, w| unsafe { + let mut bits = r.bits(); + match fifo { + Fifo::Fifo0 => bits &= !(1 << index), + Fifo::Fifo1 => bits |= 1 << index, + } + w.bits(bits) + }); + + // Set active. + self.can + .fa1r + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << index)) }) + } +} + +/// Computes a bitmask for per-filter-bank registers that only includes filters in the given range. +fn filter_bitmask(start_idx: u8, bank_count: u8) -> u32 { + let count_mask = (1 << bank_count) - 1; // `bank_count` 1-bits + count_mask << start_idx +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_filter_bitmask() { + assert_eq!(filter_bitmask(0, 1), 0x1); + assert_eq!(filter_bitmask(1, 1), 0b10); + assert_eq!(filter_bitmask(0, 4), 0xf); + assert_eq!(filter_bitmask(1, 3), 0xe); + assert_eq!(filter_bitmask(8, 1), 0x100); + assert_eq!(filter_bitmask(8, 4), 0xf00); + } +} diff --git a/embassy-stm32/src/can/bx/frame.rs b/embassy-stm32/src/can/bx/frame.rs new file mode 100644 index 000000000..c1089b044 --- /dev/null +++ b/embassy-stm32/src/can/bx/frame.rs @@ -0,0 +1,255 @@ +#[cfg(test)] +mod tests; + +use core::cmp::Ordering; +use core::ops::{Deref, DerefMut}; + +use crate::{Id, IdReg}; + +/// A CAN data or remote frame. +#[derive(Clone, Debug, Eq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub struct Frame { + pub(crate) id: IdReg, + pub(crate) data: Data, +} + +impl Frame { + /// Creates a new data frame. + pub fn new_data(id: impl Into, data: impl Into) -> Self { + let id = match id.into() { + Id::Standard(id) => IdReg::new_standard(id), + Id::Extended(id) => IdReg::new_extended(id), + }; + + Self { + id, + data: data.into(), + } + } + + /// Creates a new remote frame with configurable data length code (DLC). + /// + /// # Panics + /// + /// This function will panic if `dlc` is not inside the valid range `0..=8`. + pub fn new_remote(id: impl Into, dlc: u8) -> Self { + assert!(dlc <= 8); + + let mut frame = Self::new_data(id, []); + // Just extend the data length, even with no data present. The API does not hand out this + // `Data` object. + frame.data.len = dlc; + frame.id = frame.id.with_rtr(true); + frame + } + + /// Returns true if this frame is an extended frame. + #[inline] + pub fn is_extended(&self) -> bool { + self.id.is_extended() + } + + /// Returns true if this frame is a standard frame. + #[inline] + pub fn is_standard(&self) -> bool { + self.id.is_standard() + } + + /// Returns true if this frame is a remote frame. + #[inline] + pub fn is_remote_frame(&self) -> bool { + self.id.rtr() + } + + /// Returns true if this frame is a data frame. + #[inline] + pub fn is_data_frame(&self) -> bool { + !self.is_remote_frame() + } + + /// Returns the frame identifier. + #[inline] + pub fn id(&self) -> Id { + self.id.to_id() + } + + /// Returns the priority of this frame. + #[inline] + pub fn priority(&self) -> FramePriority { + FramePriority(self.id) + } + + /// Returns the data length code (DLC) which is in the range 0..8. + /// + /// For data frames the DLC value always matches the length of the data. + /// Remote frames do not carry any data, yet the DLC can be greater than 0. + #[inline] + pub fn dlc(&self) -> u8 { + self.data.len() as u8 + } + + /// Returns the frame data (0..8 bytes in length) if this is a data frame. + /// + /// If this is a remote frame, returns `None`. + pub fn data(&self) -> Option<&Data> { + if self.is_data_frame() { + Some(&self.data) + } else { + None + } + } +} + +impl PartialEq for Frame { + fn eq(&self, other: &Self) -> bool { + match (self.data(), other.data()) { + (None, None) => self.id.eq(&other.id), + (Some(a), Some(b)) => self.id.eq(&other.id) && a.eq(b), + (None, Some(_)) | (Some(_), None) => false, + } + } +} + +/// Priority of a CAN frame. +/// +/// Returned by [`Frame::priority`]. +/// +/// The priority of a frame is determined by the bits that are part of the *arbitration field*. +/// These consist of the frame identifier bits (including the *IDE* bit, which is 0 for extended +/// frames and 1 for standard frames), as well as the *RTR* bit, which determines whether a frame +/// is a data or remote frame. Lower values of the *arbitration field* have higher priority. +/// +/// This struct wraps the *arbitration field* and implements `PartialOrd` and `Ord` accordingly, +/// ordering higher priorities greater than lower ones. +#[derive(Debug, Copy, Clone)] +pub struct FramePriority(IdReg); + +/// Ordering is based on the Identifier and frame type (data vs. remote) and can be used to sort +/// frames by priority. +impl Ord for FramePriority { + fn cmp(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0) + } +} + +impl PartialOrd for FramePriority { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for FramePriority { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Eq for FramePriority {} + +/// Payload of a CAN data frame. +/// +/// Contains 0 to 8 Bytes of data. +/// +/// `Data` implements `From<[u8; N]>` for all `N` up to 8, which provides a convenient lossless +/// conversion from fixed-length arrays. +#[derive(Debug, Copy, Clone)] +pub struct Data { + pub(crate) len: u8, + pub(crate) bytes: [u8; 8], +} + +impl Data { + /// Creates a data payload from a raw byte slice. + /// + /// Returns `None` if `data` contains more than 8 Bytes (which is the maximum). + /// + /// `Data` can also be constructed from fixed-length arrays up to length 8 via `From`/`Into`. + pub fn new(data: &[u8]) -> Option { + if data.len() > 8 { + return None; + } + + let mut bytes = [0; 8]; + bytes[..data.len()].copy_from_slice(data); + + Some(Self { + len: data.len() as u8, + bytes, + }) + } + + /// Creates an empty data payload containing 0 bytes. + #[inline] + pub const fn empty() -> Self { + Self { + len: 0, + bytes: [0; 8], + } + } +} + +impl Deref for Data { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.bytes[..usize::from(self.len)] + } +} + +impl DerefMut for Data { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.bytes[..usize::from(self.len)] + } +} + +impl AsRef<[u8]> for Data { + #[inline] + fn as_ref(&self) -> &[u8] { + self.deref() + } +} + +impl AsMut<[u8]> for Data { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + self.deref_mut() + } +} + +impl PartialEq for Data { + fn eq(&self, other: &Self) -> bool { + self.as_ref() == other.as_ref() + } +} + +impl Eq for Data {} + +#[cfg(feature = "unstable-defmt")] +impl defmt::Format for Data { + fn format(&self, fmt: defmt::Formatter<'_>) { + self.as_ref().format(fmt) + } +} + +macro_rules! data_from_array { + ( $($len:literal),+ ) => { + $( + impl From<[u8; $len]> for Data { + #[inline] + fn from(arr: [u8; $len]) -> Self { + let mut bytes = [0; 8]; + bytes[..$len].copy_from_slice(&arr); + Self { + len: $len, + bytes, + } + } + } + )+ + }; +} + +data_from_array!(0, 1, 2, 3, 4, 5, 6, 7, 8); diff --git a/embassy-stm32/src/can/bx/id.rs b/embassy-stm32/src/can/bx/id.rs new file mode 100644 index 000000000..9fdcd8319 --- /dev/null +++ b/embassy-stm32/src/can/bx/id.rs @@ -0,0 +1,113 @@ +//! CAN Identifiers. + +/// Standard 11-bit CAN Identifier (`0..=0x7FF`). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct StandardId(u16); + +impl StandardId { + /// CAN ID `0`, the highest priority. + pub const ZERO: Self = Self(0); + + /// CAN ID `0x7FF`, the lowest priority. + pub const MAX: Self = Self(0x7FF); + + /// Tries to create a `StandardId` from a raw 16-bit integer. + /// + /// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`). + #[inline] + pub const fn new(raw: u16) -> Option { + if raw <= 0x7FF { + Some(Self(raw)) + } else { + None + } + } + + /// Creates a new `StandardId` without checking if it is inside the valid range. + /// + /// # Safety + /// + /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is + /// undefined. + #[inline] + pub const unsafe fn new_unchecked(raw: u16) -> Self { + Self(raw) + } + + /// Returns this CAN Identifier as a raw 16-bit integer. + #[inline] + pub fn as_raw(&self) -> u16 { + self.0 + } +} + +/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct ExtendedId(u32); + +impl ExtendedId { + /// CAN ID `0`, the highest priority. + pub const ZERO: Self = Self(0); + + /// CAN ID `0x1FFFFFFF`, the lowest priority. + pub const MAX: Self = Self(0x1FFF_FFFF); + + /// Tries to create a `ExtendedId` from a raw 32-bit integer. + /// + /// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`). + #[inline] + pub const fn new(raw: u32) -> Option { + if raw <= 0x1FFF_FFFF { + Some(Self(raw)) + } else { + None + } + } + + /// Creates a new `ExtendedId` without checking if it is inside the valid range. + /// + /// # Safety + /// + /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is + /// undefined. + #[inline] + pub const unsafe fn new_unchecked(raw: u32) -> Self { + Self(raw) + } + + /// Returns this CAN Identifier as a raw 32-bit integer. + #[inline] + pub fn as_raw(&self) -> u32 { + self.0 + } + + /// Returns the Base ID part of this extended identifier. + pub fn standard_id(&self) -> StandardId { + // ID-28 to ID-18 + StandardId((self.0 >> 18) as u16) + } +} + +/// A CAN Identifier (standard or extended). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Id { + /// Standard 11-bit Identifier (`0..=0x7FF`). + Standard(StandardId), + + /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`). + Extended(ExtendedId), +} + +impl From for Id { + #[inline] + fn from(id: StandardId) -> Self { + Id::Standard(id) + } +} + +impl From for Id { + #[inline] + fn from(id: ExtendedId) -> Self { + Id::Extended(id) + } +} diff --git a/embassy-stm32/src/can/bx/interrupt.rs b/embassy-stm32/src/can/bx/interrupt.rs new file mode 100644 index 000000000..17aacf8e0 --- /dev/null +++ b/embassy-stm32/src/can/bx/interrupt.rs @@ -0,0 +1,130 @@ +//! Interrupt types. + +use core::ops; + +#[allow(unused_imports)] // for intra-doc links only +use crate::{Can, Rx0}; + +/// bxCAN interrupt sources. +/// +/// These can be individually enabled and disabled in the bxCAN peripheral. Note that the bxCAN +/// peripheral only exposes 4 interrupts to the microcontroller: +/// +/// * TX +/// * RX FIFO 1 +/// * RX FIFO 2 +/// * SCE (Status Change Error) +/// +/// This means that some of the interrupts listed here will result in the same interrupt handler +/// being invoked. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Interrupt { + /// Fires the **TX** interrupt when one of the transmit mailboxes returns to empty state. + /// + /// This usually happens because its message was either transmitted successfully, or + /// transmission was aborted successfully. + /// + /// The interrupt handler must clear the interrupt condition by calling + /// [`Can::clear_request_completed_flag`] or [`Can::clear_tx_interrupt`]. + TransmitMailboxEmpty = 1 << 0, + + /// Fires the **RX FIFO 0** interrupt when FIFO 0 holds a message. + /// + /// The interrupt handler must clear the interrupt condition by receiving all messages from the + /// FIFO by calling [`Can::receive`] or [`Rx0::receive`]. + Fifo0MessagePending = 1 << 1, + + /// Fires the **RX FIFO 0** interrupt when FIFO 0 holds 3 incoming messages. + /// + /// The interrupt handler must clear the interrupt condition by receiving at least one message + /// from the FIFO (making it no longer "full"). This can be done by calling [`Can::receive`] or + /// [`Rx0::receive`]. + Fifo0Full = 1 << 2, + + /// Fires the **RX FIFO 0** interrupt when FIFO 0 drops an incoming message. + /// + /// The interrupt handler must clear the interrupt condition by calling [`Can::receive`] or + /// [`Rx0::receive`] (which will return an error). + Fifo0Overrun = 1 << 3, + + /// Fires the **RX FIFO 1** interrupt when FIFO 1 holds a message. + /// + /// Behavior is otherwise identical to [`Self::Fifo0MessagePending`]. + Fifo1MessagePending = 1 << 4, + + /// Fires the **RX FIFO 1** interrupt when FIFO 1 holds 3 incoming messages. + /// + /// Behavior is otherwise identical to [`Self::Fifo0Full`]. + Fifo1Full = 1 << 5, + + /// Fires the **RX FIFO 1** interrupt when FIFO 1 drops an incoming message. + /// + /// Behavior is otherwise identical to [`Self::Fifo0Overrun`]. + Fifo1Overrun = 1 << 6, + + Error = 1 << 15, + + /// Fires the **SCE** interrupt when an incoming CAN frame is detected while the peripheral is + /// in sleep mode. + /// + /// The interrupt handler must clear the interrupt condition by calling + /// [`Can::clear_wakeup_interrupt`]. + Wakeup = 1 << 16, + + /// Fires the **SCE** interrupt when the peripheral enters sleep mode. + /// + /// The interrupt handler must clear the interrupt condition by calling + /// [`Can::clear_sleep_interrupt`]. + Sleep = 1 << 17, +} + +bitflags::bitflags! { + /// A set of bxCAN interrupts. + pub struct Interrupts: u32 { + const TRANSMIT_MAILBOX_EMPTY = 1 << 0; + const FIFO0_MESSAGE_PENDING = 1 << 1; + const FIFO0_FULL = 1 << 2; + const FIFO0_OVERRUN = 1 << 3; + const FIFO1_MESSAGE_PENDING = 1 << 4; + const FIFO1_FULL = 1 << 5; + const FIFO1_OVERRUN = 1 << 6; + const ERROR = 1 << 15; + const WAKEUP = 1 << 16; + const SLEEP = 1 << 17; + } +} + +impl From for Interrupts { + #[inline] + fn from(i: Interrupt) -> Self { + Self::from_bits_truncate(i as u32) + } +} + +/// Adds an interrupt to the interrupt set. +impl ops::BitOrAssign for Interrupts { + #[inline] + fn bitor_assign(&mut self, rhs: Interrupt) { + *self |= Self::from(rhs); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn interrupt_flags() { + assert_eq!(Interrupts::from(Interrupt::Sleep), Interrupts::SLEEP); + assert_eq!( + Interrupts::from(Interrupt::TransmitMailboxEmpty), + Interrupts::TRANSMIT_MAILBOX_EMPTY + ); + + let mut ints = Interrupts::FIFO0_FULL; + ints |= Interrupt::Fifo1Full; + assert_eq!(ints, Interrupts::FIFO0_FULL | Interrupts::FIFO1_FULL); + } +} diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs new file mode 100644 index 000000000..3cfc09c85 --- /dev/null +++ b/embassy-stm32/src/can/bx/mod.rs @@ -0,0 +1,1100 @@ +//! Driver for the STM32 bxCAN peripheral. +//! +//! This crate provides a reusable driver for the bxCAN peripheral found in many low- to middle-end +//! STM32 microcontrollers. HALs for compatible chips can reexport this crate and implement its +//! traits to easily expose a featureful CAN driver. +//! +//! # Features +//! +//! - Supports both single- and dual-peripheral configurations (where one bxCAN instance manages the +//! filters of a secondary instance). +//! - Handles standard and extended frames, and data and remote frames. +//! - Support for interrupts emitted by the bxCAN peripheral. +//! - Transmission respects CAN IDs and protects against priority inversion (a lower-priority frame +//! may be dequeued when enqueueing a higher-priority one). +//! - Implements the [`embedded-hal`] traits for interoperability. +//! - Support for both RX FIFOs (as [`Rx0`] and [`Rx1`]). +//! +//! # Limitations +//! +//! - Support for querying error states and handling error interrupts is incomplete. +//! +//! # Cargo Features +//! +//! | Feature | Description | +//! |---------|-------------| +//! | `unstable-defmt` | Implements [`defmt`]'s `Format` trait for the types in this crate.[^1] | +//! +//! [^1]: The specific version of defmt is unspecified and may be updated in a patch release. +//! +//! [`defmt`]: https://docs.rs/defmt +//! [`embedded-hal`]: https://docs.rs/embedded-hal + +#![doc(html_root_url = "https://docs.rs/bxcan/0.7.0")] +// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default +#![doc(test(attr(deny(unused_imports, unused_must_use))))] +#![no_std] +#![allow(clippy::unnecessary_operation)] // lint is bugged + +mod embedded_hal; +pub mod filter; +mod frame; +mod id; +mod interrupt; + +#[allow(clippy::all)] // generated code +mod pac; + +pub use id::{ExtendedId, Id, StandardId}; + +pub use crate::frame::{Data, Frame, FramePriority}; +pub use crate::interrupt::{Interrupt, Interrupts}; +pub use crate::pac::can::RegisterBlock; + +use crate::filter::MasterFilters; +use core::cmp::{Ord, Ordering}; +use core::convert::{Infallible, TryInto}; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; + +use self::pac::generic::*; // To make the PAC extraction build + +/// A bxCAN peripheral instance. +/// +/// This trait is meant to be implemented for a HAL-specific type that represent ownership of +/// the CAN peripheral (and any pins required by it, although that is entirely up to the HAL). +/// +/// # Safety +/// +/// It is only safe to implement this trait, when: +/// +/// * The implementing type has ownership of the peripheral, preventing any other accesses to the +/// register block. +/// * `REGISTERS` is a pointer to that peripheral's register block and can be safely accessed for as +/// long as ownership or a borrow of the implementing type is present. +pub unsafe trait Instance { + /// Pointer to the instance's register block. + const REGISTERS: *mut RegisterBlock; +} + +/// A bxCAN instance that owns filter banks. +/// +/// In master-slave-instance setups, only the master instance owns the filter banks, and needs to +/// split some of them off for use by the slave instance. In that case, the master instance should +/// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement +/// [`Instance`]. +/// +/// In single-instance configurations, the instance owns all filter banks and they can not be split +/// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`]. +/// +/// # Safety +/// +/// This trait must only be implemented if the instance does, in fact, own its associated filter +/// banks, and `NUM_FILTER_BANKS` must be correct. +pub unsafe trait FilterOwner: Instance { + /// The total number of filter banks available to the instance. + /// + /// This is usually either 14 or 28, and should be specified in the chip's reference manual or + /// datasheet. + const NUM_FILTER_BANKS: u8; +} + +/// A bxCAN master instance that shares filter banks with a slave instance. +/// +/// In master-slave-instance setups, this trait should be implemented for the master instance. +/// +/// # Safety +/// +/// This trait must only be implemented when there is actually an associated slave instance. +pub unsafe trait MasterInstance: FilterOwner {} + +// TODO: what to do with these? +/* +#[derive(Debug, Copy, Clone, Eq, PartialEq, Format)] +pub enum Error { + Stuff, + Form, + Acknowledgement, + BitRecessive, + BitDominant, + Crc, + Software, +}*/ + +/// Error that indicates that an incoming message has been lost due to buffer overrun. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub struct OverrunError { + _priv: (), +} + +/// Identifier of a CAN message. +/// +/// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a +/// extendended identifier (29bit , Range: 0..0x1FFFFFFF). +/// +/// The `Ord` trait can be used to determine the frame’s priority this ID +/// belongs to. +/// Lower identifier values have a higher priority. Additionally standard frames +/// have a higher priority than extended frames and data frames have a higher +/// priority than remote frames. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +struct IdReg(u32); + +impl IdReg { + const STANDARD_SHIFT: u32 = 21; + + const EXTENDED_SHIFT: u32 = 3; + + const IDE_MASK: u32 = 0x0000_0004; + + const RTR_MASK: u32 = 0x0000_0002; + + /// Creates a new standard identifier (11bit, Range: 0..0x7FF) + /// + /// Panics for IDs outside the allowed range. + fn new_standard(id: StandardId) -> Self { + Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT) + } + + /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF). + /// + /// Panics for IDs outside the allowed range. + fn new_extended(id: ExtendedId) -> IdReg { + Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK) + } + + fn from_register(reg: u32) -> IdReg { + Self(reg & 0xFFFF_FFFE) + } + + /// Sets the remote transmission (RTR) flag. This marks the identifier as + /// being part of a remote frame. + #[must_use = "returns a new IdReg without modifying `self`"] + fn with_rtr(self, rtr: bool) -> IdReg { + if rtr { + Self(self.0 | Self::RTR_MASK) + } else { + Self(self.0 & !Self::RTR_MASK) + } + } + + /// Returns the identifier. + fn to_id(self) -> Id { + if self.is_extended() { + Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) + } else { + Id::Standard(unsafe { + StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) + }) + } + } + + /// Returns `true` if the identifier is an extended identifier. + fn is_extended(self) -> bool { + self.0 & Self::IDE_MASK != 0 + } + + /// Returns `true` if the identifier is a standard identifier. + fn is_standard(self) -> bool { + !self.is_extended() + } + + /// Returns `true` if the identifer is part of a remote frame (RTR bit set). + fn rtr(self) -> bool { + self.0 & Self::RTR_MASK != 0 + } +} + +/// `IdReg` is ordered by priority. +impl Ord for IdReg { + fn cmp(&self, other: &Self) -> Ordering { + // When the IDs match, data frames have priority over remote frames. + let rtr = self.rtr().cmp(&other.rtr()).reverse(); + + let id_a = self.to_id(); + let id_b = other.to_id(); + match (id_a, id_b) { + (Id::Standard(a), Id::Standard(b)) => { + // Lower IDs have priority over higher IDs. + a.as_raw().cmp(&b.as_raw()).reverse().then(rtr) + } + (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr), + (Id::Standard(a), Id::Extended(b)) => { + // Standard frames have priority over extended frames if their Base IDs match. + a.as_raw() + .cmp(&b.standard_id().as_raw()) + .reverse() + .then(Ordering::Greater) + } + (Id::Extended(a), Id::Standard(b)) => a + .standard_id() + .as_raw() + .cmp(&b.as_raw()) + .reverse() + .then(Ordering::Less), + } + } +} + +impl PartialOrd for IdReg { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// Configuration proxy returned by [`Can::modify_config`]. +#[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] +pub struct CanConfig<'a, I: Instance> { + can: &'a mut Can, +} + +impl CanConfig<'_, I> { + /// Configures the bit timings. + /// + /// You can use to calculate the `btr` parameter. Enter + /// parameters as follows: + /// + /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). + /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). + /// - *Sample Point*: Should normally be left at the default value of 87.5%. + /// - *SJW*: Should normally be left at the default value of 1. + /// + /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` + /// parameter to this method. + pub fn set_bit_timing(self, btr: u32) -> Self { + self.can.set_bit_timing(btr); + self + } + + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + pub fn set_loopback(self, enabled: bool) -> Self { + let can = self.can.registers(); + can.btr.modify(|_, w| w.lbkm().bit(enabled)); + self + } + + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + pub fn set_silent(self, enabled: bool) -> Self { + let can = self.can.registers(); + can.btr.modify(|_, w| w.silm().bit(enabled)); + self + } + + /// Enables or disables automatic retransmission of messages. + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// until it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + pub fn set_automatic_retransmit(self, enabled: bool) -> Self { + let can = self.can.registers(); + can.mcr.modify(|_, w| w.nart().bit(!enabled)); + self + } + + /// Leaves initialization mode and enables the peripheral. + /// + /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected + /// on the bus. + /// + /// If you want to finish configuration without enabling the peripheral, you can call + /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. + pub fn enable(mut self) { + self.leave_init_mode(); + + match nb::block!(self.can.enable_non_blocking()) { + Ok(()) => {} + Err(void) => match void {}, + } + + // Don't run the destructor. + mem::forget(self); + } + + /// Leaves initialization mode, but keeps the peripheral in sleep mode. + /// + /// Before the [`Can`] instance can be used, you have to enable it by calling + /// [`Can::enable_non_blocking`]. + pub fn leave_disabled(mut self) { + self.leave_init_mode(); + } + + /// Leaves initialization mode, enters sleep mode. + fn leave_init_mode(&mut self) { + let can = self.can.registers(); + can.mcr + .modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + loop { + let msr = can.msr.read(); + if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { + break; + } + } + } +} + +impl Drop for CanConfig<'_, I> { + #[inline] + fn drop(&mut self) { + self.leave_init_mode(); + } +} + +/// Builder returned by [`Can::builder`]. +#[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"] +pub struct CanBuilder { + can: Can, +} + +impl CanBuilder { + /// Configures the bit timings. + /// + /// You can use to calculate the `btr` parameter. Enter + /// parameters as follows: + /// + /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). + /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). + /// - *Sample Point*: Should normally be left at the default value of 87.5%. + /// - *SJW*: Should normally be left at the default value of 1. + /// + /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` + /// parameter to this method. + pub fn set_bit_timing(mut self, btr: u32) -> Self { + self.can.set_bit_timing(btr); + self + } + + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + pub fn set_loopback(self, enabled: bool) -> Self { + let can = self.can.registers(); + can.btr.modify(|_, w| w.lbkm().bit(enabled)); + self + } + + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + pub fn set_silent(self, enabled: bool) -> Self { + let can = self.can.registers(); + can.btr.modify(|_, w| w.silm().bit(enabled)); + self + } + + /// Enables or disables automatic retransmission of messages. + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// until it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + pub fn set_automatic_retransmit(self, enabled: bool) -> Self { + let can = self.can.registers(); + can.mcr.modify(|_, w| w.nart().bit(!enabled)); + self + } + + /// Leaves initialization mode and enables the peripheral. + /// + /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected + /// on the bus. + /// + /// If you want to finish configuration without enabling the peripheral, you can call + /// [`CanBuilder::leave_disabled`] instead. + pub fn enable(mut self) -> Can { + self.leave_init_mode(); + + match nb::block!(self.can.enable_non_blocking()) { + Ok(()) => self.can, + Err(void) => match void {}, + } + } + + /// Returns the [`Can`] interface without enabling it. + /// + /// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling + /// it. + /// + /// Before the [`Can`] instance can be used, you have to enable it by calling + /// [`Can::enable_non_blocking`]. + pub fn leave_disabled(mut self) -> Can { + self.leave_init_mode(); + self.can + } + + /// Leaves initialization mode, enters sleep mode. + fn leave_init_mode(&mut self) { + let can = self.can.registers(); + can.mcr + .modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + loop { + let msr = can.msr.read(); + if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { + break; + } + } + } +} + +/// Interface to a bxCAN peripheral. +pub struct Can { + instance: I, +} + +impl Can +where + I: Instance, +{ + /// Creates a [`CanBuilder`] for constructing a CAN interface. + pub fn builder(instance: I) -> CanBuilder { + let can_builder = CanBuilder { + can: Can { instance }, + }; + + let can_reg = can_builder.can.registers(); + // Enter init mode. + can_reg + .mcr + .modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); + loop { + let msr = can_reg.msr.read(); + if msr.slak().bit_is_clear() && msr.inak().bit_is_set() { + break; + } + } + + can_builder + } + + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } + + fn set_bit_timing(&mut self, btr: u32) { + // Mask of all non-reserved BTR bits, except the mode flags. + const MASK: u32 = 0x037F_03FF; + + let can = self.registers(); + can.btr.modify(|r, w| unsafe { + let mode_bits = r.bits() & 0xC000_0000; + w.bits(mode_bits | (btr & MASK)) + }); + } + + /// Returns a reference to the peripheral instance. + /// + /// This allows accessing HAL-specific data stored in the instance type. + pub fn instance(&mut self) -> &mut I { + &mut self.instance + } + + /// Disables the CAN interface and returns back the raw peripheral it was created from. + /// + /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to + /// enter sleep mode. + pub fn free(self) -> I { + self.registers().mcr.write(|w| w.reset().set_bit()); + self.instance + } + + /// Configure bit timings and silent/loop-back mode. + /// + /// Calling this method will enter initialization mode. + pub fn modify_config(&mut self) -> CanConfig<'_, I> { + let can = self.registers(); + + // Enter init mode. + can.mcr + .modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); + loop { + let msr = can.msr.read(); + if msr.slak().bit_is_clear() && msr.inak().bit_is_set() { + break; + } + } + + CanConfig { can: self } + } + + /// Configures the automatic wake-up feature. + /// + /// This is turned off by default. + /// + /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and + /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming + /// frame. + pub fn set_automatic_wakeup(&mut self, enabled: bool) { + let can = self.registers(); + can.mcr.modify(|_, w| w.awum().bit(enabled)); + } + + /// Leaves initialization mode and enables the peripheral (non-blocking version). + /// + /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed + /// if you want non-blocking initialization. + /// + /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself + /// in the background. The peripheral is enabled and ready to use when this method returns + /// successfully. + pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { + let can = self.registers(); + let msr = can.msr.read(); + if msr.slak().bit_is_set() { + can.mcr + .modify(|_, w| w.abom().set_bit().sleep().clear_bit()); + Err(nb::Error::WouldBlock) + } else { + Ok(()) + } + } + + /// Puts the peripheral in a sleep mode to save power. + /// + /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. + pub fn sleep(&mut self) { + let can = self.registers(); + can.mcr + .modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + loop { + let msr = can.msr.read(); + if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { + break; + } + } + } + + /// Wakes up from sleep mode. + /// + /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN + /// frame will cause that interrupt. + pub fn wakeup(&mut self) { + let can = self.registers(); + can.mcr + .modify(|_, w| w.sleep().clear_bit().inrq().clear_bit()); + loop { + let msr = can.msr.read(); + if msr.slak().bit_is_clear() && msr.inak().bit_is_clear() { + break; + } + } + } + + /// Starts listening for a CAN interrupt. + pub fn enable_interrupt(&mut self, interrupt: Interrupt) { + self.enable_interrupts(Interrupts::from_bits_truncate(interrupt as u32)) + } + + /// Starts listening for a set of CAN interrupts. + pub fn enable_interrupts(&mut self, interrupts: Interrupts) { + self.registers() + .ier + .modify(|r, w| unsafe { w.bits(r.bits() | interrupts.bits()) }) + } + + /// Stops listening for a CAN interrupt. + pub fn disable_interrupt(&mut self, interrupt: Interrupt) { + self.disable_interrupts(Interrupts::from_bits_truncate(interrupt as u32)) + } + + /// Stops listening for a set of CAN interrupts. + pub fn disable_interrupts(&mut self, interrupts: Interrupts) { + self.registers() + .ier + .modify(|r, w| unsafe { w.bits(r.bits() & !interrupts.bits()) }) + } + + /// Clears the pending flag of [`Interrupt::Sleep`]. + pub fn clear_sleep_interrupt(&self) { + let can = self.registers(); + // Read-only register with write-1-to-clear, so `&self` is sufficient. + can.msr.write(|w| w.slaki().set_bit()); + } + + /// Clears the pending flag of [`Interrupt::Wakeup`]. + pub fn clear_wakeup_interrupt(&self) { + let can = self.registers(); + // Read-only register with write-1-to-clear, so `&self` is sufficient. + can.msr.write(|w| w.wkui().set_bit()); + } + + /// Clears the "Request Completed" (RQCP) flag of a transmit mailbox. + /// + /// Returns the [`Mailbox`] whose flag was cleared. If no mailbox has the flag set, returns + /// `None`. + /// + /// Once this function returns `None`, a pending [`Interrupt::TransmitMailboxEmpty`] is + /// considered acknowledged. + pub fn clear_request_completed_flag(&mut self) -> Option { + let can = self.registers(); + let tsr = can.tsr.read(); + if tsr.rqcp0().bit_is_set() { + can.tsr.modify(|_, w| w.rqcp0().set_bit()); + Some(Mailbox::Mailbox0) + } else if tsr.rqcp1().bit_is_set() { + can.tsr.modify(|_, w| w.rqcp1().set_bit()); + Some(Mailbox::Mailbox1) + } else if tsr.rqcp2().bit_is_set() { + can.tsr.modify(|_, w| w.rqcp2().set_bit()); + Some(Mailbox::Mailbox2) + } else { + None + } + } + + /// Clears a pending TX interrupt ([`Interrupt::TransmitMailboxEmpty`]). + /// + /// This does not return the mailboxes that have finished tranmission. If you need that + /// information, call [`Can::clear_request_completed_flag`] instead. + pub fn clear_tx_interrupt(&mut self) { + while self.clear_request_completed_flag().is_some() {} + } + + /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. + /// + /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). + /// Transmit order is preserved for frames with identical priority. + /// + /// If all transmit mailboxes are full, and `frame` has a higher priority than the + /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is + /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as + /// [`TransmitStatus::dequeued_frame`]. + pub fn transmit(&mut self, frame: &Frame) -> nb::Result { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure().transmit(frame) } + } + + /// Returns `true` if no frame is pending for transmission. + pub fn is_transmitter_idle(&self) -> bool { + // Safety: Read-only operation. + unsafe { Tx::::conjure().is_idle() } + } + + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// If there is a frame in the provided mailbox, and it is canceled successfully, this function + /// returns `true`. + pub fn abort(&mut self, mailbox: Mailbox) -> bool { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure().abort(mailbox) } + } + + /// Returns a received frame if available. + /// + /// This will first check FIFO 0 for a message or error. If none are available, FIFO 1 is + /// checked. + /// + /// Returns `Err` when a frame was lost due to buffer overrun. + pub fn receive(&mut self) -> nb::Result { + // Safety: We have a `&mut self` and have unique access to the peripheral. + let mut rx0 = unsafe { Rx0::::conjure() }; + let mut rx1 = unsafe { Rx1::::conjure() }; + + match rx0.receive() { + Err(nb::Error::WouldBlock) => rx1.receive(), + result => result, + } + } + + /// Returns a reference to the RX FIFO 0. + pub fn rx0(&mut self) -> &mut Rx0 { + // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. + unsafe { Rx0::conjure_by_ref() } + } + + /// Returns a reference to the RX FIFO 1. + pub fn rx1(&mut self) -> &mut Rx1 { + // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. + unsafe { Rx1::conjure_by_ref() } + } + + /// Splits this `Can` instance into transmitting and receiving halves, by reference. + pub fn split_by_ref(&mut self) -> (&mut Tx, &mut Rx0, &mut Rx1) { + // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. + let tx = unsafe { Tx::conjure_by_ref() }; + let rx0 = unsafe { Rx0::conjure_by_ref() }; + let rx1 = unsafe { Rx1::conjure_by_ref() }; + (tx, rx0, rx1) + } + + /// Consumes this `Can` instance and splits it into transmitting and receiving halves. + pub fn split(self) -> (Tx, Rx0, Rx1) { + // Safety: `Self` is not `Copy` and is destroyed by moving it into this method. + unsafe { (Tx::conjure(), Rx0::conjure(), Rx1::conjure()) } + } +} + +impl Can { + /// Accesses the filter banks owned by this CAN peripheral. + /// + /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master + /// peripheral instead. + pub fn modify_filters(&mut self) -> MasterFilters<'_, I> { + unsafe { MasterFilters::new() } + } +} + +/// Interface to the CAN transmitter part. +pub struct Tx { + _can: PhantomData, +} + +#[inline] +const fn ok_mask(idx: usize) -> u32 { + 0x02 << (8 * idx) +} + +#[inline] +const fn abort_mask(idx: usize) -> u32 { + 0x80 << (8 * idx) +} + +impl Tx +where + I: Instance, +{ + unsafe fn conjure() -> Self { + Self { _can: PhantomData } + } + + /// Creates a `&mut Self` out of thin air. + /// + /// This is only safe if it is the only way to access a `Tx`. + unsafe fn conjure_by_ref<'a>() -> &'a mut Self { + // Cause out of bounds access when `Self` is not zero-sized. + [()][core::mem::size_of::()]; + + // Any aligned pointer is valid for ZSTs. + &mut *NonNull::dangling().as_ptr() + } + + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } + + /// Puts a CAN frame in a transmit mailbox for transmission on the bus. + /// + /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). + /// Transmit order is preserved for frames with identical priority. + /// + /// If all transmit mailboxes are full, and `frame` has a higher priority than the + /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is + /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as + /// [`TransmitStatus::dequeued_frame`]. + pub fn transmit(&mut self, frame: &Frame) -> nb::Result { + let can = self.registers(); + + // Get the index of the next free mailbox or the one with the lowest priority. + let tsr = can.tsr.read(); + let idx = tsr.code().bits() as usize; + + let frame_is_pending = + tsr.tme0().bit_is_clear() || tsr.tme1().bit_is_clear() || tsr.tme2().bit_is_clear(); + let pending_frame = if frame_is_pending { + // High priority frames are transmitted first by the mailbox system. + // Frames with identical identifier shall be transmitted in FIFO order. + // The controller schedules pending frames of same priority based on the + // mailbox index instead. As a workaround check all pending mailboxes + // and only accept higher priority frames. + self.check_priority(0, frame.id)?; + self.check_priority(1, frame.id)?; + self.check_priority(2, frame.id)?; + + let all_frames_are_pending = + tsr.tme0().bit_is_clear() && tsr.tme1().bit_is_clear() && tsr.tme2().bit_is_clear(); + if all_frames_are_pending { + // No free mailbox is available. This can only happen when three frames with + // ascending priority (descending IDs) were requested for transmission and all + // of them are blocked by bus traffic with even higher priority. + // To prevent a priority inversion abort and replace the lowest priority frame. + self.read_pending_mailbox(idx) + } else { + // There was a free mailbox. + None + } + } else { + // All mailboxes are available: Send frame without performing any checks. + None + }; + + self.write_mailbox(idx, frame); + + let mailbox = match idx { + 0 => Mailbox::Mailbox0, + 1 => Mailbox::Mailbox1, + 2 => Mailbox::Mailbox2, + _ => unreachable!(), + }; + Ok(TransmitStatus { + dequeued_frame: pending_frame, + mailbox, + }) + } + + /// Returns `Ok` when the mailbox is free or if it contains pending frame with a + /// lower priority (higher ID) than the identifier `id`. + fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { + let can = self.registers(); + + // Read the pending frame's id to check its priority. + assert!(idx < 3); + let tir = &can.tx[idx].tir.read(); + + // Check the priority by comparing the identifiers. But first make sure the + // frame has not finished the transmission (`TXRQ` == 0) in the meantime. + if tir.txrq().bit_is_set() && id <= IdReg::from_register(tir.bits()) { + // There's a mailbox whose priority is higher or equal + // the priority of the new frame. + return Err(nb::Error::WouldBlock); + } + + Ok(()) + } + + fn write_mailbox(&mut self, idx: usize, frame: &Frame) { + let can = self.registers(); + + debug_assert!(idx < 3); + let mb = unsafe { &can.tx.get_unchecked(idx) }; + + mb.tdtr + .write(|w| unsafe { w.dlc().bits(frame.dlc() as u8) }); + mb.tdlr.write(|w| unsafe { + w.bits(u32::from_ne_bytes( + frame.data.bytes[0..4].try_into().unwrap(), + )) + }); + mb.tdhr.write(|w| unsafe { + w.bits(u32::from_ne_bytes( + frame.data.bytes[4..8].try_into().unwrap(), + )) + }); + mb.tir + .write(|w| unsafe { w.bits(frame.id.0).txrq().set_bit() }); + } + + fn read_pending_mailbox(&mut self, idx: usize) -> Option { + if self.abort_by_index(idx) { + let can = self.registers(); + debug_assert!(idx < 3); + let mb = unsafe { &can.tx.get_unchecked(idx) }; + + // Read back the pending frame. + let mut pending_frame = Frame { + id: IdReg(mb.tir.read().bits()), + data: Data::empty(), + }; + pending_frame.data.bytes[0..4].copy_from_slice(&mb.tdlr.read().bits().to_ne_bytes()); + pending_frame.data.bytes[4..8].copy_from_slice(&mb.tdhr.read().bits().to_ne_bytes()); + pending_frame.data.len = mb.tdtr.read().dlc().bits(); + + Some(pending_frame) + } else { + // Abort request failed because the frame was already sent (or being sent) on + // the bus. All mailboxes are now free. This can happen for small prescaler + // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR + // has preempted the execution. + None + } + } + + /// Tries to abort a pending frame. Returns `true` when aborted. + fn abort_by_index(&mut self, idx: usize) -> bool { + let can = self.registers(); + + can.tsr.write(|w| unsafe { w.bits(abort_mask(idx)) }); + + // Wait for the abort request to be finished. + loop { + let tsr = can.tsr.read().bits(); + if tsr & abort_mask(idx) == 0 { + break tsr & ok_mask(idx) == 0; + } + } + } + + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// If there is a frame in the provided mailbox, and it is canceled successfully, this function + /// returns `true`. + pub fn abort(&mut self, mailbox: Mailbox) -> bool { + // If the mailbox is empty, the value of TXOKx depends on what happened with the previous + // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. + let tsr = self.registers().tsr.read(); + let mailbox_empty = match mailbox { + Mailbox::Mailbox0 => tsr.tme0().bit_is_set(), + Mailbox::Mailbox1 => tsr.tme1().bit_is_set(), + Mailbox::Mailbox2 => tsr.tme2().bit_is_set(), + }; + if mailbox_empty { + false + } else { + self.abort_by_index(mailbox as usize) + } + } + + /// Returns `true` if no frame is pending for transmission. + pub fn is_idle(&self) -> bool { + let can = self.registers(); + let tsr = can.tsr.read(); + tsr.tme0().bit_is_set() && tsr.tme1().bit_is_set() && tsr.tme2().bit_is_set() + } + + /// Clears the request complete flag for all mailboxes. + pub fn clear_interrupt_flags(&mut self) { + let can = self.registers(); + can.tsr + .write(|w| w.rqcp2().set_bit().rqcp1().set_bit().rqcp0().set_bit()); + } +} + +/// Interface to receiver FIFO 0. +pub struct Rx0 { + _can: PhantomData, +} + +impl Rx0 +where + I: Instance, +{ + unsafe fn conjure() -> Self { + Self { _can: PhantomData } + } + + /// Creates a `&mut Self` out of thin air. + /// + /// This is only safe if it is the only way to access an `Rx`. + unsafe fn conjure_by_ref<'a>() -> &'a mut Self { + // Cause out of bounds access when `Self` is not zero-sized. + [()][core::mem::size_of::()]; + + // Any aligned pointer is valid for ZSTs. + &mut *NonNull::dangling().as_ptr() + } + + /// Returns a received frame if available. + /// + /// Returns `Err` when a frame was lost due to buffer overrun. + pub fn receive(&mut self) -> nb::Result { + receive_fifo(self.registers(), 0) + } + + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } +} + +/// Interface to receiver FIFO 1. +pub struct Rx1 { + _can: PhantomData, +} + +impl Rx1 +where + I: Instance, +{ + unsafe fn conjure() -> Self { + Self { _can: PhantomData } + } + + /// Creates a `&mut Self` out of thin air. + /// + /// This is only safe if it is the only way to access an `Rx`. + unsafe fn conjure_by_ref<'a>() -> &'a mut Self { + // Cause out of bounds access when `Self` is not zero-sized. + [()][core::mem::size_of::()]; + + // Any aligned pointer is valid for ZSTs. + &mut *NonNull::dangling().as_ptr() + } + + /// Returns a received frame if available. + /// + /// Returns `Err` when a frame was lost due to buffer overrun. + pub fn receive(&mut self) -> nb::Result { + receive_fifo(self.registers(), 1) + } + + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } +} + +fn receive_fifo(can: &RegisterBlock, fifo_nr: usize) -> nb::Result { + assert!(fifo_nr < 2); + let rfr = &can.rfr[fifo_nr]; + let rx = &can.rx[fifo_nr]; + + // Check if a frame is available in the mailbox. + let rfr_read = rfr.read(); + if rfr_read.fmp().bits() == 0 { + return Err(nb::Error::WouldBlock); + } + + // Check for RX FIFO overrun. + if rfr_read.fovr().bit_is_set() { + rfr.write(|w| w.fovr().set_bit()); + return Err(nb::Error::Other(OverrunError { _priv: () })); + } + + // Read the frame. + let mut frame = Frame { + id: IdReg(rx.rir.read().bits()), + data: [0; 8].into(), + }; + frame.data[0..4].copy_from_slice(&rx.rdlr.read().bits().to_ne_bytes()); + frame.data[4..8].copy_from_slice(&rx.rdhr.read().bits().to_ne_bytes()); + frame.data.len = rx.rdtr.read().dlc().bits(); + + // Release the mailbox. + rfr.write(|w| w.rfom().set_bit()); + + Ok(frame) +} + +/// Identifies one of the two receive FIFOs. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum Fifo { + Fifo0 = 0, + Fifo1 = 1, +} + +/// Identifies one of the three transmit mailboxes. +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum Mailbox { + /// Transmit mailbox 0 + Mailbox0 = 0, + /// Transmit mailbox 1 + Mailbox1 = 1, + /// Transmit mailbox 2 + Mailbox2 = 2, +} + +/// Contains information about a frame enqueued for transmission via [`Can::transmit`] or +/// [`Tx::transmit`]. +pub struct TransmitStatus { + dequeued_frame: Option, + mailbox: Mailbox, +} + +impl TransmitStatus { + /// Returns the lower-priority frame that was dequeued to make space for the new frame. + #[inline] + pub fn dequeued_frame(&self) -> Option<&Frame> { + self.dequeued_frame.as_ref() + } + + /// Returns the [`Mailbox`] the frame was enqueued in. + #[inline] + pub fn mailbox(&self) -> Mailbox { + self.mailbox + } +} diff --git a/embassy-stm32/src/can/bx/pac/can.rs b/embassy-stm32/src/can/bx/pac/can.rs new file mode 100644 index 000000000..f190fdff4 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can.rs @@ -0,0 +1,213 @@ +/// Register block of bxCAN peripherals. +#[repr(C)] +pub struct RegisterBlock { + #[doc = "0x00 - CAN_MCR"] + pub(crate) mcr: MCR, + #[doc = "0x04 - CAN_MSR"] + pub(crate) msr: MSR, + #[doc = "0x08 - CAN_TSR"] + pub(crate) tsr: TSR, + #[doc = "0x0c - CAN_RF0R"] + pub(crate) rfr: [RFR; 2], + #[doc = "0x14 - CAN_IER"] + pub(crate) ier: IER, + #[doc = "0x18 - CAN_ESR"] + pub(crate) esr: ESR, + #[doc = "0x1c - CAN_BTR"] + pub(crate) btr: BTR, + _reserved7: [u8; 352usize], + #[doc = "0x180 - CAN Transmit cluster"] + pub(crate) tx: [TX; 3], + #[doc = "0x1b0 - CAN Receive cluster"] + pub(crate) rx: [RX; 2], + _reserved9: [u8; 48usize], + #[doc = "0x200 - CAN_FMR"] + pub(crate) fmr: FMR, + #[doc = "0x204 - CAN_FM1R"] + pub(crate) fm1r: FM1R, + _reserved11: [u8; 4usize], + #[doc = "0x20c - CAN_FS1R"] + pub(crate) fs1r: FS1R, + _reserved12: [u8; 4usize], + #[doc = "0x214 - CAN_FFA1R"] + pub(crate) ffa1r: FFA1R, + _reserved13: [u8; 4usize], + #[doc = "0x21c - CAN_FA1R"] + pub(crate) fa1r: FA1R, + _reserved14: [u8; 32usize], + #[doc = "0x240 - CAN Filter Bank cluster"] + pub(crate) fb: [FB; 28], // UP TO 28, but 14 in some devices +} +#[doc = r"Register block"] +#[repr(C)] +pub struct TX { + #[doc = "0x00 - CAN_TI0R"] + pub tir: self::tx::TIR, + #[doc = "0x04 - CAN_TDT0R"] + pub tdtr: self::tx::TDTR, + #[doc = "0x08 - CAN_TDL0R"] + pub tdlr: self::tx::TDLR, + #[doc = "0x0c - CAN_TDH0R"] + pub tdhr: self::tx::TDHR, +} +#[doc = r"Register block"] +#[doc = "CAN Transmit cluster"] +pub mod tx; +#[doc = r"Register block"] +#[repr(C)] +pub struct RX { + #[doc = "0x00 - CAN_RI0R"] + pub rir: self::rx::RIR, + #[doc = "0x04 - CAN_RDT0R"] + pub rdtr: self::rx::RDTR, + #[doc = "0x08 - CAN_RDL0R"] + pub rdlr: self::rx::RDLR, + #[doc = "0x0c - CAN_RDH0R"] + pub rdhr: self::rx::RDHR, +} +#[doc = r"Register block"] +#[doc = "CAN Receive cluster"] +pub mod rx; +#[doc = r"Register block"] +#[repr(C)] +pub struct FB { + #[doc = "0x00 - Filter bank 0 register 1"] + pub fr1: self::fb::FR1, + #[doc = "0x04 - Filter bank 0 register 2"] + pub fr2: self::fb::FR2, +} +#[doc = r"Register block"] +#[doc = "CAN Filter Bank cluster"] +pub mod fb; +#[doc = "CAN_MCR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [mcr](mcr) module"] +pub type MCR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _MCR; +#[doc = "`read()` method returns [mcr::R](mcr::R) reader structure"] +impl crate::Readable for MCR {} +#[doc = "`write(|w| ..)` method takes [mcr::W](mcr::W) writer structure"] +impl crate::Writable for MCR {} +#[doc = "CAN_MCR"] +pub mod mcr; +#[doc = "CAN_MSR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [msr](msr) module"] +pub type MSR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _MSR; +#[doc = "`read()` method returns [msr::R](msr::R) reader structure"] +impl crate::Readable for MSR {} +#[doc = "`write(|w| ..)` method takes [msr::W](msr::W) writer structure"] +impl crate::Writable for MSR {} +#[doc = "CAN_MSR"] +pub mod msr; +#[doc = "CAN_TSR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tsr](tsr) module"] +pub type TSR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _TSR; +#[doc = "`read()` method returns [tsr::R](tsr::R) reader structure"] +impl crate::Readable for TSR {} +#[doc = "`write(|w| ..)` method takes [tsr::W](tsr::W) writer structure"] +impl crate::Writable for TSR {} +#[doc = "CAN_TSR"] +pub mod tsr; +#[doc = "CAN_RF0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rfr](rfr) module"] +pub type RFR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _RFR; +#[doc = "`read()` method returns [rfr::R](rfr::R) reader structure"] +impl crate::Readable for RFR {} +#[doc = "`write(|w| ..)` method takes [rfr::W](rfr::W) writer structure"] +impl crate::Writable for RFR {} +#[doc = "CAN_RF0R"] +pub mod rfr; +#[doc = "CAN_IER\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [ier](ier) module"] +pub type IER = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _IER; +#[doc = "`read()` method returns [ier::R](ier::R) reader structure"] +impl crate::Readable for IER {} +#[doc = "`write(|w| ..)` method takes [ier::W](ier::W) writer structure"] +impl crate::Writable for IER {} +#[doc = "CAN_IER"] +pub mod ier; +#[doc = "CAN_ESR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [esr](esr) module"] +pub type ESR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _ESR; +#[doc = "`read()` method returns [esr::R](esr::R) reader structure"] +impl crate::Readable for ESR {} +#[doc = "`write(|w| ..)` method takes [esr::W](esr::W) writer structure"] +impl crate::Writable for ESR {} +#[doc = "CAN_ESR"] +pub mod esr; +#[doc = "CAN_BTR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [btr](btr) module"] +pub type BTR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _BTR; +#[doc = "`read()` method returns [btr::R](btr::R) reader structure"] +impl crate::Readable for BTR {} +#[doc = "`write(|w| ..)` method takes [btr::W](btr::W) writer structure"] +impl crate::Writable for BTR {} +#[doc = "CAN_BTR"] +pub mod btr; +#[doc = "CAN_FMR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fmr](fmr) module"] +pub type FMR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _FMR; +#[doc = "`read()` method returns [fmr::R](fmr::R) reader structure"] +impl crate::Readable for FMR {} +#[doc = "`write(|w| ..)` method takes [fmr::W](fmr::W) writer structure"] +impl crate::Writable for FMR {} +#[doc = "CAN_FMR"] +pub mod fmr; +#[doc = "CAN_FM1R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fm1r](fm1r) module"] +pub type FM1R = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _FM1R; +#[doc = "`read()` method returns [fm1r::R](fm1r::R) reader structure"] +impl crate::Readable for FM1R {} +#[doc = "`write(|w| ..)` method takes [fm1r::W](fm1r::W) writer structure"] +impl crate::Writable for FM1R {} +#[doc = "CAN_FM1R"] +pub mod fm1r; +#[doc = "CAN_FS1R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fs1r](fs1r) module"] +pub type FS1R = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _FS1R; +#[doc = "`read()` method returns [fs1r::R](fs1r::R) reader structure"] +impl crate::Readable for FS1R {} +#[doc = "`write(|w| ..)` method takes [fs1r::W](fs1r::W) writer structure"] +impl crate::Writable for FS1R {} +#[doc = "CAN_FS1R"] +pub mod fs1r; +#[doc = "CAN_FFA1R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [ffa1r](ffa1r) module"] +pub type FFA1R = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _FFA1R; +#[doc = "`read()` method returns [ffa1r::R](ffa1r::R) reader structure"] +impl crate::Readable for FFA1R {} +#[doc = "`write(|w| ..)` method takes [ffa1r::W](ffa1r::W) writer structure"] +impl crate::Writable for FFA1R {} +#[doc = "CAN_FFA1R"] +pub mod ffa1r; +#[doc = "CAN_FA1R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fa1r](fa1r) module"] +pub type FA1R = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _FA1R; +#[doc = "`read()` method returns [fa1r::R](fa1r::R) reader structure"] +impl crate::Readable for FA1R {} +#[doc = "`write(|w| ..)` method takes [fa1r::W](fa1r::W) writer structure"] +impl crate::Writable for FA1R {} +#[doc = "CAN_FA1R"] +pub mod fa1r; diff --git a/embassy-stm32/src/can/bx/pac/can/btr.rs b/embassy-stm32/src/can/bx/pac/can/btr.rs new file mode 100644 index 000000000..0a801c50e --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/btr.rs @@ -0,0 +1,282 @@ +#[doc = "Reader of register BTR"] +pub type R = crate::R; +#[doc = "Writer for register BTR"] +pub type W = crate::W; +#[doc = "Register BTR `reset()`'s with value 0"] +impl crate::ResetValue for super::BTR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "SILM\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum SILM_A { + #[doc = "0: Normal operation"] + NORMAL = 0, + #[doc = "1: Silent Mode"] + SILENT = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: SILM_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `SILM`"] +pub type SILM_R = crate::R; +impl SILM_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> SILM_A { + match self.bits { + false => SILM_A::NORMAL, + true => SILM_A::SILENT, + } + } + #[doc = "Checks if the value of the field is `NORMAL`"] + #[inline(always)] + pub fn is_normal(&self) -> bool { + *self == SILM_A::NORMAL + } + #[doc = "Checks if the value of the field is `SILENT`"] + #[inline(always)] + pub fn is_silent(&self) -> bool { + *self == SILM_A::SILENT + } +} +#[doc = "Write proxy for field `SILM`"] +pub struct SILM_W<'a> { + w: &'a mut W, +} +impl<'a> SILM_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: SILM_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "Normal operation"] + #[inline(always)] + pub fn normal(self) -> &'a mut W { + self.variant(SILM_A::NORMAL) + } + #[doc = "Silent Mode"] + #[inline(always)] + pub fn silent(self) -> &'a mut W { + self.variant(SILM_A::SILENT) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 31)) | (((value as u32) & 0x01) << 31); + self.w + } +} +#[doc = "LBKM\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum LBKM_A { + #[doc = "0: Loop Back Mode disabled"] + DISABLED = 0, + #[doc = "1: Loop Back Mode enabled"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: LBKM_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `LBKM`"] +pub type LBKM_R = crate::R; +impl LBKM_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> LBKM_A { + match self.bits { + false => LBKM_A::DISABLED, + true => LBKM_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == LBKM_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == LBKM_A::ENABLED + } +} +#[doc = "Write proxy for field `LBKM`"] +pub struct LBKM_W<'a> { + w: &'a mut W, +} +impl<'a> LBKM_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: LBKM_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "Loop Back Mode disabled"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(LBKM_A::DISABLED) + } + #[doc = "Loop Back Mode enabled"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(LBKM_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 30)) | (((value as u32) & 0x01) << 30); + self.w + } +} +#[doc = "Reader of field `SJW`"] +pub type SJW_R = crate::R; +#[doc = "Write proxy for field `SJW`"] +pub struct SJW_W<'a> { + w: &'a mut W, +} +impl<'a> SJW_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x03 << 24)) | (((value as u32) & 0x03) << 24); + self.w + } +} +#[doc = "Reader of field `TS2`"] +pub type TS2_R = crate::R; +#[doc = "Write proxy for field `TS2`"] +pub struct TS2_W<'a> { + w: &'a mut W, +} +impl<'a> TS2_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x07 << 20)) | (((value as u32) & 0x07) << 20); + self.w + } +} +#[doc = "Reader of field `TS1`"] +pub type TS1_R = crate::R; +#[doc = "Write proxy for field `TS1`"] +pub struct TS1_W<'a> { + w: &'a mut W, +} +impl<'a> TS1_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x0f << 16)) | (((value as u32) & 0x0f) << 16); + self.w + } +} +#[doc = "Reader of field `BRP`"] +pub type BRP_R = crate::R; +#[doc = "Write proxy for field `BRP`"] +pub struct BRP_W<'a> { + w: &'a mut W, +} +impl<'a> BRP_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u16) -> &'a mut W { + self.w.bits = (self.w.bits & !0x03ff) | ((value as u32) & 0x03ff); + self.w + } +} +impl R { + #[doc = "Bit 31 - SILM"] + #[inline(always)] + pub fn silm(&self) -> SILM_R { + SILM_R::new(((self.bits >> 31) & 0x01) != 0) + } + #[doc = "Bit 30 - LBKM"] + #[inline(always)] + pub fn lbkm(&self) -> LBKM_R { + LBKM_R::new(((self.bits >> 30) & 0x01) != 0) + } + #[doc = "Bits 24:25 - SJW"] + #[inline(always)] + pub fn sjw(&self) -> SJW_R { + SJW_R::new(((self.bits >> 24) & 0x03) as u8) + } + #[doc = "Bits 20:22 - TS2"] + #[inline(always)] + pub fn ts2(&self) -> TS2_R { + TS2_R::new(((self.bits >> 20) & 0x07) as u8) + } + #[doc = "Bits 16:19 - TS1"] + #[inline(always)] + pub fn ts1(&self) -> TS1_R { + TS1_R::new(((self.bits >> 16) & 0x0f) as u8) + } + #[doc = "Bits 0:9 - BRP"] + #[inline(always)] + pub fn brp(&self) -> BRP_R { + BRP_R::new((self.bits & 0x03ff) as u16) + } +} +impl W { + #[doc = "Bit 31 - SILM"] + #[inline(always)] + pub fn silm(&mut self) -> SILM_W { + SILM_W { w: self } + } + #[doc = "Bit 30 - LBKM"] + #[inline(always)] + pub fn lbkm(&mut self) -> LBKM_W { + LBKM_W { w: self } + } + #[doc = "Bits 24:25 - SJW"] + #[inline(always)] + pub fn sjw(&mut self) -> SJW_W { + SJW_W { w: self } + } + #[doc = "Bits 20:22 - TS2"] + #[inline(always)] + pub fn ts2(&mut self) -> TS2_W { + TS2_W { w: self } + } + #[doc = "Bits 16:19 - TS1"] + #[inline(always)] + pub fn ts1(&mut self) -> TS1_W { + TS1_W { w: self } + } + #[doc = "Bits 0:9 - BRP"] + #[inline(always)] + pub fn brp(&mut self) -> BRP_W { + BRP_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/esr.rs b/embassy-stm32/src/can/bx/pac/can/esr.rs new file mode 100644 index 000000000..9ea7c5a24 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/esr.rs @@ -0,0 +1,206 @@ +#[doc = "Reader of register ESR"] +pub type R = crate::R; +#[doc = "Writer for register ESR"] +pub type W = crate::W; +#[doc = "Register ESR `reset()`'s with value 0"] +impl crate::ResetValue for super::ESR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `REC`"] +pub type REC_R = crate::R; +#[doc = "Reader of field `TEC`"] +pub type TEC_R = crate::R; +#[doc = "LEC\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(u8)] +pub enum LEC_A { + #[doc = "0: No Error"] + NOERROR = 0, + #[doc = "1: Stuff Error"] + STUFF = 1, + #[doc = "2: Form Error"] + FORM = 2, + #[doc = "3: Acknowledgment Error"] + ACK = 3, + #[doc = "4: Bit recessive Error"] + BITRECESSIVE = 4, + #[doc = "5: Bit dominant Error"] + BITDOMINANT = 5, + #[doc = "6: CRC Error"] + CRC = 6, + #[doc = "7: Set by software"] + CUSTOM = 7, +} +impl From for u8 { + #[inline(always)] + fn from(variant: LEC_A) -> Self { + variant as _ + } +} +#[doc = "Reader of field `LEC`"] +pub type LEC_R = crate::R; +impl LEC_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> LEC_A { + match self.bits { + 0 => LEC_A::NOERROR, + 1 => LEC_A::STUFF, + 2 => LEC_A::FORM, + 3 => LEC_A::ACK, + 4 => LEC_A::BITRECESSIVE, + 5 => LEC_A::BITDOMINANT, + 6 => LEC_A::CRC, + 7 => LEC_A::CUSTOM, + _ => unreachable!(), + } + } + #[doc = "Checks if the value of the field is `NOERROR`"] + #[inline(always)] + pub fn is_no_error(&self) -> bool { + *self == LEC_A::NOERROR + } + #[doc = "Checks if the value of the field is `STUFF`"] + #[inline(always)] + pub fn is_stuff(&self) -> bool { + *self == LEC_A::STUFF + } + #[doc = "Checks if the value of the field is `FORM`"] + #[inline(always)] + pub fn is_form(&self) -> bool { + *self == LEC_A::FORM + } + #[doc = "Checks if the value of the field is `ACK`"] + #[inline(always)] + pub fn is_ack(&self) -> bool { + *self == LEC_A::ACK + } + #[doc = "Checks if the value of the field is `BITRECESSIVE`"] + #[inline(always)] + pub fn is_bit_recessive(&self) -> bool { + *self == LEC_A::BITRECESSIVE + } + #[doc = "Checks if the value of the field is `BITDOMINANT`"] + #[inline(always)] + pub fn is_bit_dominant(&self) -> bool { + *self == LEC_A::BITDOMINANT + } + #[doc = "Checks if the value of the field is `CRC`"] + #[inline(always)] + pub fn is_crc(&self) -> bool { + *self == LEC_A::CRC + } + #[doc = "Checks if the value of the field is `CUSTOM`"] + #[inline(always)] + pub fn is_custom(&self) -> bool { + *self == LEC_A::CUSTOM + } +} +#[doc = "Write proxy for field `LEC`"] +pub struct LEC_W<'a> { + w: &'a mut W, +} +impl<'a> LEC_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: LEC_A) -> &'a mut W { + { + self.bits(variant.into()) + } + } + #[doc = "No Error"] + #[inline(always)] + pub fn no_error(self) -> &'a mut W { + self.variant(LEC_A::NOERROR) + } + #[doc = "Stuff Error"] + #[inline(always)] + pub fn stuff(self) -> &'a mut W { + self.variant(LEC_A::STUFF) + } + #[doc = "Form Error"] + #[inline(always)] + pub fn form(self) -> &'a mut W { + self.variant(LEC_A::FORM) + } + #[doc = "Acknowledgment Error"] + #[inline(always)] + pub fn ack(self) -> &'a mut W { + self.variant(LEC_A::ACK) + } + #[doc = "Bit recessive Error"] + #[inline(always)] + pub fn bit_recessive(self) -> &'a mut W { + self.variant(LEC_A::BITRECESSIVE) + } + #[doc = "Bit dominant Error"] + #[inline(always)] + pub fn bit_dominant(self) -> &'a mut W { + self.variant(LEC_A::BITDOMINANT) + } + #[doc = "CRC Error"] + #[inline(always)] + pub fn crc(self) -> &'a mut W { + self.variant(LEC_A::CRC) + } + #[doc = "Set by software"] + #[inline(always)] + pub fn custom(self) -> &'a mut W { + self.variant(LEC_A::CUSTOM) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x07 << 4)) | (((value as u32) & 0x07) << 4); + self.w + } +} +#[doc = "Reader of field `BOFF`"] +pub type BOFF_R = crate::R; +#[doc = "Reader of field `EPVF`"] +pub type EPVF_R = crate::R; +#[doc = "Reader of field `EWGF`"] +pub type EWGF_R = crate::R; +impl R { + #[doc = "Bits 24:31 - REC"] + #[inline(always)] + pub fn rec(&self) -> REC_R { + REC_R::new(((self.bits >> 24) & 0xff) as u8) + } + #[doc = "Bits 16:23 - TEC"] + #[inline(always)] + pub fn tec(&self) -> TEC_R { + TEC_R::new(((self.bits >> 16) & 0xff) as u8) + } + #[doc = "Bits 4:6 - LEC"] + #[inline(always)] + pub fn lec(&self) -> LEC_R { + LEC_R::new(((self.bits >> 4) & 0x07) as u8) + } + #[doc = "Bit 2 - BOFF"] + #[inline(always)] + pub fn boff(&self) -> BOFF_R { + BOFF_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 1 - EPVF"] + #[inline(always)] + pub fn epvf(&self) -> EPVF_R { + EPVF_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 0 - EWGF"] + #[inline(always)] + pub fn ewgf(&self) -> EWGF_R { + EWGF_R::new((self.bits & 0x01) != 0) + } +} +impl W { + #[doc = "Bits 4:6 - LEC"] + #[inline(always)] + pub fn lec(&mut self) -> LEC_W { + LEC_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/fa1r.rs b/embassy-stm32/src/can/bx/pac/can/fa1r.rs new file mode 100644 index 000000000..797e4e074 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/fa1r.rs @@ -0,0 +1,492 @@ +#[doc = "Reader of register FA1R"] +pub type R = crate::R; +#[doc = "Writer for register FA1R"] +pub type W = crate::W; +#[doc = "Register FA1R `reset()`'s with value 0"] +impl crate::ResetValue for super::FA1R { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `FACT0`"] +pub type FACT0_R = crate::R; +#[doc = "Write proxy for field `FACT0`"] +pub struct FACT0_W<'a> { + w: &'a mut W, +} +impl<'a> FACT0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +#[doc = "Reader of field `FACT1`"] +pub type FACT1_R = crate::R; +#[doc = "Write proxy for field `FACT1`"] +pub struct FACT1_W<'a> { + w: &'a mut W, +} +impl<'a> FACT1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); + self.w + } +} +#[doc = "Reader of field `FACT2`"] +pub type FACT2_R = crate::R; +#[doc = "Write proxy for field `FACT2`"] +pub struct FACT2_W<'a> { + w: &'a mut W, +} +impl<'a> FACT2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "Reader of field `FACT3`"] +pub type FACT3_R = crate::R; +#[doc = "Write proxy for field `FACT3`"] +pub struct FACT3_W<'a> { + w: &'a mut W, +} +impl<'a> FACT3_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "Reader of field `FACT4`"] +pub type FACT4_R = crate::R; +#[doc = "Write proxy for field `FACT4`"] +pub struct FACT4_W<'a> { + w: &'a mut W, +} +impl<'a> FACT4_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); + self.w + } +} +#[doc = "Reader of field `FACT5`"] +pub type FACT5_R = crate::R; +#[doc = "Write proxy for field `FACT5`"] +pub struct FACT5_W<'a> { + w: &'a mut W, +} +impl<'a> FACT5_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); + self.w + } +} +#[doc = "Reader of field `FACT6`"] +pub type FACT6_R = crate::R; +#[doc = "Write proxy for field `FACT6`"] +pub struct FACT6_W<'a> { + w: &'a mut W, +} +impl<'a> FACT6_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); + self.w + } +} +#[doc = "Reader of field `FACT7`"] +pub type FACT7_R = crate::R; +#[doc = "Write proxy for field `FACT7`"] +pub struct FACT7_W<'a> { + w: &'a mut W, +} +impl<'a> FACT7_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); + self.w + } +} +#[doc = "Reader of field `FACT8`"] +pub type FACT8_R = crate::R; +#[doc = "Write proxy for field `FACT8`"] +pub struct FACT8_W<'a> { + w: &'a mut W, +} +impl<'a> FACT8_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); + self.w + } +} +#[doc = "Reader of field `FACT9`"] +pub type FACT9_R = crate::R; +#[doc = "Write proxy for field `FACT9`"] +pub struct FACT9_W<'a> { + w: &'a mut W, +} +impl<'a> FACT9_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); + self.w + } +} +#[doc = "Reader of field `FACT10`"] +pub type FACT10_R = crate::R; +#[doc = "Write proxy for field `FACT10`"] +pub struct FACT10_W<'a> { + w: &'a mut W, +} +impl<'a> FACT10_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); + self.w + } +} +#[doc = "Reader of field `FACT11`"] +pub type FACT11_R = crate::R; +#[doc = "Write proxy for field `FACT11`"] +pub struct FACT11_W<'a> { + w: &'a mut W, +} +impl<'a> FACT11_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); + self.w + } +} +#[doc = "Reader of field `FACT12`"] +pub type FACT12_R = crate::R; +#[doc = "Write proxy for field `FACT12`"] +pub struct FACT12_W<'a> { + w: &'a mut W, +} +impl<'a> FACT12_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 12)) | (((value as u32) & 0x01) << 12); + self.w + } +} +#[doc = "Reader of field `FACT13`"] +pub type FACT13_R = crate::R; +#[doc = "Write proxy for field `FACT13`"] +pub struct FACT13_W<'a> { + w: &'a mut W, +} +impl<'a> FACT13_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 13)) | (((value as u32) & 0x01) << 13); + self.w + } +} +impl R { + #[doc = "Bit 0 - Filter active"] + #[inline(always)] + pub fn fact0(&self) -> FACT0_R { + FACT0_R::new((self.bits & 0x01) != 0) + } + #[doc = "Bit 1 - Filter active"] + #[inline(always)] + pub fn fact1(&self) -> FACT1_R { + FACT1_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 2 - Filter active"] + #[inline(always)] + pub fn fact2(&self) -> FACT2_R { + FACT2_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 3 - Filter active"] + #[inline(always)] + pub fn fact3(&self) -> FACT3_R { + FACT3_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bit 4 - Filter active"] + #[inline(always)] + pub fn fact4(&self) -> FACT4_R { + FACT4_R::new(((self.bits >> 4) & 0x01) != 0) + } + #[doc = "Bit 5 - Filter active"] + #[inline(always)] + pub fn fact5(&self) -> FACT5_R { + FACT5_R::new(((self.bits >> 5) & 0x01) != 0) + } + #[doc = "Bit 6 - Filter active"] + #[inline(always)] + pub fn fact6(&self) -> FACT6_R { + FACT6_R::new(((self.bits >> 6) & 0x01) != 0) + } + #[doc = "Bit 7 - Filter active"] + #[inline(always)] + pub fn fact7(&self) -> FACT7_R { + FACT7_R::new(((self.bits >> 7) & 0x01) != 0) + } + #[doc = "Bit 8 - Filter active"] + #[inline(always)] + pub fn fact8(&self) -> FACT8_R { + FACT8_R::new(((self.bits >> 8) & 0x01) != 0) + } + #[doc = "Bit 9 - Filter active"] + #[inline(always)] + pub fn fact9(&self) -> FACT9_R { + FACT9_R::new(((self.bits >> 9) & 0x01) != 0) + } + #[doc = "Bit 10 - Filter active"] + #[inline(always)] + pub fn fact10(&self) -> FACT10_R { + FACT10_R::new(((self.bits >> 10) & 0x01) != 0) + } + #[doc = "Bit 11 - Filter active"] + #[inline(always)] + pub fn fact11(&self) -> FACT11_R { + FACT11_R::new(((self.bits >> 11) & 0x01) != 0) + } + #[doc = "Bit 12 - Filter active"] + #[inline(always)] + pub fn fact12(&self) -> FACT12_R { + FACT12_R::new(((self.bits >> 12) & 0x01) != 0) + } + #[doc = "Bit 13 - Filter active"] + #[inline(always)] + pub fn fact13(&self) -> FACT13_R { + FACT13_R::new(((self.bits >> 13) & 0x01) != 0) + } +} +impl W { + #[doc = "Bit 0 - Filter active"] + #[inline(always)] + pub fn fact0(&mut self) -> FACT0_W { + FACT0_W { w: self } + } + #[doc = "Bit 1 - Filter active"] + #[inline(always)] + pub fn fact1(&mut self) -> FACT1_W { + FACT1_W { w: self } + } + #[doc = "Bit 2 - Filter active"] + #[inline(always)] + pub fn fact2(&mut self) -> FACT2_W { + FACT2_W { w: self } + } + #[doc = "Bit 3 - Filter active"] + #[inline(always)] + pub fn fact3(&mut self) -> FACT3_W { + FACT3_W { w: self } + } + #[doc = "Bit 4 - Filter active"] + #[inline(always)] + pub fn fact4(&mut self) -> FACT4_W { + FACT4_W { w: self } + } + #[doc = "Bit 5 - Filter active"] + #[inline(always)] + pub fn fact5(&mut self) -> FACT5_W { + FACT5_W { w: self } + } + #[doc = "Bit 6 - Filter active"] + #[inline(always)] + pub fn fact6(&mut self) -> FACT6_W { + FACT6_W { w: self } + } + #[doc = "Bit 7 - Filter active"] + #[inline(always)] + pub fn fact7(&mut self) -> FACT7_W { + FACT7_W { w: self } + } + #[doc = "Bit 8 - Filter active"] + #[inline(always)] + pub fn fact8(&mut self) -> FACT8_W { + FACT8_W { w: self } + } + #[doc = "Bit 9 - Filter active"] + #[inline(always)] + pub fn fact9(&mut self) -> FACT9_W { + FACT9_W { w: self } + } + #[doc = "Bit 10 - Filter active"] + #[inline(always)] + pub fn fact10(&mut self) -> FACT10_W { + FACT10_W { w: self } + } + #[doc = "Bit 11 - Filter active"] + #[inline(always)] + pub fn fact11(&mut self) -> FACT11_W { + FACT11_W { w: self } + } + #[doc = "Bit 12 - Filter active"] + #[inline(always)] + pub fn fact12(&mut self) -> FACT12_W { + FACT12_W { w: self } + } + #[doc = "Bit 13 - Filter active"] + #[inline(always)] + pub fn fact13(&mut self) -> FACT13_W { + FACT13_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/fb.rs b/embassy-stm32/src/can/bx/pac/can/fb.rs new file mode 100644 index 000000000..1b31e37c5 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/fb.rs @@ -0,0 +1,22 @@ +#[doc = "Filter bank 0 register 1\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fr1](fr1) module"] +pub type FR1 = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _FR1; +#[doc = "`read()` method returns [fr1::R](fr1::R) reader structure"] +impl crate::Readable for FR1 {} +#[doc = "`write(|w| ..)` method takes [fr1::W](fr1::W) writer structure"] +impl crate::Writable for FR1 {} +#[doc = "Filter bank 0 register 1"] +pub mod fr1; +#[doc = "Filter bank 0 register 2\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fr2](fr2) module"] +pub type FR2 = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _FR2; +#[doc = "`read()` method returns [fr2::R](fr2::R) reader structure"] +impl crate::Readable for FR2 {} +#[doc = "`write(|w| ..)` method takes [fr2::W](fr2::W) writer structure"] +impl crate::Writable for FR2 {} +#[doc = "Filter bank 0 register 2"] +pub mod fr2; diff --git a/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs b/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs new file mode 100644 index 000000000..b39d5e8fb --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs @@ -0,0 +1,40 @@ +#[doc = "Reader of register FR1"] +pub type R = crate::R; +#[doc = "Writer for register FR1"] +pub type W = crate::W; +#[doc = "Register FR1 `reset()`'s with value 0"] +impl crate::ResetValue for super::FR1 { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `FB`"] +pub type FB_R = crate::R; +#[doc = "Write proxy for field `FB`"] +pub struct FB_W<'a> { + w: &'a mut W, +} +impl<'a> FB_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u32) -> &'a mut W { + self.w.bits = (self.w.bits & !0xffff_ffff) | ((value as u32) & 0xffff_ffff); + self.w + } +} +impl R { + #[doc = "Bits 0:31 - Filter bits"] + #[inline(always)] + pub fn fb(&self) -> FB_R { + FB_R::new((self.bits & 0xffff_ffff) as u32) + } +} +impl W { + #[doc = "Bits 0:31 - Filter bits"] + #[inline(always)] + pub fn fb(&mut self) -> FB_W { + FB_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs b/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs new file mode 100644 index 000000000..1f318894e --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs @@ -0,0 +1,40 @@ +#[doc = "Reader of register FR2"] +pub type R = crate::R; +#[doc = "Writer for register FR2"] +pub type W = crate::W; +#[doc = "Register FR2 `reset()`'s with value 0"] +impl crate::ResetValue for super::FR2 { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `FB`"] +pub type FB_R = crate::R; +#[doc = "Write proxy for field `FB`"] +pub struct FB_W<'a> { + w: &'a mut W, +} +impl<'a> FB_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u32) -> &'a mut W { + self.w.bits = (self.w.bits & !0xffff_ffff) | ((value as u32) & 0xffff_ffff); + self.w + } +} +impl R { + #[doc = "Bits 0:31 - Filter bits"] + #[inline(always)] + pub fn fb(&self) -> FB_R { + FB_R::new((self.bits & 0xffff_ffff) as u32) + } +} +impl W { + #[doc = "Bits 0:31 - Filter bits"] + #[inline(always)] + pub fn fb(&mut self) -> FB_W { + FB_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/ffa1r.rs b/embassy-stm32/src/can/bx/pac/can/ffa1r.rs new file mode 100644 index 000000000..bc3ab0eb9 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/ffa1r.rs @@ -0,0 +1,492 @@ +#[doc = "Reader of register FFA1R"] +pub type R = crate::R; +#[doc = "Writer for register FFA1R"] +pub type W = crate::W; +#[doc = "Register FFA1R `reset()`'s with value 0"] +impl crate::ResetValue for super::FFA1R { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `FFA0`"] +pub type FFA0_R = crate::R; +#[doc = "Write proxy for field `FFA0`"] +pub struct FFA0_W<'a> { + w: &'a mut W, +} +impl<'a> FFA0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +#[doc = "Reader of field `FFA1`"] +pub type FFA1_R = crate::R; +#[doc = "Write proxy for field `FFA1`"] +pub struct FFA1_W<'a> { + w: &'a mut W, +} +impl<'a> FFA1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); + self.w + } +} +#[doc = "Reader of field `FFA2`"] +pub type FFA2_R = crate::R; +#[doc = "Write proxy for field `FFA2`"] +pub struct FFA2_W<'a> { + w: &'a mut W, +} +impl<'a> FFA2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "Reader of field `FFA3`"] +pub type FFA3_R = crate::R; +#[doc = "Write proxy for field `FFA3`"] +pub struct FFA3_W<'a> { + w: &'a mut W, +} +impl<'a> FFA3_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "Reader of field `FFA4`"] +pub type FFA4_R = crate::R; +#[doc = "Write proxy for field `FFA4`"] +pub struct FFA4_W<'a> { + w: &'a mut W, +} +impl<'a> FFA4_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); + self.w + } +} +#[doc = "Reader of field `FFA5`"] +pub type FFA5_R = crate::R; +#[doc = "Write proxy for field `FFA5`"] +pub struct FFA5_W<'a> { + w: &'a mut W, +} +impl<'a> FFA5_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); + self.w + } +} +#[doc = "Reader of field `FFA6`"] +pub type FFA6_R = crate::R; +#[doc = "Write proxy for field `FFA6`"] +pub struct FFA6_W<'a> { + w: &'a mut W, +} +impl<'a> FFA6_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); + self.w + } +} +#[doc = "Reader of field `FFA7`"] +pub type FFA7_R = crate::R; +#[doc = "Write proxy for field `FFA7`"] +pub struct FFA7_W<'a> { + w: &'a mut W, +} +impl<'a> FFA7_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); + self.w + } +} +#[doc = "Reader of field `FFA8`"] +pub type FFA8_R = crate::R; +#[doc = "Write proxy for field `FFA8`"] +pub struct FFA8_W<'a> { + w: &'a mut W, +} +impl<'a> FFA8_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); + self.w + } +} +#[doc = "Reader of field `FFA9`"] +pub type FFA9_R = crate::R; +#[doc = "Write proxy for field `FFA9`"] +pub struct FFA9_W<'a> { + w: &'a mut W, +} +impl<'a> FFA9_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); + self.w + } +} +#[doc = "Reader of field `FFA10`"] +pub type FFA10_R = crate::R; +#[doc = "Write proxy for field `FFA10`"] +pub struct FFA10_W<'a> { + w: &'a mut W, +} +impl<'a> FFA10_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); + self.w + } +} +#[doc = "Reader of field `FFA11`"] +pub type FFA11_R = crate::R; +#[doc = "Write proxy for field `FFA11`"] +pub struct FFA11_W<'a> { + w: &'a mut W, +} +impl<'a> FFA11_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); + self.w + } +} +#[doc = "Reader of field `FFA12`"] +pub type FFA12_R = crate::R; +#[doc = "Write proxy for field `FFA12`"] +pub struct FFA12_W<'a> { + w: &'a mut W, +} +impl<'a> FFA12_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 12)) | (((value as u32) & 0x01) << 12); + self.w + } +} +#[doc = "Reader of field `FFA13`"] +pub type FFA13_R = crate::R; +#[doc = "Write proxy for field `FFA13`"] +pub struct FFA13_W<'a> { + w: &'a mut W, +} +impl<'a> FFA13_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 13)) | (((value as u32) & 0x01) << 13); + self.w + } +} +impl R { + #[doc = "Bit 0 - Filter FIFO assignment for filter 0"] + #[inline(always)] + pub fn ffa0(&self) -> FFA0_R { + FFA0_R::new((self.bits & 0x01) != 0) + } + #[doc = "Bit 1 - Filter FIFO assignment for filter 1"] + #[inline(always)] + pub fn ffa1(&self) -> FFA1_R { + FFA1_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 2 - Filter FIFO assignment for filter 2"] + #[inline(always)] + pub fn ffa2(&self) -> FFA2_R { + FFA2_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 3 - Filter FIFO assignment for filter 3"] + #[inline(always)] + pub fn ffa3(&self) -> FFA3_R { + FFA3_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bit 4 - Filter FIFO assignment for filter 4"] + #[inline(always)] + pub fn ffa4(&self) -> FFA4_R { + FFA4_R::new(((self.bits >> 4) & 0x01) != 0) + } + #[doc = "Bit 5 - Filter FIFO assignment for filter 5"] + #[inline(always)] + pub fn ffa5(&self) -> FFA5_R { + FFA5_R::new(((self.bits >> 5) & 0x01) != 0) + } + #[doc = "Bit 6 - Filter FIFO assignment for filter 6"] + #[inline(always)] + pub fn ffa6(&self) -> FFA6_R { + FFA6_R::new(((self.bits >> 6) & 0x01) != 0) + } + #[doc = "Bit 7 - Filter FIFO assignment for filter 7"] + #[inline(always)] + pub fn ffa7(&self) -> FFA7_R { + FFA7_R::new(((self.bits >> 7) & 0x01) != 0) + } + #[doc = "Bit 8 - Filter FIFO assignment for filter 8"] + #[inline(always)] + pub fn ffa8(&self) -> FFA8_R { + FFA8_R::new(((self.bits >> 8) & 0x01) != 0) + } + #[doc = "Bit 9 - Filter FIFO assignment for filter 9"] + #[inline(always)] + pub fn ffa9(&self) -> FFA9_R { + FFA9_R::new(((self.bits >> 9) & 0x01) != 0) + } + #[doc = "Bit 10 - Filter FIFO assignment for filter 10"] + #[inline(always)] + pub fn ffa10(&self) -> FFA10_R { + FFA10_R::new(((self.bits >> 10) & 0x01) != 0) + } + #[doc = "Bit 11 - Filter FIFO assignment for filter 11"] + #[inline(always)] + pub fn ffa11(&self) -> FFA11_R { + FFA11_R::new(((self.bits >> 11) & 0x01) != 0) + } + #[doc = "Bit 12 - Filter FIFO assignment for filter 12"] + #[inline(always)] + pub fn ffa12(&self) -> FFA12_R { + FFA12_R::new(((self.bits >> 12) & 0x01) != 0) + } + #[doc = "Bit 13 - Filter FIFO assignment for filter 13"] + #[inline(always)] + pub fn ffa13(&self) -> FFA13_R { + FFA13_R::new(((self.bits >> 13) & 0x01) != 0) + } +} +impl W { + #[doc = "Bit 0 - Filter FIFO assignment for filter 0"] + #[inline(always)] + pub fn ffa0(&mut self) -> FFA0_W { + FFA0_W { w: self } + } + #[doc = "Bit 1 - Filter FIFO assignment for filter 1"] + #[inline(always)] + pub fn ffa1(&mut self) -> FFA1_W { + FFA1_W { w: self } + } + #[doc = "Bit 2 - Filter FIFO assignment for filter 2"] + #[inline(always)] + pub fn ffa2(&mut self) -> FFA2_W { + FFA2_W { w: self } + } + #[doc = "Bit 3 - Filter FIFO assignment for filter 3"] + #[inline(always)] + pub fn ffa3(&mut self) -> FFA3_W { + FFA3_W { w: self } + } + #[doc = "Bit 4 - Filter FIFO assignment for filter 4"] + #[inline(always)] + pub fn ffa4(&mut self) -> FFA4_W { + FFA4_W { w: self } + } + #[doc = "Bit 5 - Filter FIFO assignment for filter 5"] + #[inline(always)] + pub fn ffa5(&mut self) -> FFA5_W { + FFA5_W { w: self } + } + #[doc = "Bit 6 - Filter FIFO assignment for filter 6"] + #[inline(always)] + pub fn ffa6(&mut self) -> FFA6_W { + FFA6_W { w: self } + } + #[doc = "Bit 7 - Filter FIFO assignment for filter 7"] + #[inline(always)] + pub fn ffa7(&mut self) -> FFA7_W { + FFA7_W { w: self } + } + #[doc = "Bit 8 - Filter FIFO assignment for filter 8"] + #[inline(always)] + pub fn ffa8(&mut self) -> FFA8_W { + FFA8_W { w: self } + } + #[doc = "Bit 9 - Filter FIFO assignment for filter 9"] + #[inline(always)] + pub fn ffa9(&mut self) -> FFA9_W { + FFA9_W { w: self } + } + #[doc = "Bit 10 - Filter FIFO assignment for filter 10"] + #[inline(always)] + pub fn ffa10(&mut self) -> FFA10_W { + FFA10_W { w: self } + } + #[doc = "Bit 11 - Filter FIFO assignment for filter 11"] + #[inline(always)] + pub fn ffa11(&mut self) -> FFA11_W { + FFA11_W { w: self } + } + #[doc = "Bit 12 - Filter FIFO assignment for filter 12"] + #[inline(always)] + pub fn ffa12(&mut self) -> FFA12_W { + FFA12_W { w: self } + } + #[doc = "Bit 13 - Filter FIFO assignment for filter 13"] + #[inline(always)] + pub fn ffa13(&mut self) -> FFA13_W { + FFA13_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/fm1r.rs b/embassy-stm32/src/can/bx/pac/can/fm1r.rs new file mode 100644 index 000000000..e0a8dc648 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/fm1r.rs @@ -0,0 +1,492 @@ +#[doc = "Reader of register FM1R"] +pub type R = crate::R; +#[doc = "Writer for register FM1R"] +pub type W = crate::W; +#[doc = "Register FM1R `reset()`'s with value 0"] +impl crate::ResetValue for super::FM1R { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `FBM0`"] +pub type FBM0_R = crate::R; +#[doc = "Write proxy for field `FBM0`"] +pub struct FBM0_W<'a> { + w: &'a mut W, +} +impl<'a> FBM0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +#[doc = "Reader of field `FBM1`"] +pub type FBM1_R = crate::R; +#[doc = "Write proxy for field `FBM1`"] +pub struct FBM1_W<'a> { + w: &'a mut W, +} +impl<'a> FBM1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); + self.w + } +} +#[doc = "Reader of field `FBM2`"] +pub type FBM2_R = crate::R; +#[doc = "Write proxy for field `FBM2`"] +pub struct FBM2_W<'a> { + w: &'a mut W, +} +impl<'a> FBM2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "Reader of field `FBM3`"] +pub type FBM3_R = crate::R; +#[doc = "Write proxy for field `FBM3`"] +pub struct FBM3_W<'a> { + w: &'a mut W, +} +impl<'a> FBM3_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "Reader of field `FBM4`"] +pub type FBM4_R = crate::R; +#[doc = "Write proxy for field `FBM4`"] +pub struct FBM4_W<'a> { + w: &'a mut W, +} +impl<'a> FBM4_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); + self.w + } +} +#[doc = "Reader of field `FBM5`"] +pub type FBM5_R = crate::R; +#[doc = "Write proxy for field `FBM5`"] +pub struct FBM5_W<'a> { + w: &'a mut W, +} +impl<'a> FBM5_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); + self.w + } +} +#[doc = "Reader of field `FBM6`"] +pub type FBM6_R = crate::R; +#[doc = "Write proxy for field `FBM6`"] +pub struct FBM6_W<'a> { + w: &'a mut W, +} +impl<'a> FBM6_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); + self.w + } +} +#[doc = "Reader of field `FBM7`"] +pub type FBM7_R = crate::R; +#[doc = "Write proxy for field `FBM7`"] +pub struct FBM7_W<'a> { + w: &'a mut W, +} +impl<'a> FBM7_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); + self.w + } +} +#[doc = "Reader of field `FBM8`"] +pub type FBM8_R = crate::R; +#[doc = "Write proxy for field `FBM8`"] +pub struct FBM8_W<'a> { + w: &'a mut W, +} +impl<'a> FBM8_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); + self.w + } +} +#[doc = "Reader of field `FBM9`"] +pub type FBM9_R = crate::R; +#[doc = "Write proxy for field `FBM9`"] +pub struct FBM9_W<'a> { + w: &'a mut W, +} +impl<'a> FBM9_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); + self.w + } +} +#[doc = "Reader of field `FBM10`"] +pub type FBM10_R = crate::R; +#[doc = "Write proxy for field `FBM10`"] +pub struct FBM10_W<'a> { + w: &'a mut W, +} +impl<'a> FBM10_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); + self.w + } +} +#[doc = "Reader of field `FBM11`"] +pub type FBM11_R = crate::R; +#[doc = "Write proxy for field `FBM11`"] +pub struct FBM11_W<'a> { + w: &'a mut W, +} +impl<'a> FBM11_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); + self.w + } +} +#[doc = "Reader of field `FBM12`"] +pub type FBM12_R = crate::R; +#[doc = "Write proxy for field `FBM12`"] +pub struct FBM12_W<'a> { + w: &'a mut W, +} +impl<'a> FBM12_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 12)) | (((value as u32) & 0x01) << 12); + self.w + } +} +#[doc = "Reader of field `FBM13`"] +pub type FBM13_R = crate::R; +#[doc = "Write proxy for field `FBM13`"] +pub struct FBM13_W<'a> { + w: &'a mut W, +} +impl<'a> FBM13_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 13)) | (((value as u32) & 0x01) << 13); + self.w + } +} +impl R { + #[doc = "Bit 0 - Filter mode"] + #[inline(always)] + pub fn fbm0(&self) -> FBM0_R { + FBM0_R::new((self.bits & 0x01) != 0) + } + #[doc = "Bit 1 - Filter mode"] + #[inline(always)] + pub fn fbm1(&self) -> FBM1_R { + FBM1_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 2 - Filter mode"] + #[inline(always)] + pub fn fbm2(&self) -> FBM2_R { + FBM2_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 3 - Filter mode"] + #[inline(always)] + pub fn fbm3(&self) -> FBM3_R { + FBM3_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bit 4 - Filter mode"] + #[inline(always)] + pub fn fbm4(&self) -> FBM4_R { + FBM4_R::new(((self.bits >> 4) & 0x01) != 0) + } + #[doc = "Bit 5 - Filter mode"] + #[inline(always)] + pub fn fbm5(&self) -> FBM5_R { + FBM5_R::new(((self.bits >> 5) & 0x01) != 0) + } + #[doc = "Bit 6 - Filter mode"] + #[inline(always)] + pub fn fbm6(&self) -> FBM6_R { + FBM6_R::new(((self.bits >> 6) & 0x01) != 0) + } + #[doc = "Bit 7 - Filter mode"] + #[inline(always)] + pub fn fbm7(&self) -> FBM7_R { + FBM7_R::new(((self.bits >> 7) & 0x01) != 0) + } + #[doc = "Bit 8 - Filter mode"] + #[inline(always)] + pub fn fbm8(&self) -> FBM8_R { + FBM8_R::new(((self.bits >> 8) & 0x01) != 0) + } + #[doc = "Bit 9 - Filter mode"] + #[inline(always)] + pub fn fbm9(&self) -> FBM9_R { + FBM9_R::new(((self.bits >> 9) & 0x01) != 0) + } + #[doc = "Bit 10 - Filter mode"] + #[inline(always)] + pub fn fbm10(&self) -> FBM10_R { + FBM10_R::new(((self.bits >> 10) & 0x01) != 0) + } + #[doc = "Bit 11 - Filter mode"] + #[inline(always)] + pub fn fbm11(&self) -> FBM11_R { + FBM11_R::new(((self.bits >> 11) & 0x01) != 0) + } + #[doc = "Bit 12 - Filter mode"] + #[inline(always)] + pub fn fbm12(&self) -> FBM12_R { + FBM12_R::new(((self.bits >> 12) & 0x01) != 0) + } + #[doc = "Bit 13 - Filter mode"] + #[inline(always)] + pub fn fbm13(&self) -> FBM13_R { + FBM13_R::new(((self.bits >> 13) & 0x01) != 0) + } +} +impl W { + #[doc = "Bit 0 - Filter mode"] + #[inline(always)] + pub fn fbm0(&mut self) -> FBM0_W { + FBM0_W { w: self } + } + #[doc = "Bit 1 - Filter mode"] + #[inline(always)] + pub fn fbm1(&mut self) -> FBM1_W { + FBM1_W { w: self } + } + #[doc = "Bit 2 - Filter mode"] + #[inline(always)] + pub fn fbm2(&mut self) -> FBM2_W { + FBM2_W { w: self } + } + #[doc = "Bit 3 - Filter mode"] + #[inline(always)] + pub fn fbm3(&mut self) -> FBM3_W { + FBM3_W { w: self } + } + #[doc = "Bit 4 - Filter mode"] + #[inline(always)] + pub fn fbm4(&mut self) -> FBM4_W { + FBM4_W { w: self } + } + #[doc = "Bit 5 - Filter mode"] + #[inline(always)] + pub fn fbm5(&mut self) -> FBM5_W { + FBM5_W { w: self } + } + #[doc = "Bit 6 - Filter mode"] + #[inline(always)] + pub fn fbm6(&mut self) -> FBM6_W { + FBM6_W { w: self } + } + #[doc = "Bit 7 - Filter mode"] + #[inline(always)] + pub fn fbm7(&mut self) -> FBM7_W { + FBM7_W { w: self } + } + #[doc = "Bit 8 - Filter mode"] + #[inline(always)] + pub fn fbm8(&mut self) -> FBM8_W { + FBM8_W { w: self } + } + #[doc = "Bit 9 - Filter mode"] + #[inline(always)] + pub fn fbm9(&mut self) -> FBM9_W { + FBM9_W { w: self } + } + #[doc = "Bit 10 - Filter mode"] + #[inline(always)] + pub fn fbm10(&mut self) -> FBM10_W { + FBM10_W { w: self } + } + #[doc = "Bit 11 - Filter mode"] + #[inline(always)] + pub fn fbm11(&mut self) -> FBM11_W { + FBM11_W { w: self } + } + #[doc = "Bit 12 - Filter mode"] + #[inline(always)] + pub fn fbm12(&mut self) -> FBM12_W { + FBM12_W { w: self } + } + #[doc = "Bit 13 - Filter mode"] + #[inline(always)] + pub fn fbm13(&mut self) -> FBM13_W { + FBM13_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/fmr.rs b/embassy-stm32/src/can/bx/pac/can/fmr.rs new file mode 100644 index 000000000..5701af452 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/fmr.rs @@ -0,0 +1,74 @@ +#[doc = "Reader of register FMR"] +pub type R = crate::R; +#[doc = "Writer for register FMR"] +pub type W = crate::W; +#[doc = "Register FMR `reset()`'s with value 0"] +impl crate::ResetValue for super::FMR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `CAN2SB`"] +pub type CAN2SB_R = crate::R; +#[doc = "Write proxy for field `CAN2SB`"] +pub struct CAN2SB_W<'a> { + w: &'a mut W, +} +impl<'a> CAN2SB_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x3f << 8)) | (((value as u32) & 0x3f) << 8); + self.w + } +} +#[doc = "Reader of field `FINIT`"] +pub type FINIT_R = crate::R; +#[doc = "Write proxy for field `FINIT`"] +pub struct FINIT_W<'a> { + w: &'a mut W, +} +impl<'a> FINIT_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +impl R { + #[doc = "Bits 8:13 - CAN2SB"] + #[inline(always)] + pub fn can2sb(&self) -> CAN2SB_R { + CAN2SB_R::new(((self.bits >> 8) & 0x3f) as u8) + } + #[doc = "Bit 0 - FINIT"] + #[inline(always)] + pub fn finit(&self) -> FINIT_R { + FINIT_R::new((self.bits & 0x01) != 0) + } +} +impl W { + #[doc = "Bits 8:13 - CAN2SB"] + #[inline(always)] + pub fn can2sb(&mut self) -> CAN2SB_W { + CAN2SB_W { w: self } + } + #[doc = "Bit 0 - FINIT"] + #[inline(always)] + pub fn finit(&mut self) -> FINIT_W { + FINIT_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/fs1r.rs b/embassy-stm32/src/can/bx/pac/can/fs1r.rs new file mode 100644 index 000000000..7bff8197d --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/fs1r.rs @@ -0,0 +1,492 @@ +#[doc = "Reader of register FS1R"] +pub type R = crate::R; +#[doc = "Writer for register FS1R"] +pub type W = crate::W; +#[doc = "Register FS1R `reset()`'s with value 0"] +impl crate::ResetValue for super::FS1R { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `FSC0`"] +pub type FSC0_R = crate::R; +#[doc = "Write proxy for field `FSC0`"] +pub struct FSC0_W<'a> { + w: &'a mut W, +} +impl<'a> FSC0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +#[doc = "Reader of field `FSC1`"] +pub type FSC1_R = crate::R; +#[doc = "Write proxy for field `FSC1`"] +pub struct FSC1_W<'a> { + w: &'a mut W, +} +impl<'a> FSC1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); + self.w + } +} +#[doc = "Reader of field `FSC2`"] +pub type FSC2_R = crate::R; +#[doc = "Write proxy for field `FSC2`"] +pub struct FSC2_W<'a> { + w: &'a mut W, +} +impl<'a> FSC2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "Reader of field `FSC3`"] +pub type FSC3_R = crate::R; +#[doc = "Write proxy for field `FSC3`"] +pub struct FSC3_W<'a> { + w: &'a mut W, +} +impl<'a> FSC3_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "Reader of field `FSC4`"] +pub type FSC4_R = crate::R; +#[doc = "Write proxy for field `FSC4`"] +pub struct FSC4_W<'a> { + w: &'a mut W, +} +impl<'a> FSC4_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); + self.w + } +} +#[doc = "Reader of field `FSC5`"] +pub type FSC5_R = crate::R; +#[doc = "Write proxy for field `FSC5`"] +pub struct FSC5_W<'a> { + w: &'a mut W, +} +impl<'a> FSC5_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); + self.w + } +} +#[doc = "Reader of field `FSC6`"] +pub type FSC6_R = crate::R; +#[doc = "Write proxy for field `FSC6`"] +pub struct FSC6_W<'a> { + w: &'a mut W, +} +impl<'a> FSC6_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); + self.w + } +} +#[doc = "Reader of field `FSC7`"] +pub type FSC7_R = crate::R; +#[doc = "Write proxy for field `FSC7`"] +pub struct FSC7_W<'a> { + w: &'a mut W, +} +impl<'a> FSC7_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); + self.w + } +} +#[doc = "Reader of field `FSC8`"] +pub type FSC8_R = crate::R; +#[doc = "Write proxy for field `FSC8`"] +pub struct FSC8_W<'a> { + w: &'a mut W, +} +impl<'a> FSC8_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); + self.w + } +} +#[doc = "Reader of field `FSC9`"] +pub type FSC9_R = crate::R; +#[doc = "Write proxy for field `FSC9`"] +pub struct FSC9_W<'a> { + w: &'a mut W, +} +impl<'a> FSC9_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); + self.w + } +} +#[doc = "Reader of field `FSC10`"] +pub type FSC10_R = crate::R; +#[doc = "Write proxy for field `FSC10`"] +pub struct FSC10_W<'a> { + w: &'a mut W, +} +impl<'a> FSC10_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); + self.w + } +} +#[doc = "Reader of field `FSC11`"] +pub type FSC11_R = crate::R; +#[doc = "Write proxy for field `FSC11`"] +pub struct FSC11_W<'a> { + w: &'a mut W, +} +impl<'a> FSC11_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); + self.w + } +} +#[doc = "Reader of field `FSC12`"] +pub type FSC12_R = crate::R; +#[doc = "Write proxy for field `FSC12`"] +pub struct FSC12_W<'a> { + w: &'a mut W, +} +impl<'a> FSC12_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 12)) | (((value as u32) & 0x01) << 12); + self.w + } +} +#[doc = "Reader of field `FSC13`"] +pub type FSC13_R = crate::R; +#[doc = "Write proxy for field `FSC13`"] +pub struct FSC13_W<'a> { + w: &'a mut W, +} +impl<'a> FSC13_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 13)) | (((value as u32) & 0x01) << 13); + self.w + } +} +impl R { + #[doc = "Bit 0 - Filter scale configuration"] + #[inline(always)] + pub fn fsc0(&self) -> FSC0_R { + FSC0_R::new((self.bits & 0x01) != 0) + } + #[doc = "Bit 1 - Filter scale configuration"] + #[inline(always)] + pub fn fsc1(&self) -> FSC1_R { + FSC1_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 2 - Filter scale configuration"] + #[inline(always)] + pub fn fsc2(&self) -> FSC2_R { + FSC2_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 3 - Filter scale configuration"] + #[inline(always)] + pub fn fsc3(&self) -> FSC3_R { + FSC3_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bit 4 - Filter scale configuration"] + #[inline(always)] + pub fn fsc4(&self) -> FSC4_R { + FSC4_R::new(((self.bits >> 4) & 0x01) != 0) + } + #[doc = "Bit 5 - Filter scale configuration"] + #[inline(always)] + pub fn fsc5(&self) -> FSC5_R { + FSC5_R::new(((self.bits >> 5) & 0x01) != 0) + } + #[doc = "Bit 6 - Filter scale configuration"] + #[inline(always)] + pub fn fsc6(&self) -> FSC6_R { + FSC6_R::new(((self.bits >> 6) & 0x01) != 0) + } + #[doc = "Bit 7 - Filter scale configuration"] + #[inline(always)] + pub fn fsc7(&self) -> FSC7_R { + FSC7_R::new(((self.bits >> 7) & 0x01) != 0) + } + #[doc = "Bit 8 - Filter scale configuration"] + #[inline(always)] + pub fn fsc8(&self) -> FSC8_R { + FSC8_R::new(((self.bits >> 8) & 0x01) != 0) + } + #[doc = "Bit 9 - Filter scale configuration"] + #[inline(always)] + pub fn fsc9(&self) -> FSC9_R { + FSC9_R::new(((self.bits >> 9) & 0x01) != 0) + } + #[doc = "Bit 10 - Filter scale configuration"] + #[inline(always)] + pub fn fsc10(&self) -> FSC10_R { + FSC10_R::new(((self.bits >> 10) & 0x01) != 0) + } + #[doc = "Bit 11 - Filter scale configuration"] + #[inline(always)] + pub fn fsc11(&self) -> FSC11_R { + FSC11_R::new(((self.bits >> 11) & 0x01) != 0) + } + #[doc = "Bit 12 - Filter scale configuration"] + #[inline(always)] + pub fn fsc12(&self) -> FSC12_R { + FSC12_R::new(((self.bits >> 12) & 0x01) != 0) + } + #[doc = "Bit 13 - Filter scale configuration"] + #[inline(always)] + pub fn fsc13(&self) -> FSC13_R { + FSC13_R::new(((self.bits >> 13) & 0x01) != 0) + } +} +impl W { + #[doc = "Bit 0 - Filter scale configuration"] + #[inline(always)] + pub fn fsc0(&mut self) -> FSC0_W { + FSC0_W { w: self } + } + #[doc = "Bit 1 - Filter scale configuration"] + #[inline(always)] + pub fn fsc1(&mut self) -> FSC1_W { + FSC1_W { w: self } + } + #[doc = "Bit 2 - Filter scale configuration"] + #[inline(always)] + pub fn fsc2(&mut self) -> FSC2_W { + FSC2_W { w: self } + } + #[doc = "Bit 3 - Filter scale configuration"] + #[inline(always)] + pub fn fsc3(&mut self) -> FSC3_W { + FSC3_W { w: self } + } + #[doc = "Bit 4 - Filter scale configuration"] + #[inline(always)] + pub fn fsc4(&mut self) -> FSC4_W { + FSC4_W { w: self } + } + #[doc = "Bit 5 - Filter scale configuration"] + #[inline(always)] + pub fn fsc5(&mut self) -> FSC5_W { + FSC5_W { w: self } + } + #[doc = "Bit 6 - Filter scale configuration"] + #[inline(always)] + pub fn fsc6(&mut self) -> FSC6_W { + FSC6_W { w: self } + } + #[doc = "Bit 7 - Filter scale configuration"] + #[inline(always)] + pub fn fsc7(&mut self) -> FSC7_W { + FSC7_W { w: self } + } + #[doc = "Bit 8 - Filter scale configuration"] + #[inline(always)] + pub fn fsc8(&mut self) -> FSC8_W { + FSC8_W { w: self } + } + #[doc = "Bit 9 - Filter scale configuration"] + #[inline(always)] + pub fn fsc9(&mut self) -> FSC9_W { + FSC9_W { w: self } + } + #[doc = "Bit 10 - Filter scale configuration"] + #[inline(always)] + pub fn fsc10(&mut self) -> FSC10_W { + FSC10_W { w: self } + } + #[doc = "Bit 11 - Filter scale configuration"] + #[inline(always)] + pub fn fsc11(&mut self) -> FSC11_W { + FSC11_W { w: self } + } + #[doc = "Bit 12 - Filter scale configuration"] + #[inline(always)] + pub fn fsc12(&mut self) -> FSC12_W { + FSC12_W { w: self } + } + #[doc = "Bit 13 - Filter scale configuration"] + #[inline(always)] + pub fn fsc13(&mut self) -> FSC13_W { + FSC13_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/ier.rs b/embassy-stm32/src/can/bx/pac/can/ier.rs new file mode 100644 index 000000000..3c57331b7 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/ier.rs @@ -0,0 +1,1218 @@ +#[doc = "Reader of register IER"] +pub type R = crate::R; +#[doc = "Writer for register IER"] +pub type W = crate::W; +#[doc = "Register IER `reset()`'s with value 0"] +impl crate::ResetValue for super::IER { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "SLKIE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum SLKIE_A { + #[doc = "0: No interrupt when SLAKI bit is set"] + DISABLED = 0, + #[doc = "1: Interrupt generated when SLAKI bit is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: SLKIE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `SLKIE`"] +pub type SLKIE_R = crate::R; +impl SLKIE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> SLKIE_A { + match self.bits { + false => SLKIE_A::DISABLED, + true => SLKIE_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == SLKIE_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == SLKIE_A::ENABLED + } +} +#[doc = "Write proxy for field `SLKIE`"] +pub struct SLKIE_W<'a> { + w: &'a mut W, +} +impl<'a> SLKIE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: SLKIE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt when SLAKI bit is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(SLKIE_A::DISABLED) + } + #[doc = "Interrupt generated when SLAKI bit is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(SLKIE_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 17)) | (((value as u32) & 0x01) << 17); + self.w + } +} +#[doc = "WKUIE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum WKUIE_A { + #[doc = "0: No interrupt when WKUI is set"] + DISABLED = 0, + #[doc = "1: Interrupt generated when WKUI bit is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: WKUIE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `WKUIE`"] +pub type WKUIE_R = crate::R; +impl WKUIE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> WKUIE_A { + match self.bits { + false => WKUIE_A::DISABLED, + true => WKUIE_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == WKUIE_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == WKUIE_A::ENABLED + } +} +#[doc = "Write proxy for field `WKUIE`"] +pub struct WKUIE_W<'a> { + w: &'a mut W, +} +impl<'a> WKUIE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: WKUIE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt when WKUI is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(WKUIE_A::DISABLED) + } + #[doc = "Interrupt generated when WKUI bit is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(WKUIE_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 16)) | (((value as u32) & 0x01) << 16); + self.w + } +} +#[doc = "ERRIE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ERRIE_A { + #[doc = "0: No interrupt will be generated when an error condition is pending in the CAN_ESR"] + DISABLED = 0, + #[doc = "1: An interrupt will be generation when an error condition is pending in the CAN_ESR"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: ERRIE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `ERRIE`"] +pub type ERRIE_R = crate::R; +impl ERRIE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> ERRIE_A { + match self.bits { + false => ERRIE_A::DISABLED, + true => ERRIE_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == ERRIE_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == ERRIE_A::ENABLED + } +} +#[doc = "Write proxy for field `ERRIE`"] +pub struct ERRIE_W<'a> { + w: &'a mut W, +} +impl<'a> ERRIE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: ERRIE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt will be generated when an error condition is pending in the CAN_ESR"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(ERRIE_A::DISABLED) + } + #[doc = "An interrupt will be generation when an error condition is pending in the CAN_ESR"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(ERRIE_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 15)) | (((value as u32) & 0x01) << 15); + self.w + } +} +#[doc = "LECIE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum LECIE_A { + #[doc = "0: ERRI bit will not be set when the error code in LEC\\[2:0\\] +is set by hardware on error detection"] + DISABLED = 0, + #[doc = "1: ERRI bit will be set when the error code in LEC\\[2:0\\] +is set by hardware on error detection"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: LECIE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `LECIE`"] +pub type LECIE_R = crate::R; +impl LECIE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> LECIE_A { + match self.bits { + false => LECIE_A::DISABLED, + true => LECIE_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == LECIE_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == LECIE_A::ENABLED + } +} +#[doc = "Write proxy for field `LECIE`"] +pub struct LECIE_W<'a> { + w: &'a mut W, +} +impl<'a> LECIE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: LECIE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "ERRI bit will not be set when the error code in LEC\\[2:0\\] +is set by hardware on error detection"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(LECIE_A::DISABLED) + } + #[doc = "ERRI bit will be set when the error code in LEC\\[2:0\\] +is set by hardware on error detection"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(LECIE_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); + self.w + } +} +#[doc = "BOFIE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BOFIE_A { + #[doc = "0: ERRI bit will not be set when BOFF is set"] + DISABLED = 0, + #[doc = "1: ERRI bit will be set when BOFF is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: BOFIE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `BOFIE`"] +pub type BOFIE_R = crate::R; +impl BOFIE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> BOFIE_A { + match self.bits { + false => BOFIE_A::DISABLED, + true => BOFIE_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == BOFIE_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == BOFIE_A::ENABLED + } +} +#[doc = "Write proxy for field `BOFIE`"] +pub struct BOFIE_W<'a> { + w: &'a mut W, +} +impl<'a> BOFIE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: BOFIE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "ERRI bit will not be set when BOFF is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(BOFIE_A::DISABLED) + } + #[doc = "ERRI bit will be set when BOFF is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(BOFIE_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); + self.w + } +} +#[doc = "EPVIE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum EPVIE_A { + #[doc = "0: ERRI bit will not be set when EPVF is set"] + DISABLED = 0, + #[doc = "1: ERRI bit will be set when EPVF is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: EPVIE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `EPVIE`"] +pub type EPVIE_R = crate::R; +impl EPVIE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> EPVIE_A { + match self.bits { + false => EPVIE_A::DISABLED, + true => EPVIE_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == EPVIE_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == EPVIE_A::ENABLED + } +} +#[doc = "Write proxy for field `EPVIE`"] +pub struct EPVIE_W<'a> { + w: &'a mut W, +} +impl<'a> EPVIE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: EPVIE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "ERRI bit will not be set when EPVF is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(EPVIE_A::DISABLED) + } + #[doc = "ERRI bit will be set when EPVF is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(EPVIE_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); + self.w + } +} +#[doc = "EWGIE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum EWGIE_A { + #[doc = "0: ERRI bit will not be set when EWGF is set"] + DISABLED = 0, + #[doc = "1: ERRI bit will be set when EWGF is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: EWGIE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `EWGIE`"] +pub type EWGIE_R = crate::R; +impl EWGIE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> EWGIE_A { + match self.bits { + false => EWGIE_A::DISABLED, + true => EWGIE_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == EWGIE_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == EWGIE_A::ENABLED + } +} +#[doc = "Write proxy for field `EWGIE`"] +pub struct EWGIE_W<'a> { + w: &'a mut W, +} +impl<'a> EWGIE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: EWGIE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "ERRI bit will not be set when EWGF is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(EWGIE_A::DISABLED) + } + #[doc = "ERRI bit will be set when EWGF is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(EWGIE_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); + self.w + } +} +#[doc = "FOVIE1\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FOVIE1_A { + #[doc = "0: No interrupt when FOVR is set"] + DISABLED = 0, + #[doc = "1: Interrupt generation when FOVR is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FOVIE1_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `FOVIE1`"] +pub type FOVIE1_R = crate::R; +impl FOVIE1_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> FOVIE1_A { + match self.bits { + false => FOVIE1_A::DISABLED, + true => FOVIE1_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == FOVIE1_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == FOVIE1_A::ENABLED + } +} +#[doc = "Write proxy for field `FOVIE1`"] +pub struct FOVIE1_W<'a> { + w: &'a mut W, +} +impl<'a> FOVIE1_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: FOVIE1_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt when FOVR is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(FOVIE1_A::DISABLED) + } + #[doc = "Interrupt generation when FOVR is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(FOVIE1_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); + self.w + } +} +#[doc = "FFIE1\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FFIE1_A { + #[doc = "0: No interrupt when FULL bit is set"] + DISABLED = 0, + #[doc = "1: Interrupt generated when FULL bit is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FFIE1_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `FFIE1`"] +pub type FFIE1_R = crate::R; +impl FFIE1_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> FFIE1_A { + match self.bits { + false => FFIE1_A::DISABLED, + true => FFIE1_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == FFIE1_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == FFIE1_A::ENABLED + } +} +#[doc = "Write proxy for field `FFIE1`"] +pub struct FFIE1_W<'a> { + w: &'a mut W, +} +impl<'a> FFIE1_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: FFIE1_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt when FULL bit is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(FFIE1_A::DISABLED) + } + #[doc = "Interrupt generated when FULL bit is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(FFIE1_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); + self.w + } +} +#[doc = "FMPIE1\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FMPIE1_A { + #[doc = "0: No interrupt generated when state of FMP\\[1:0\\] +bits are not 00b"] + DISABLED = 0, + #[doc = "1: Interrupt generated when state of FMP\\[1:0\\] +bits are not 00b"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FMPIE1_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `FMPIE1`"] +pub type FMPIE1_R = crate::R; +impl FMPIE1_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> FMPIE1_A { + match self.bits { + false => FMPIE1_A::DISABLED, + true => FMPIE1_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == FMPIE1_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == FMPIE1_A::ENABLED + } +} +#[doc = "Write proxy for field `FMPIE1`"] +pub struct FMPIE1_W<'a> { + w: &'a mut W, +} +impl<'a> FMPIE1_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: FMPIE1_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt generated when state of FMP\\[1:0\\] +bits are not 00b"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(FMPIE1_A::DISABLED) + } + #[doc = "Interrupt generated when state of FMP\\[1:0\\] +bits are not 00b"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(FMPIE1_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); + self.w + } +} +#[doc = "FOVIE0\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FOVIE0_A { + #[doc = "0: No interrupt when FOVR bit is set"] + DISABLED = 0, + #[doc = "1: Interrupt generated when FOVR bit is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FOVIE0_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `FOVIE0`"] +pub type FOVIE0_R = crate::R; +impl FOVIE0_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> FOVIE0_A { + match self.bits { + false => FOVIE0_A::DISABLED, + true => FOVIE0_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == FOVIE0_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == FOVIE0_A::ENABLED + } +} +#[doc = "Write proxy for field `FOVIE0`"] +pub struct FOVIE0_W<'a> { + w: &'a mut W, +} +impl<'a> FOVIE0_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: FOVIE0_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt when FOVR bit is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(FOVIE0_A::DISABLED) + } + #[doc = "Interrupt generated when FOVR bit is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(FOVIE0_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "FFIE0\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FFIE0_A { + #[doc = "0: No interrupt when FULL bit is set"] + DISABLED = 0, + #[doc = "1: Interrupt generated when FULL bit is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FFIE0_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `FFIE0`"] +pub type FFIE0_R = crate::R; +impl FFIE0_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> FFIE0_A { + match self.bits { + false => FFIE0_A::DISABLED, + true => FFIE0_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == FFIE0_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == FFIE0_A::ENABLED + } +} +#[doc = "Write proxy for field `FFIE0`"] +pub struct FFIE0_W<'a> { + w: &'a mut W, +} +impl<'a> FFIE0_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: FFIE0_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt when FULL bit is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(FFIE0_A::DISABLED) + } + #[doc = "Interrupt generated when FULL bit is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(FFIE0_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "FMPIE0\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FMPIE0_A { + #[doc = "0: No interrupt generated when state of FMP\\[1:0\\] +bits are not 00"] + DISABLED = 0, + #[doc = "1: Interrupt generated when state of FMP\\[1:0\\] +bits are not 00b"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FMPIE0_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `FMPIE0`"] +pub type FMPIE0_R = crate::R; +impl FMPIE0_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> FMPIE0_A { + match self.bits { + false => FMPIE0_A::DISABLED, + true => FMPIE0_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == FMPIE0_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == FMPIE0_A::ENABLED + } +} +#[doc = "Write proxy for field `FMPIE0`"] +pub struct FMPIE0_W<'a> { + w: &'a mut W, +} +impl<'a> FMPIE0_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: FMPIE0_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt generated when state of FMP\\[1:0\\] +bits are not 00"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(FMPIE0_A::DISABLED) + } + #[doc = "Interrupt generated when state of FMP\\[1:0\\] +bits are not 00b"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(FMPIE0_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); + self.w + } +} +#[doc = "TMEIE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum TMEIE_A { + #[doc = "0: No interrupt when RQCPx bit is set"] + DISABLED = 0, + #[doc = "1: Interrupt generated when RQCPx bit is set"] + ENABLED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: TMEIE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `TMEIE`"] +pub type TMEIE_R = crate::R; +impl TMEIE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> TMEIE_A { + match self.bits { + false => TMEIE_A::DISABLED, + true => TMEIE_A::ENABLED, + } + } + #[doc = "Checks if the value of the field is `DISABLED`"] + #[inline(always)] + pub fn is_disabled(&self) -> bool { + *self == TMEIE_A::DISABLED + } + #[doc = "Checks if the value of the field is `ENABLED`"] + #[inline(always)] + pub fn is_enabled(&self) -> bool { + *self == TMEIE_A::ENABLED + } +} +#[doc = "Write proxy for field `TMEIE`"] +pub struct TMEIE_W<'a> { + w: &'a mut W, +} +impl<'a> TMEIE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: TMEIE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "No interrupt when RQCPx bit is set"] + #[inline(always)] + pub fn disabled(self) -> &'a mut W { + self.variant(TMEIE_A::DISABLED) + } + #[doc = "Interrupt generated when RQCPx bit is set"] + #[inline(always)] + pub fn enabled(self) -> &'a mut W { + self.variant(TMEIE_A::ENABLED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +impl R { + #[doc = "Bit 17 - SLKIE"] + #[inline(always)] + pub fn slkie(&self) -> SLKIE_R { + SLKIE_R::new(((self.bits >> 17) & 0x01) != 0) + } + #[doc = "Bit 16 - WKUIE"] + #[inline(always)] + pub fn wkuie(&self) -> WKUIE_R { + WKUIE_R::new(((self.bits >> 16) & 0x01) != 0) + } + #[doc = "Bit 15 - ERRIE"] + #[inline(always)] + pub fn errie(&self) -> ERRIE_R { + ERRIE_R::new(((self.bits >> 15) & 0x01) != 0) + } + #[doc = "Bit 11 - LECIE"] + #[inline(always)] + pub fn lecie(&self) -> LECIE_R { + LECIE_R::new(((self.bits >> 11) & 0x01) != 0) + } + #[doc = "Bit 10 - BOFIE"] + #[inline(always)] + pub fn bofie(&self) -> BOFIE_R { + BOFIE_R::new(((self.bits >> 10) & 0x01) != 0) + } + #[doc = "Bit 9 - EPVIE"] + #[inline(always)] + pub fn epvie(&self) -> EPVIE_R { + EPVIE_R::new(((self.bits >> 9) & 0x01) != 0) + } + #[doc = "Bit 8 - EWGIE"] + #[inline(always)] + pub fn ewgie(&self) -> EWGIE_R { + EWGIE_R::new(((self.bits >> 8) & 0x01) != 0) + } + #[doc = "Bit 6 - FOVIE1"] + #[inline(always)] + pub fn fovie1(&self) -> FOVIE1_R { + FOVIE1_R::new(((self.bits >> 6) & 0x01) != 0) + } + #[doc = "Bit 5 - FFIE1"] + #[inline(always)] + pub fn ffie1(&self) -> FFIE1_R { + FFIE1_R::new(((self.bits >> 5) & 0x01) != 0) + } + #[doc = "Bit 4 - FMPIE1"] + #[inline(always)] + pub fn fmpie1(&self) -> FMPIE1_R { + FMPIE1_R::new(((self.bits >> 4) & 0x01) != 0) + } + #[doc = "Bit 3 - FOVIE0"] + #[inline(always)] + pub fn fovie0(&self) -> FOVIE0_R { + FOVIE0_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bit 2 - FFIE0"] + #[inline(always)] + pub fn ffie0(&self) -> FFIE0_R { + FFIE0_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 1 - FMPIE0"] + #[inline(always)] + pub fn fmpie0(&self) -> FMPIE0_R { + FMPIE0_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 0 - TMEIE"] + #[inline(always)] + pub fn tmeie(&self) -> TMEIE_R { + TMEIE_R::new((self.bits & 0x01) != 0) + } +} +impl W { + #[doc = "Bit 17 - SLKIE"] + #[inline(always)] + pub fn slkie(&mut self) -> SLKIE_W { + SLKIE_W { w: self } + } + #[doc = "Bit 16 - WKUIE"] + #[inline(always)] + pub fn wkuie(&mut self) -> WKUIE_W { + WKUIE_W { w: self } + } + #[doc = "Bit 15 - ERRIE"] + #[inline(always)] + pub fn errie(&mut self) -> ERRIE_W { + ERRIE_W { w: self } + } + #[doc = "Bit 11 - LECIE"] + #[inline(always)] + pub fn lecie(&mut self) -> LECIE_W { + LECIE_W { w: self } + } + #[doc = "Bit 10 - BOFIE"] + #[inline(always)] + pub fn bofie(&mut self) -> BOFIE_W { + BOFIE_W { w: self } + } + #[doc = "Bit 9 - EPVIE"] + #[inline(always)] + pub fn epvie(&mut self) -> EPVIE_W { + EPVIE_W { w: self } + } + #[doc = "Bit 8 - EWGIE"] + #[inline(always)] + pub fn ewgie(&mut self) -> EWGIE_W { + EWGIE_W { w: self } + } + #[doc = "Bit 6 - FOVIE1"] + #[inline(always)] + pub fn fovie1(&mut self) -> FOVIE1_W { + FOVIE1_W { w: self } + } + #[doc = "Bit 5 - FFIE1"] + #[inline(always)] + pub fn ffie1(&mut self) -> FFIE1_W { + FFIE1_W { w: self } + } + #[doc = "Bit 4 - FMPIE1"] + #[inline(always)] + pub fn fmpie1(&mut self) -> FMPIE1_W { + FMPIE1_W { w: self } + } + #[doc = "Bit 3 - FOVIE0"] + #[inline(always)] + pub fn fovie0(&mut self) -> FOVIE0_W { + FOVIE0_W { w: self } + } + #[doc = "Bit 2 - FFIE0"] + #[inline(always)] + pub fn ffie0(&mut self) -> FFIE0_W { + FFIE0_W { w: self } + } + #[doc = "Bit 1 - FMPIE0"] + #[inline(always)] + pub fn fmpie0(&mut self) -> FMPIE0_W { + FMPIE0_W { w: self } + } + #[doc = "Bit 0 - TMEIE"] + #[inline(always)] + pub fn tmeie(&mut self) -> TMEIE_W { + TMEIE_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/mcr.rs b/embassy-stm32/src/can/bx/pac/can/mcr.rs new file mode 100644 index 000000000..5e47c0901 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/mcr.rs @@ -0,0 +1,356 @@ +#[doc = "Reader of register MCR"] +pub type R = crate::R; +#[doc = "Writer for register MCR"] +pub type W = crate::W; +#[doc = "Register MCR `reset()`'s with value 0"] +impl crate::ResetValue for super::MCR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `DBF`"] +pub type DBF_R = crate::R; +#[doc = "Write proxy for field `DBF`"] +pub struct DBF_W<'a> { + w: &'a mut W, +} +impl<'a> DBF_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 16)) | (((value as u32) & 0x01) << 16); + self.w + } +} +#[doc = "Reader of field `RESET`"] +pub type RESET_R = crate::R; +#[doc = "Write proxy for field `RESET`"] +pub struct RESET_W<'a> { + w: &'a mut W, +} +impl<'a> RESET_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 15)) | (((value as u32) & 0x01) << 15); + self.w + } +} +#[doc = "Reader of field `TTCM`"] +pub type TTCM_R = crate::R; +#[doc = "Write proxy for field `TTCM`"] +pub struct TTCM_W<'a> { + w: &'a mut W, +} +impl<'a> TTCM_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); + self.w + } +} +#[doc = "Reader of field `ABOM`"] +pub type ABOM_R = crate::R; +#[doc = "Write proxy for field `ABOM`"] +pub struct ABOM_W<'a> { + w: &'a mut W, +} +impl<'a> ABOM_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); + self.w + } +} +#[doc = "Reader of field `AWUM`"] +pub type AWUM_R = crate::R; +#[doc = "Write proxy for field `AWUM`"] +pub struct AWUM_W<'a> { + w: &'a mut W, +} +impl<'a> AWUM_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); + self.w + } +} +#[doc = "Reader of field `NART`"] +pub type NART_R = crate::R; +#[doc = "Write proxy for field `NART`"] +pub struct NART_W<'a> { + w: &'a mut W, +} +impl<'a> NART_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); + self.w + } +} +#[doc = "Reader of field `RFLM`"] +pub type RFLM_R = crate::R; +#[doc = "Write proxy for field `RFLM`"] +pub struct RFLM_W<'a> { + w: &'a mut W, +} +impl<'a> RFLM_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "Reader of field `TXFP`"] +pub type TXFP_R = crate::R; +#[doc = "Write proxy for field `TXFP`"] +pub struct TXFP_W<'a> { + w: &'a mut W, +} +impl<'a> TXFP_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "Reader of field `SLEEP`"] +pub type SLEEP_R = crate::R; +#[doc = "Write proxy for field `SLEEP`"] +pub struct SLEEP_W<'a> { + w: &'a mut W, +} +impl<'a> SLEEP_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); + self.w + } +} +#[doc = "Reader of field `INRQ`"] +pub type INRQ_R = crate::R; +#[doc = "Write proxy for field `INRQ`"] +pub struct INRQ_W<'a> { + w: &'a mut W, +} +impl<'a> INRQ_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +impl R { + #[doc = "Bit 16 - DBF"] + #[inline(always)] + pub fn dbf(&self) -> DBF_R { + DBF_R::new(((self.bits >> 16) & 0x01) != 0) + } + #[doc = "Bit 15 - RESET"] + #[inline(always)] + pub fn reset(&self) -> RESET_R { + RESET_R::new(((self.bits >> 15) & 0x01) != 0) + } + #[doc = "Bit 7 - TTCM"] + #[inline(always)] + pub fn ttcm(&self) -> TTCM_R { + TTCM_R::new(((self.bits >> 7) & 0x01) != 0) + } + #[doc = "Bit 6 - ABOM"] + #[inline(always)] + pub fn abom(&self) -> ABOM_R { + ABOM_R::new(((self.bits >> 6) & 0x01) != 0) + } + #[doc = "Bit 5 - AWUM"] + #[inline(always)] + pub fn awum(&self) -> AWUM_R { + AWUM_R::new(((self.bits >> 5) & 0x01) != 0) + } + #[doc = "Bit 4 - NART"] + #[inline(always)] + pub fn nart(&self) -> NART_R { + NART_R::new(((self.bits >> 4) & 0x01) != 0) + } + #[doc = "Bit 3 - RFLM"] + #[inline(always)] + pub fn rflm(&self) -> RFLM_R { + RFLM_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bit 2 - TXFP"] + #[inline(always)] + pub fn txfp(&self) -> TXFP_R { + TXFP_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 1 - SLEEP"] + #[inline(always)] + pub fn sleep(&self) -> SLEEP_R { + SLEEP_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 0 - INRQ"] + #[inline(always)] + pub fn inrq(&self) -> INRQ_R { + INRQ_R::new((self.bits & 0x01) != 0) + } +} +impl W { + #[doc = "Bit 16 - DBF"] + #[inline(always)] + pub fn dbf(&mut self) -> DBF_W { + DBF_W { w: self } + } + #[doc = "Bit 15 - RESET"] + #[inline(always)] + pub fn reset(&mut self) -> RESET_W { + RESET_W { w: self } + } + #[doc = "Bit 7 - TTCM"] + #[inline(always)] + pub fn ttcm(&mut self) -> TTCM_W { + TTCM_W { w: self } + } + #[doc = "Bit 6 - ABOM"] + #[inline(always)] + pub fn abom(&mut self) -> ABOM_W { + ABOM_W { w: self } + } + #[doc = "Bit 5 - AWUM"] + #[inline(always)] + pub fn awum(&mut self) -> AWUM_W { + AWUM_W { w: self } + } + #[doc = "Bit 4 - NART"] + #[inline(always)] + pub fn nart(&mut self) -> NART_W { + NART_W { w: self } + } + #[doc = "Bit 3 - RFLM"] + #[inline(always)] + pub fn rflm(&mut self) -> RFLM_W { + RFLM_W { w: self } + } + #[doc = "Bit 2 - TXFP"] + #[inline(always)] + pub fn txfp(&mut self) -> TXFP_W { + TXFP_W { w: self } + } + #[doc = "Bit 1 - SLEEP"] + #[inline(always)] + pub fn sleep(&mut self) -> SLEEP_W { + SLEEP_W { w: self } + } + #[doc = "Bit 0 - INRQ"] + #[inline(always)] + pub fn inrq(&mut self) -> INRQ_W { + INRQ_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/msr.rs b/embassy-stm32/src/can/bx/pac/can/msr.rs new file mode 100644 index 000000000..18e21c844 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/msr.rs @@ -0,0 +1,160 @@ +#[doc = "Reader of register MSR"] +pub type R = crate::R; +#[doc = "Writer for register MSR"] +pub type W = crate::W; +#[doc = "Register MSR `reset()`'s with value 0"] +impl crate::ResetValue for super::MSR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `RX`"] +pub type RX_R = crate::R; +#[doc = "Reader of field `SAMP`"] +pub type SAMP_R = crate::R; +#[doc = "Reader of field `RXM`"] +pub type RXM_R = crate::R; +#[doc = "Reader of field `TXM`"] +pub type TXM_R = crate::R; +#[doc = "Reader of field `SLAKI`"] +pub type SLAKI_R = crate::R; +#[doc = "Write proxy for field `SLAKI`"] +pub struct SLAKI_W<'a> { + w: &'a mut W, +} +impl<'a> SLAKI_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); + self.w + } +} +#[doc = "Reader of field `WKUI`"] +pub type WKUI_R = crate::R; +#[doc = "Write proxy for field `WKUI`"] +pub struct WKUI_W<'a> { + w: &'a mut W, +} +impl<'a> WKUI_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "Reader of field `ERRI`"] +pub type ERRI_R = crate::R; +#[doc = "Write proxy for field `ERRI`"] +pub struct ERRI_W<'a> { + w: &'a mut W, +} +impl<'a> ERRI_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "Reader of field `SLAK`"] +pub type SLAK_R = crate::R; +#[doc = "Reader of field `INAK`"] +pub type INAK_R = crate::R; +impl R { + #[doc = "Bit 11 - RX"] + #[inline(always)] + pub fn rx(&self) -> RX_R { + RX_R::new(((self.bits >> 11) & 0x01) != 0) + } + #[doc = "Bit 10 - SAMP"] + #[inline(always)] + pub fn samp(&self) -> SAMP_R { + SAMP_R::new(((self.bits >> 10) & 0x01) != 0) + } + #[doc = "Bit 9 - RXM"] + #[inline(always)] + pub fn rxm(&self) -> RXM_R { + RXM_R::new(((self.bits >> 9) & 0x01) != 0) + } + #[doc = "Bit 8 - TXM"] + #[inline(always)] + pub fn txm(&self) -> TXM_R { + TXM_R::new(((self.bits >> 8) & 0x01) != 0) + } + #[doc = "Bit 4 - SLAKI"] + #[inline(always)] + pub fn slaki(&self) -> SLAKI_R { + SLAKI_R::new(((self.bits >> 4) & 0x01) != 0) + } + #[doc = "Bit 3 - WKUI"] + #[inline(always)] + pub fn wkui(&self) -> WKUI_R { + WKUI_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bit 2 - ERRI"] + #[inline(always)] + pub fn erri(&self) -> ERRI_R { + ERRI_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 1 - SLAK"] + #[inline(always)] + pub fn slak(&self) -> SLAK_R { + SLAK_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 0 - INAK"] + #[inline(always)] + pub fn inak(&self) -> INAK_R { + INAK_R::new((self.bits & 0x01) != 0) + } +} +impl W { + #[doc = "Bit 4 - SLAKI"] + #[inline(always)] + pub fn slaki(&mut self) -> SLAKI_W { + SLAKI_W { w: self } + } + #[doc = "Bit 3 - WKUI"] + #[inline(always)] + pub fn wkui(&mut self) -> WKUI_W { + WKUI_W { w: self } + } + #[doc = "Bit 2 - ERRI"] + #[inline(always)] + pub fn erri(&mut self) -> ERRI_W { + ERRI_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/rfr.rs b/embassy-stm32/src/can/bx/pac/can/rfr.rs new file mode 100644 index 000000000..6f5a960d1 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/rfr.rs @@ -0,0 +1,281 @@ +#[doc = "Reader of register RF%sR"] +pub type R = crate::R; +#[doc = "Writer for register RF%sR"] +pub type W = crate::W; +#[doc = "Register RF%sR `reset()`'s with value 0"] +impl crate::ResetValue for super::RFR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "RFOM0\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum RFOM_A { + #[doc = "1: Set by software to release the output mailbox of the FIFO"] + RELEASE = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: RFOM_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `RFOM`"] +pub type RFOM_R = crate::R; +impl RFOM_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> crate::Variant { + use crate::Variant::*; + match self.bits { + true => Val(RFOM_A::RELEASE), + i => Res(i), + } + } + #[doc = "Checks if the value of the field is `RELEASE`"] + #[inline(always)] + pub fn is_release(&self) -> bool { + *self == RFOM_A::RELEASE + } +} +#[doc = "Write proxy for field `RFOM`"] +pub struct RFOM_W<'a> { + w: &'a mut W, +} +impl<'a> RFOM_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: RFOM_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "Set by software to release the output mailbox of the FIFO"] + #[inline(always)] + pub fn release(self) -> &'a mut W { + self.variant(RFOM_A::RELEASE) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); + self.w + } +} +#[doc = "FOVR0\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FOVR_A { + #[doc = "0: No FIFO x overrun"] + NOOVERRUN = 0, + #[doc = "1: FIFO x overrun"] + OVERRUN = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FOVR_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `FOVR`"] +pub type FOVR_R = crate::R; +impl FOVR_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> FOVR_A { + match self.bits { + false => FOVR_A::NOOVERRUN, + true => FOVR_A::OVERRUN, + } + } + #[doc = "Checks if the value of the field is `NOOVERRUN`"] + #[inline(always)] + pub fn is_no_overrun(&self) -> bool { + *self == FOVR_A::NOOVERRUN + } + #[doc = "Checks if the value of the field is `OVERRUN`"] + #[inline(always)] + pub fn is_overrun(&self) -> bool { + *self == FOVR_A::OVERRUN + } +} +#[doc = "FOVR0\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FOVR_AW { + #[doc = "1: Clear flag"] + CLEAR = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FOVR_AW) -> Self { + variant as u8 != 0 + } +} +#[doc = "Write proxy for field `FOVR`"] +pub struct FOVR_W<'a> { + w: &'a mut W, +} +impl<'a> FOVR_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: FOVR_AW) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "Clear flag"] + #[inline(always)] + pub fn clear(self) -> &'a mut W { + self.variant(FOVR_AW::CLEAR) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); + self.w + } +} +#[doc = "FULL0\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FULL_A { + #[doc = "0: FIFO x is not full"] + NOTFULL = 0, + #[doc = "1: FIFO x is full"] + FULL = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FULL_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `FULL`"] +pub type FULL_R = crate::R; +impl FULL_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> FULL_A { + match self.bits { + false => FULL_A::NOTFULL, + true => FULL_A::FULL, + } + } + #[doc = "Checks if the value of the field is `NOTFULL`"] + #[inline(always)] + pub fn is_not_full(&self) -> bool { + *self == FULL_A::NOTFULL + } + #[doc = "Checks if the value of the field is `FULL`"] + #[inline(always)] + pub fn is_full(&self) -> bool { + *self == FULL_A::FULL + } +} +#[doc = "FULL0\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FULL_AW { + #[doc = "1: Clear flag"] + CLEAR = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: FULL_AW) -> Self { + variant as u8 != 0 + } +} +#[doc = "Write proxy for field `FULL`"] +pub struct FULL_W<'a> { + w: &'a mut W, +} +impl<'a> FULL_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: FULL_AW) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "Clear flag"] + #[inline(always)] + pub fn clear(self) -> &'a mut W { + self.variant(FULL_AW::CLEAR) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "Reader of field `FMP`"] +pub type FMP_R = crate::R; +impl R { + #[doc = "Bit 5 - RFOM0"] + #[inline(always)] + pub fn rfom(&self) -> RFOM_R { + RFOM_R::new(((self.bits >> 5) & 0x01) != 0) + } + #[doc = "Bit 4 - FOVR0"] + #[inline(always)] + pub fn fovr(&self) -> FOVR_R { + FOVR_R::new(((self.bits >> 4) & 0x01) != 0) + } + #[doc = "Bit 3 - FULL0"] + #[inline(always)] + pub fn full(&self) -> FULL_R { + FULL_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bits 0:1 - FMP0"] + #[inline(always)] + pub fn fmp(&self) -> FMP_R { + FMP_R::new((self.bits & 0x03) as u8) + } +} +impl W { + #[doc = "Bit 5 - RFOM0"] + #[inline(always)] + pub fn rfom(&mut self) -> RFOM_W { + RFOM_W { w: self } + } + #[doc = "Bit 4 - FOVR0"] + #[inline(always)] + pub fn fovr(&mut self) -> FOVR_W { + FOVR_W { w: self } + } + #[doc = "Bit 3 - FULL0"] + #[inline(always)] + pub fn full(&mut self) -> FULL_W { + FULL_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/rx.rs b/embassy-stm32/src/can/bx/pac/can/rx.rs new file mode 100644 index 000000000..dba344e7c --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/rx.rs @@ -0,0 +1,36 @@ +#[doc = "CAN_RI0R\n\nThis register you can [`read`](crate::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rir](rir) module"] +pub type RIR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _RIR; +#[doc = "`read()` method returns [rir::R](rir::R) reader structure"] +impl crate::Readable for RIR {} +#[doc = "CAN_RI0R"] +pub mod rir; +#[doc = "CAN_RDT0R\n\nThis register you can [`read`](crate::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdtr](rdtr) module"] +pub type RDTR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _RDTR; +#[doc = "`read()` method returns [rdtr::R](rdtr::R) reader structure"] +impl crate::Readable for RDTR {} +#[doc = "CAN_RDT0R"] +pub mod rdtr; +#[doc = "CAN_RDL0R\n\nThis register you can [`read`](crate::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdlr](rdlr) module"] +pub type RDLR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _RDLR; +#[doc = "`read()` method returns [rdlr::R](rdlr::R) reader structure"] +impl crate::Readable for RDLR {} +#[doc = "CAN_RDL0R"] +pub mod rdlr; +#[doc = "CAN_RDH0R\n\nThis register you can [`read`](crate::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdhr](rdhr) module"] +pub type RDHR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _RDHR; +#[doc = "`read()` method returns [rdhr::R](rdhr::R) reader structure"] +impl crate::Readable for RDHR {} +#[doc = "CAN_RDH0R"] +pub mod rdhr; diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs new file mode 100644 index 000000000..a0e6a52d0 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs @@ -0,0 +1,32 @@ +#[doc = "Reader of register RDHR"] +pub type R = crate::R; +#[doc = "Reader of field `DATA7`"] +pub type DATA7_R = crate::R; +#[doc = "Reader of field `DATA6`"] +pub type DATA6_R = crate::R; +#[doc = "Reader of field `DATA5`"] +pub type DATA5_R = crate::R; +#[doc = "Reader of field `DATA4`"] +pub type DATA4_R = crate::R; +impl R { + #[doc = "Bits 24:31 - DATA7"] + #[inline(always)] + pub fn data7(&self) -> DATA7_R { + DATA7_R::new(((self.bits >> 24) & 0xff) as u8) + } + #[doc = "Bits 16:23 - DATA6"] + #[inline(always)] + pub fn data6(&self) -> DATA6_R { + DATA6_R::new(((self.bits >> 16) & 0xff) as u8) + } + #[doc = "Bits 8:15 - DATA5"] + #[inline(always)] + pub fn data5(&self) -> DATA5_R { + DATA5_R::new(((self.bits >> 8) & 0xff) as u8) + } + #[doc = "Bits 0:7 - DATA4"] + #[inline(always)] + pub fn data4(&self) -> DATA4_R { + DATA4_R::new((self.bits & 0xff) as u8) + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs new file mode 100644 index 000000000..e61746669 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs @@ -0,0 +1,32 @@ +#[doc = "Reader of register RDLR"] +pub type R = crate::R; +#[doc = "Reader of field `DATA3`"] +pub type DATA3_R = crate::R; +#[doc = "Reader of field `DATA2`"] +pub type DATA2_R = crate::R; +#[doc = "Reader of field `DATA1`"] +pub type DATA1_R = crate::R; +#[doc = "Reader of field `DATA0`"] +pub type DATA0_R = crate::R; +impl R { + #[doc = "Bits 24:31 - DATA3"] + #[inline(always)] + pub fn data3(&self) -> DATA3_R { + DATA3_R::new(((self.bits >> 24) & 0xff) as u8) + } + #[doc = "Bits 16:23 - DATA2"] + #[inline(always)] + pub fn data2(&self) -> DATA2_R { + DATA2_R::new(((self.bits >> 16) & 0xff) as u8) + } + #[doc = "Bits 8:15 - DATA1"] + #[inline(always)] + pub fn data1(&self) -> DATA1_R { + DATA1_R::new(((self.bits >> 8) & 0xff) as u8) + } + #[doc = "Bits 0:7 - DATA0"] + #[inline(always)] + pub fn data0(&self) -> DATA0_R { + DATA0_R::new((self.bits & 0xff) as u8) + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs new file mode 100644 index 000000000..6778a7b4a --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs @@ -0,0 +1,25 @@ +#[doc = "Reader of register RDTR"] +pub type R = crate::R; +#[doc = "Reader of field `TIME`"] +pub type TIME_R = crate::R; +#[doc = "Reader of field `FMI`"] +pub type FMI_R = crate::R; +#[doc = "Reader of field `DLC`"] +pub type DLC_R = crate::R; +impl R { + #[doc = "Bits 16:31 - TIME"] + #[inline(always)] + pub fn time(&self) -> TIME_R { + TIME_R::new(((self.bits >> 16) & 0xffff) as u16) + } + #[doc = "Bits 8:15 - FMI"] + #[inline(always)] + pub fn fmi(&self) -> FMI_R { + FMI_R::new(((self.bits >> 8) & 0xff) as u8) + } + #[doc = "Bits 0:3 - DLC"] + #[inline(always)] + pub fn dlc(&self) -> DLC_R { + DLC_R::new((self.bits & 0x0f) as u8) + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rir.rs b/embassy-stm32/src/can/bx/pac/can/rx/rir.rs new file mode 100644 index 000000000..c0e4248f4 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/rx/rir.rs @@ -0,0 +1,100 @@ +#[doc = "Reader of register RIR"] +pub type R = crate::R; +#[doc = "Reader of field `STID`"] +pub type STID_R = crate::R; +#[doc = "Reader of field `EXID`"] +pub type EXID_R = crate::R; +#[doc = "IDE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum IDE_A { + #[doc = "0: Standard identifier"] + STANDARD = 0, + #[doc = "1: Extended identifier"] + EXTENDED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: IDE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `IDE`"] +pub type IDE_R = crate::R; +impl IDE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> IDE_A { + match self.bits { + false => IDE_A::STANDARD, + true => IDE_A::EXTENDED, + } + } + #[doc = "Checks if the value of the field is `STANDARD`"] + #[inline(always)] + pub fn is_standard(&self) -> bool { + *self == IDE_A::STANDARD + } + #[doc = "Checks if the value of the field is `EXTENDED`"] + #[inline(always)] + pub fn is_extended(&self) -> bool { + *self == IDE_A::EXTENDED + } +} +#[doc = "RTR\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum RTR_A { + #[doc = "0: Data frame"] + DATA = 0, + #[doc = "1: Remote frame"] + REMOTE = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: RTR_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `RTR`"] +pub type RTR_R = crate::R; +impl RTR_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> RTR_A { + match self.bits { + false => RTR_A::DATA, + true => RTR_A::REMOTE, + } + } + #[doc = "Checks if the value of the field is `DATA`"] + #[inline(always)] + pub fn is_data(&self) -> bool { + *self == RTR_A::DATA + } + #[doc = "Checks if the value of the field is `REMOTE`"] + #[inline(always)] + pub fn is_remote(&self) -> bool { + *self == RTR_A::REMOTE + } +} +impl R { + #[doc = "Bits 21:31 - STID"] + #[inline(always)] + pub fn stid(&self) -> STID_R { + STID_R::new(((self.bits >> 21) & 0x07ff) as u16) + } + #[doc = "Bits 3:20 - EXID"] + #[inline(always)] + pub fn exid(&self) -> EXID_R { + EXID_R::new(((self.bits >> 3) & 0x0003_ffff) as u32) + } + #[doc = "Bit 2 - IDE"] + #[inline(always)] + pub fn ide(&self) -> IDE_R { + IDE_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 1 - RTR"] + #[inline(always)] + pub fn rtr(&self) -> RTR_R { + RTR_R::new(((self.bits >> 1) & 0x01) != 0) + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/tsr.rs b/embassy-stm32/src/can/bx/pac/can/tsr.rs new file mode 100644 index 000000000..2527b36a5 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/tsr.rs @@ -0,0 +1,575 @@ +#[doc = "Reader of register TSR"] +pub type R = crate::R; +#[doc = "Writer for register TSR"] +pub type W = crate::W; +#[doc = "Register TSR `reset()`'s with value 0"] +impl crate::ResetValue for super::TSR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `LOW2`"] +pub type LOW2_R = crate::R; +#[doc = "Reader of field `LOW1`"] +pub type LOW1_R = crate::R; +#[doc = "Reader of field `LOW0`"] +pub type LOW0_R = crate::R; +#[doc = "Reader of field `TME2`"] +pub type TME2_R = crate::R; +#[doc = "Reader of field `TME1`"] +pub type TME1_R = crate::R; +#[doc = "Reader of field `TME0`"] +pub type TME0_R = crate::R; +#[doc = "Reader of field `CODE`"] +pub type CODE_R = crate::R; +#[doc = "Reader of field `ABRQ2`"] +pub type ABRQ2_R = crate::R; +#[doc = "Write proxy for field `ABRQ2`"] +pub struct ABRQ2_W<'a> { + w: &'a mut W, +} +impl<'a> ABRQ2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 23)) | (((value as u32) & 0x01) << 23); + self.w + } +} +#[doc = "Reader of field `TERR2`"] +pub type TERR2_R = crate::R; +#[doc = "Write proxy for field `TERR2`"] +pub struct TERR2_W<'a> { + w: &'a mut W, +} +impl<'a> TERR2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 19)) | (((value as u32) & 0x01) << 19); + self.w + } +} +#[doc = "Reader of field `ALST2`"] +pub type ALST2_R = crate::R; +#[doc = "Write proxy for field `ALST2`"] +pub struct ALST2_W<'a> { + w: &'a mut W, +} +impl<'a> ALST2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 18)) | (((value as u32) & 0x01) << 18); + self.w + } +} +#[doc = "Reader of field `TXOK2`"] +pub type TXOK2_R = crate::R; +#[doc = "Write proxy for field `TXOK2`"] +pub struct TXOK2_W<'a> { + w: &'a mut W, +} +impl<'a> TXOK2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 17)) | (((value as u32) & 0x01) << 17); + self.w + } +} +#[doc = "Reader of field `RQCP2`"] +pub type RQCP2_R = crate::R; +#[doc = "Write proxy for field `RQCP2`"] +pub struct RQCP2_W<'a> { + w: &'a mut W, +} +impl<'a> RQCP2_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 16)) | (((value as u32) & 0x01) << 16); + self.w + } +} +#[doc = "Reader of field `ABRQ1`"] +pub type ABRQ1_R = crate::R; +#[doc = "Write proxy for field `ABRQ1`"] +pub struct ABRQ1_W<'a> { + w: &'a mut W, +} +impl<'a> ABRQ1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 15)) | (((value as u32) & 0x01) << 15); + self.w + } +} +#[doc = "Reader of field `TERR1`"] +pub type TERR1_R = crate::R; +#[doc = "Write proxy for field `TERR1`"] +pub struct TERR1_W<'a> { + w: &'a mut W, +} +impl<'a> TERR1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); + self.w + } +} +#[doc = "Reader of field `ALST1`"] +pub type ALST1_R = crate::R; +#[doc = "Write proxy for field `ALST1`"] +pub struct ALST1_W<'a> { + w: &'a mut W, +} +impl<'a> ALST1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); + self.w + } +} +#[doc = "Reader of field `TXOK1`"] +pub type TXOK1_R = crate::R; +#[doc = "Write proxy for field `TXOK1`"] +pub struct TXOK1_W<'a> { + w: &'a mut W, +} +impl<'a> TXOK1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); + self.w + } +} +#[doc = "Reader of field `RQCP1`"] +pub type RQCP1_R = crate::R; +#[doc = "Write proxy for field `RQCP1`"] +pub struct RQCP1_W<'a> { + w: &'a mut W, +} +impl<'a> RQCP1_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); + self.w + } +} +#[doc = "Reader of field `ABRQ0`"] +pub type ABRQ0_R = crate::R; +#[doc = "Write proxy for field `ABRQ0`"] +pub struct ABRQ0_W<'a> { + w: &'a mut W, +} +impl<'a> ABRQ0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); + self.w + } +} +#[doc = "Reader of field `TERR0`"] +pub type TERR0_R = crate::R; +#[doc = "Write proxy for field `TERR0`"] +pub struct TERR0_W<'a> { + w: &'a mut W, +} +impl<'a> TERR0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); + self.w + } +} +#[doc = "Reader of field `ALST0`"] +pub type ALST0_R = crate::R; +#[doc = "Write proxy for field `ALST0`"] +pub struct ALST0_W<'a> { + w: &'a mut W, +} +impl<'a> ALST0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "Reader of field `TXOK0`"] +pub type TXOK0_R = crate::R; +#[doc = "Write proxy for field `TXOK0`"] +pub struct TXOK0_W<'a> { + w: &'a mut W, +} +impl<'a> TXOK0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); + self.w + } +} +#[doc = "Reader of field `RQCP0`"] +pub type RQCP0_R = crate::R; +#[doc = "Write proxy for field `RQCP0`"] +pub struct RQCP0_W<'a> { + w: &'a mut W, +} +impl<'a> RQCP0_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +impl R { + #[doc = "Bit 31 - Lowest priority flag for mailbox 2"] + #[inline(always)] + pub fn low2(&self) -> LOW2_R { + LOW2_R::new(((self.bits >> 31) & 0x01) != 0) + } + #[doc = "Bit 30 - Lowest priority flag for mailbox 1"] + #[inline(always)] + pub fn low1(&self) -> LOW1_R { + LOW1_R::new(((self.bits >> 30) & 0x01) != 0) + } + #[doc = "Bit 29 - Lowest priority flag for mailbox 0"] + #[inline(always)] + pub fn low0(&self) -> LOW0_R { + LOW0_R::new(((self.bits >> 29) & 0x01) != 0) + } + #[doc = "Bit 28 - Lowest priority flag for mailbox 2"] + #[inline(always)] + pub fn tme2(&self) -> TME2_R { + TME2_R::new(((self.bits >> 28) & 0x01) != 0) + } + #[doc = "Bit 27 - Lowest priority flag for mailbox 1"] + #[inline(always)] + pub fn tme1(&self) -> TME1_R { + TME1_R::new(((self.bits >> 27) & 0x01) != 0) + } + #[doc = "Bit 26 - Lowest priority flag for mailbox 0"] + #[inline(always)] + pub fn tme0(&self) -> TME0_R { + TME0_R::new(((self.bits >> 26) & 0x01) != 0) + } + #[doc = "Bits 24:25 - CODE"] + #[inline(always)] + pub fn code(&self) -> CODE_R { + CODE_R::new(((self.bits >> 24) & 0x03) as u8) + } + #[doc = "Bit 23 - ABRQ2"] + #[inline(always)] + pub fn abrq2(&self) -> ABRQ2_R { + ABRQ2_R::new(((self.bits >> 23) & 0x01) != 0) + } + #[doc = "Bit 19 - TERR2"] + #[inline(always)] + pub fn terr2(&self) -> TERR2_R { + TERR2_R::new(((self.bits >> 19) & 0x01) != 0) + } + #[doc = "Bit 18 - ALST2"] + #[inline(always)] + pub fn alst2(&self) -> ALST2_R { + ALST2_R::new(((self.bits >> 18) & 0x01) != 0) + } + #[doc = "Bit 17 - TXOK2"] + #[inline(always)] + pub fn txok2(&self) -> TXOK2_R { + TXOK2_R::new(((self.bits >> 17) & 0x01) != 0) + } + #[doc = "Bit 16 - RQCP2"] + #[inline(always)] + pub fn rqcp2(&self) -> RQCP2_R { + RQCP2_R::new(((self.bits >> 16) & 0x01) != 0) + } + #[doc = "Bit 15 - ABRQ1"] + #[inline(always)] + pub fn abrq1(&self) -> ABRQ1_R { + ABRQ1_R::new(((self.bits >> 15) & 0x01) != 0) + } + #[doc = "Bit 11 - TERR1"] + #[inline(always)] + pub fn terr1(&self) -> TERR1_R { + TERR1_R::new(((self.bits >> 11) & 0x01) != 0) + } + #[doc = "Bit 10 - ALST1"] + #[inline(always)] + pub fn alst1(&self) -> ALST1_R { + ALST1_R::new(((self.bits >> 10) & 0x01) != 0) + } + #[doc = "Bit 9 - TXOK1"] + #[inline(always)] + pub fn txok1(&self) -> TXOK1_R { + TXOK1_R::new(((self.bits >> 9) & 0x01) != 0) + } + #[doc = "Bit 8 - RQCP1"] + #[inline(always)] + pub fn rqcp1(&self) -> RQCP1_R { + RQCP1_R::new(((self.bits >> 8) & 0x01) != 0) + } + #[doc = "Bit 7 - ABRQ0"] + #[inline(always)] + pub fn abrq0(&self) -> ABRQ0_R { + ABRQ0_R::new(((self.bits >> 7) & 0x01) != 0) + } + #[doc = "Bit 3 - TERR0"] + #[inline(always)] + pub fn terr0(&self) -> TERR0_R { + TERR0_R::new(((self.bits >> 3) & 0x01) != 0) + } + #[doc = "Bit 2 - ALST0"] + #[inline(always)] + pub fn alst0(&self) -> ALST0_R { + ALST0_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 1 - TXOK0"] + #[inline(always)] + pub fn txok0(&self) -> TXOK0_R { + TXOK0_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 0 - RQCP0"] + #[inline(always)] + pub fn rqcp0(&self) -> RQCP0_R { + RQCP0_R::new((self.bits & 0x01) != 0) + } +} +impl W { + #[doc = "Bit 23 - ABRQ2"] + #[inline(always)] + pub fn abrq2(&mut self) -> ABRQ2_W { + ABRQ2_W { w: self } + } + #[doc = "Bit 19 - TERR2"] + #[inline(always)] + pub fn terr2(&mut self) -> TERR2_W { + TERR2_W { w: self } + } + #[doc = "Bit 18 - ALST2"] + #[inline(always)] + pub fn alst2(&mut self) -> ALST2_W { + ALST2_W { w: self } + } + #[doc = "Bit 17 - TXOK2"] + #[inline(always)] + pub fn txok2(&mut self) -> TXOK2_W { + TXOK2_W { w: self } + } + #[doc = "Bit 16 - RQCP2"] + #[inline(always)] + pub fn rqcp2(&mut self) -> RQCP2_W { + RQCP2_W { w: self } + } + #[doc = "Bit 15 - ABRQ1"] + #[inline(always)] + pub fn abrq1(&mut self) -> ABRQ1_W { + ABRQ1_W { w: self } + } + #[doc = "Bit 11 - TERR1"] + #[inline(always)] + pub fn terr1(&mut self) -> TERR1_W { + TERR1_W { w: self } + } + #[doc = "Bit 10 - ALST1"] + #[inline(always)] + pub fn alst1(&mut self) -> ALST1_W { + ALST1_W { w: self } + } + #[doc = "Bit 9 - TXOK1"] + #[inline(always)] + pub fn txok1(&mut self) -> TXOK1_W { + TXOK1_W { w: self } + } + #[doc = "Bit 8 - RQCP1"] + #[inline(always)] + pub fn rqcp1(&mut self) -> RQCP1_W { + RQCP1_W { w: self } + } + #[doc = "Bit 7 - ABRQ0"] + #[inline(always)] + pub fn abrq0(&mut self) -> ABRQ0_W { + ABRQ0_W { w: self } + } + #[doc = "Bit 3 - TERR0"] + #[inline(always)] + pub fn terr0(&mut self) -> TERR0_W { + TERR0_W { w: self } + } + #[doc = "Bit 2 - ALST0"] + #[inline(always)] + pub fn alst0(&mut self) -> ALST0_W { + ALST0_W { w: self } + } + #[doc = "Bit 1 - TXOK0"] + #[inline(always)] + pub fn txok0(&mut self) -> TXOK0_W { + TXOK0_W { w: self } + } + #[doc = "Bit 0 - RQCP0"] + #[inline(always)] + pub fn rqcp0(&mut self) -> RQCP0_W { + RQCP0_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/tx.rs b/embassy-stm32/src/can/bx/pac/can/tx.rs new file mode 100644 index 000000000..7b926bd14 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/tx.rs @@ -0,0 +1,44 @@ +#[doc = "CAN_TI0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tir](tir) module"] +pub type TIR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _TIR; +#[doc = "`read()` method returns [tir::R](tir::R) reader structure"] +impl crate::Readable for TIR {} +#[doc = "`write(|w| ..)` method takes [tir::W](tir::W) writer structure"] +impl crate::Writable for TIR {} +#[doc = "CAN_TI0R"] +pub mod tir; +#[doc = "CAN_TDT0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdtr](tdtr) module"] +pub type TDTR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _TDTR; +#[doc = "`read()` method returns [tdtr::R](tdtr::R) reader structure"] +impl crate::Readable for TDTR {} +#[doc = "`write(|w| ..)` method takes [tdtr::W](tdtr::W) writer structure"] +impl crate::Writable for TDTR {} +#[doc = "CAN_TDT0R"] +pub mod tdtr; +#[doc = "CAN_TDL0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdlr](tdlr) module"] +pub type TDLR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _TDLR; +#[doc = "`read()` method returns [tdlr::R](tdlr::R) reader structure"] +impl crate::Readable for TDLR {} +#[doc = "`write(|w| ..)` method takes [tdlr::W](tdlr::W) writer structure"] +impl crate::Writable for TDLR {} +#[doc = "CAN_TDL0R"] +pub mod tdlr; +#[doc = "CAN_TDH0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdhr](tdhr) module"] +pub type TDHR = crate::Reg; +#[allow(missing_docs)] +#[doc(hidden)] +pub struct _TDHR; +#[doc = "`read()` method returns [tdhr::R](tdhr::R) reader structure"] +impl crate::Readable for TDHR {} +#[doc = "`write(|w| ..)` method takes [tdhr::W](tdhr::W) writer structure"] +impl crate::Writable for TDHR {} +#[doc = "CAN_TDH0R"] +pub mod tdhr; diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs new file mode 100644 index 000000000..240fa94f0 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs @@ -0,0 +1,112 @@ +#[doc = "Reader of register TDHR"] +pub type R = crate::R; +#[doc = "Writer for register TDHR"] +pub type W = crate::W; +#[doc = "Register TDHR `reset()`'s with value 0"] +impl crate::ResetValue for super::TDHR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `DATA7`"] +pub type DATA7_R = crate::R; +#[doc = "Write proxy for field `DATA7`"] +pub struct DATA7_W<'a> { + w: &'a mut W, +} +impl<'a> DATA7_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0xff << 24)) | (((value as u32) & 0xff) << 24); + self.w + } +} +#[doc = "Reader of field `DATA6`"] +pub type DATA6_R = crate::R; +#[doc = "Write proxy for field `DATA6`"] +pub struct DATA6_W<'a> { + w: &'a mut W, +} +impl<'a> DATA6_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0xff << 16)) | (((value as u32) & 0xff) << 16); + self.w + } +} +#[doc = "Reader of field `DATA5`"] +pub type DATA5_R = crate::R; +#[doc = "Write proxy for field `DATA5`"] +pub struct DATA5_W<'a> { + w: &'a mut W, +} +impl<'a> DATA5_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0xff << 8)) | (((value as u32) & 0xff) << 8); + self.w + } +} +#[doc = "Reader of field `DATA4`"] +pub type DATA4_R = crate::R; +#[doc = "Write proxy for field `DATA4`"] +pub struct DATA4_W<'a> { + w: &'a mut W, +} +impl<'a> DATA4_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !0xff) | ((value as u32) & 0xff); + self.w + } +} +impl R { + #[doc = "Bits 24:31 - DATA7"] + #[inline(always)] + pub fn data7(&self) -> DATA7_R { + DATA7_R::new(((self.bits >> 24) & 0xff) as u8) + } + #[doc = "Bits 16:23 - DATA6"] + #[inline(always)] + pub fn data6(&self) -> DATA6_R { + DATA6_R::new(((self.bits >> 16) & 0xff) as u8) + } + #[doc = "Bits 8:15 - DATA5"] + #[inline(always)] + pub fn data5(&self) -> DATA5_R { + DATA5_R::new(((self.bits >> 8) & 0xff) as u8) + } + #[doc = "Bits 0:7 - DATA4"] + #[inline(always)] + pub fn data4(&self) -> DATA4_R { + DATA4_R::new((self.bits & 0xff) as u8) + } +} +impl W { + #[doc = "Bits 24:31 - DATA7"] + #[inline(always)] + pub fn data7(&mut self) -> DATA7_W { + DATA7_W { w: self } + } + #[doc = "Bits 16:23 - DATA6"] + #[inline(always)] + pub fn data6(&mut self) -> DATA6_W { + DATA6_W { w: self } + } + #[doc = "Bits 8:15 - DATA5"] + #[inline(always)] + pub fn data5(&mut self) -> DATA5_W { + DATA5_W { w: self } + } + #[doc = "Bits 0:7 - DATA4"] + #[inline(always)] + pub fn data4(&mut self) -> DATA4_W { + DATA4_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs new file mode 100644 index 000000000..c4c855d46 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs @@ -0,0 +1,112 @@ +#[doc = "Reader of register TDLR"] +pub type R = crate::R; +#[doc = "Writer for register TDLR"] +pub type W = crate::W; +#[doc = "Register TDLR `reset()`'s with value 0"] +impl crate::ResetValue for super::TDLR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `DATA3`"] +pub type DATA3_R = crate::R; +#[doc = "Write proxy for field `DATA3`"] +pub struct DATA3_W<'a> { + w: &'a mut W, +} +impl<'a> DATA3_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0xff << 24)) | (((value as u32) & 0xff) << 24); + self.w + } +} +#[doc = "Reader of field `DATA2`"] +pub type DATA2_R = crate::R; +#[doc = "Write proxy for field `DATA2`"] +pub struct DATA2_W<'a> { + w: &'a mut W, +} +impl<'a> DATA2_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0xff << 16)) | (((value as u32) & 0xff) << 16); + self.w + } +} +#[doc = "Reader of field `DATA1`"] +pub type DATA1_R = crate::R; +#[doc = "Write proxy for field `DATA1`"] +pub struct DATA1_W<'a> { + w: &'a mut W, +} +impl<'a> DATA1_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !(0xff << 8)) | (((value as u32) & 0xff) << 8); + self.w + } +} +#[doc = "Reader of field `DATA0`"] +pub type DATA0_R = crate::R; +#[doc = "Write proxy for field `DATA0`"] +pub struct DATA0_W<'a> { + w: &'a mut W, +} +impl<'a> DATA0_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !0xff) | ((value as u32) & 0xff); + self.w + } +} +impl R { + #[doc = "Bits 24:31 - DATA3"] + #[inline(always)] + pub fn data3(&self) -> DATA3_R { + DATA3_R::new(((self.bits >> 24) & 0xff) as u8) + } + #[doc = "Bits 16:23 - DATA2"] + #[inline(always)] + pub fn data2(&self) -> DATA2_R { + DATA2_R::new(((self.bits >> 16) & 0xff) as u8) + } + #[doc = "Bits 8:15 - DATA1"] + #[inline(always)] + pub fn data1(&self) -> DATA1_R { + DATA1_R::new(((self.bits >> 8) & 0xff) as u8) + } + #[doc = "Bits 0:7 - DATA0"] + #[inline(always)] + pub fn data0(&self) -> DATA0_R { + DATA0_R::new((self.bits & 0xff) as u8) + } +} +impl W { + #[doc = "Bits 24:31 - DATA3"] + #[inline(always)] + pub fn data3(&mut self) -> DATA3_W { + DATA3_W { w: self } + } + #[doc = "Bits 16:23 - DATA2"] + #[inline(always)] + pub fn data2(&mut self) -> DATA2_W { + DATA2_W { w: self } + } + #[doc = "Bits 8:15 - DATA1"] + #[inline(always)] + pub fn data1(&mut self) -> DATA1_W { + DATA1_W { w: self } + } + #[doc = "Bits 0:7 - DATA0"] + #[inline(always)] + pub fn data0(&mut self) -> DATA0_W { + DATA0_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs new file mode 100644 index 000000000..310bca497 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs @@ -0,0 +1,98 @@ +#[doc = "Reader of register TDTR"] +pub type R = crate::R; +#[doc = "Writer for register TDTR"] +pub type W = crate::W; +#[doc = "Register TDTR `reset()`'s with value 0"] +impl crate::ResetValue for super::TDTR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `TIME`"] +pub type TIME_R = crate::R; +#[doc = "Write proxy for field `TIME`"] +pub struct TIME_W<'a> { + w: &'a mut W, +} +impl<'a> TIME_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u16) -> &'a mut W { + self.w.bits = (self.w.bits & !(0xffff << 16)) | (((value as u32) & 0xffff) << 16); + self.w + } +} +#[doc = "Reader of field `TGT`"] +pub type TGT_R = crate::R; +#[doc = "Write proxy for field `TGT`"] +pub struct TGT_W<'a> { + w: &'a mut W, +} +impl<'a> TGT_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); + self.w + } +} +#[doc = "Reader of field `DLC`"] +pub type DLC_R = crate::R; +#[doc = "Write proxy for field `DLC`"] +pub struct DLC_W<'a> { + w: &'a mut W, +} +impl<'a> DLC_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u8) -> &'a mut W { + self.w.bits = (self.w.bits & !0x0f) | ((value as u32) & 0x0f); + self.w + } +} +impl R { + #[doc = "Bits 16:31 - TIME"] + #[inline(always)] + pub fn time(&self) -> TIME_R { + TIME_R::new(((self.bits >> 16) & 0xffff) as u16) + } + #[doc = "Bit 8 - TGT"] + #[inline(always)] + pub fn tgt(&self) -> TGT_R { + TGT_R::new(((self.bits >> 8) & 0x01) != 0) + } + #[doc = "Bits 0:3 - DLC"] + #[inline(always)] + pub fn dlc(&self) -> DLC_R { + DLC_R::new((self.bits & 0x0f) as u8) + } +} +impl W { + #[doc = "Bits 16:31 - TIME"] + #[inline(always)] + pub fn time(&mut self) -> TIME_W { + TIME_W { w: self } + } + #[doc = "Bit 8 - TGT"] + #[inline(always)] + pub fn tgt(&mut self) -> TGT_W { + TGT_W { w: self } + } + #[doc = "Bits 0:3 - DLC"] + #[inline(always)] + pub fn dlc(&mut self) -> DLC_W { + DLC_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tir.rs b/embassy-stm32/src/can/bx/pac/can/tx/tir.rs new file mode 100644 index 000000000..12bc3d1f3 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/can/tx/tir.rs @@ -0,0 +1,268 @@ +#[doc = "Reader of register TIR"] +pub type R = crate::R; +#[doc = "Writer for register TIR"] +pub type W = crate::W; +#[doc = "Register TIR `reset()`'s with value 0"] +impl crate::ResetValue for super::TIR { + type Type = u32; + #[inline(always)] + fn reset_value() -> Self::Type { + 0 + } +} +#[doc = "Reader of field `STID`"] +pub type STID_R = crate::R; +#[doc = "Write proxy for field `STID`"] +pub struct STID_W<'a> { + w: &'a mut W, +} +impl<'a> STID_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u16) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x07ff << 21)) | (((value as u32) & 0x07ff) << 21); + self.w + } +} +#[doc = "Reader of field `EXID`"] +pub type EXID_R = crate::R; +#[doc = "Write proxy for field `EXID`"] +pub struct EXID_W<'a> { + w: &'a mut W, +} +impl<'a> EXID_W<'a> { + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub unsafe fn bits(self, value: u32) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x0003_ffff << 3)) | (((value as u32) & 0x0003_ffff) << 3); + self.w + } +} +#[doc = "IDE\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum IDE_A { + #[doc = "0: Standard identifier"] + STANDARD = 0, + #[doc = "1: Extended identifier"] + EXTENDED = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: IDE_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `IDE`"] +pub type IDE_R = crate::R; +impl IDE_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> IDE_A { + match self.bits { + false => IDE_A::STANDARD, + true => IDE_A::EXTENDED, + } + } + #[doc = "Checks if the value of the field is `STANDARD`"] + #[inline(always)] + pub fn is_standard(&self) -> bool { + *self == IDE_A::STANDARD + } + #[doc = "Checks if the value of the field is `EXTENDED`"] + #[inline(always)] + pub fn is_extended(&self) -> bool { + *self == IDE_A::EXTENDED + } +} +#[doc = "Write proxy for field `IDE`"] +pub struct IDE_W<'a> { + w: &'a mut W, +} +impl<'a> IDE_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: IDE_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "Standard identifier"] + #[inline(always)] + pub fn standard(self) -> &'a mut W { + self.variant(IDE_A::STANDARD) + } + #[doc = "Extended identifier"] + #[inline(always)] + pub fn extended(self) -> &'a mut W { + self.variant(IDE_A::EXTENDED) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); + self.w + } +} +#[doc = "RTR\n\nValue on reset: 0"] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum RTR_A { + #[doc = "0: Data frame"] + DATA = 0, + #[doc = "1: Remote frame"] + REMOTE = 1, +} +impl From for bool { + #[inline(always)] + fn from(variant: RTR_A) -> Self { + variant as u8 != 0 + } +} +#[doc = "Reader of field `RTR`"] +pub type RTR_R = crate::R; +impl RTR_R { + #[doc = r"Get enumerated values variant"] + #[inline(always)] + pub fn variant(&self) -> RTR_A { + match self.bits { + false => RTR_A::DATA, + true => RTR_A::REMOTE, + } + } + #[doc = "Checks if the value of the field is `DATA`"] + #[inline(always)] + pub fn is_data(&self) -> bool { + *self == RTR_A::DATA + } + #[doc = "Checks if the value of the field is `REMOTE`"] + #[inline(always)] + pub fn is_remote(&self) -> bool { + *self == RTR_A::REMOTE + } +} +#[doc = "Write proxy for field `RTR`"] +pub struct RTR_W<'a> { + w: &'a mut W, +} +impl<'a> RTR_W<'a> { + #[doc = r"Writes `variant` to the field"] + #[inline(always)] + pub fn variant(self, variant: RTR_A) -> &'a mut W { + { + self.bit(variant.into()) + } + } + #[doc = "Data frame"] + #[inline(always)] + pub fn data(self) -> &'a mut W { + self.variant(RTR_A::DATA) + } + #[doc = "Remote frame"] + #[inline(always)] + pub fn remote(self) -> &'a mut W { + self.variant(RTR_A::REMOTE) + } + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); + self.w + } +} +#[doc = "Reader of field `TXRQ`"] +pub type TXRQ_R = crate::R; +#[doc = "Write proxy for field `TXRQ`"] +pub struct TXRQ_W<'a> { + w: &'a mut W, +} +impl<'a> TXRQ_W<'a> { + #[doc = r"Sets the field bit"] + #[inline(always)] + pub fn set_bit(self) -> &'a mut W { + self.bit(true) + } + #[doc = r"Clears the field bit"] + #[inline(always)] + pub fn clear_bit(self) -> &'a mut W { + self.bit(false) + } + #[doc = r"Writes raw bits to the field"] + #[inline(always)] + pub fn bit(self, value: bool) -> &'a mut W { + self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); + self.w + } +} +impl R { + #[doc = "Bits 21:31 - STID"] + #[inline(always)] + pub fn stid(&self) -> STID_R { + STID_R::new(((self.bits >> 21) & 0x07ff) as u16) + } + #[doc = "Bits 3:20 - EXID"] + #[inline(always)] + pub fn exid(&self) -> EXID_R { + EXID_R::new(((self.bits >> 3) & 0x0003_ffff) as u32) + } + #[doc = "Bit 2 - IDE"] + #[inline(always)] + pub fn ide(&self) -> IDE_R { + IDE_R::new(((self.bits >> 2) & 0x01) != 0) + } + #[doc = "Bit 1 - RTR"] + #[inline(always)] + pub fn rtr(&self) -> RTR_R { + RTR_R::new(((self.bits >> 1) & 0x01) != 0) + } + #[doc = "Bit 0 - TXRQ"] + #[inline(always)] + pub fn txrq(&self) -> TXRQ_R { + TXRQ_R::new((self.bits & 0x01) != 0) + } +} +impl W { + #[doc = "Bits 21:31 - STID"] + #[inline(always)] + pub fn stid(&mut self) -> STID_W { + STID_W { w: self } + } + #[doc = "Bits 3:20 - EXID"] + #[inline(always)] + pub fn exid(&mut self) -> EXID_W { + EXID_W { w: self } + } + #[doc = "Bit 2 - IDE"] + #[inline(always)] + pub fn ide(&mut self) -> IDE_W { + IDE_W { w: self } + } + #[doc = "Bit 1 - RTR"] + #[inline(always)] + pub fn rtr(&mut self) -> RTR_W { + RTR_W { w: self } + } + #[doc = "Bit 0 - TXRQ"] + #[inline(always)] + pub fn txrq(&mut self) -> TXRQ_W { + TXRQ_W { w: self } + } +} diff --git a/embassy-stm32/src/can/bx/pac/generic.rs b/embassy-stm32/src/can/bx/pac/generic.rs new file mode 100644 index 000000000..749e7e204 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/generic.rs @@ -0,0 +1,256 @@ +use core::marker; + +///This trait shows that register has `read` method +/// +///Registers marked with `Writable` can be also `modify`'ed +pub trait Readable {} + +///This trait shows that register has `write`, `write_with_zero` and `reset` method +/// +///Registers marked with `Readable` can be also `modify`'ed +pub trait Writable {} + +///Reset value of the register +/// +///This value is initial value for `write` method. +///It can be also directly writed to register by `reset` method. +pub trait ResetValue { + ///Register size + type Type; + ///Reset value of the register + fn reset_value() -> Self::Type; +} + +///This structure provides volatile access to register +pub struct Reg { + register: vcell::VolatileCell, + _marker: marker::PhantomData, +} + +unsafe impl Send for Reg {} + +impl Reg +where + Self: Readable, + U: Copy, +{ + ///Reads the contents of `Readable` register + /// + ///You can read the contents of a register in such way: + ///```ignore + ///let bits = periph.reg.read().bits(); + ///``` + ///or get the content of a particular field of a register. + ///```ignore + ///let reader = periph.reg.read(); + ///let bits = reader.field1().bits(); + ///let flag = reader.field2().bit_is_set(); + ///``` + #[inline(always)] + pub fn read(&self) -> R { + R { + bits: self.register.get(), + _reg: marker::PhantomData, + } + } +} + +impl Reg +where + Self: ResetValue + Writable, + U: Copy, +{ + ///Writes the reset value to `Writable` register + /// + ///Resets the register to its initial state + #[inline(always)] + pub fn reset(&self) { + self.register.set(Self::reset_value()) + } +} + +impl Reg +where + Self: ResetValue + Writable, + U: Copy, +{ + ///Writes bits to `Writable` register + /// + ///You can write raw bits into a register: + ///```ignore + ///periph.reg.write(|w| unsafe { w.bits(rawbits) }); + ///``` + ///or write only the fields you need: + ///```ignore + ///periph.reg.write(|w| w + /// .field1().bits(newfield1bits) + /// .field2().set_bit() + /// .field3().variant(VARIANT) + ///); + ///``` + ///Other fields will have reset value. + #[inline(always)] + pub fn write(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W, + { + self.register.set( + f(&mut W { + bits: Self::reset_value(), + _reg: marker::PhantomData, + }) + .bits, + ); + } +} + +impl Reg +where + Self: Writable, + U: Copy + Default, +{ + ///Writes Zero to `Writable` register + /// + ///Similar to `write`, but unused bits will contain 0. + #[inline(always)] + pub fn write_with_zero(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W, + { + self.register.set( + f(&mut W { + bits: U::default(), + _reg: marker::PhantomData, + }) + .bits, + ); + } +} + +impl Reg +where + Self: Readable + Writable, + U: Copy, +{ + ///Modifies the contents of the register + /// + ///E.g. to do a read-modify-write sequence to change parts of a register: + ///```ignore + ///periph.reg.modify(|r, w| unsafe { w.bits( + /// r.bits() | 3 + ///) }); + ///``` + ///or + ///```ignore + ///periph.reg.modify(|_, w| w + /// .field1().bits(newfield1bits) + /// .field2().set_bit() + /// .field3().variant(VARIANT) + ///); + ///``` + ///Other fields will have value they had before call `modify`. + #[inline(always)] + pub fn modify(&self, f: F) + where + for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, + { + let bits = self.register.get(); + self.register.set( + f( + &R { + bits, + _reg: marker::PhantomData, + }, + &mut W { + bits, + _reg: marker::PhantomData, + }, + ) + .bits, + ); + } +} + +///Register/field reader +/// +///Result of the [`read`](Reg::read) method of a register. +///Also it can be used in the [`modify`](Reg::read) method +pub struct R { + pub(crate) bits: U, + _reg: marker::PhantomData, +} + +impl R +where + U: Copy, +{ + ///Create new instance of reader + #[inline(always)] + pub(crate) fn new(bits: U) -> Self { + Self { + bits, + _reg: marker::PhantomData, + } + } + ///Read raw bits from register/field + #[inline(always)] + pub fn bits(&self) -> U { + self.bits + } +} + +impl PartialEq for R +where + U: PartialEq, + FI: Copy + Into, +{ + #[inline(always)] + fn eq(&self, other: &FI) -> bool { + self.bits.eq(&(*other).into()) + } +} + +impl R { + ///Value of the field as raw bits + #[inline(always)] + pub fn bit(&self) -> bool { + self.bits + } + ///Returns `true` if the bit is clear (0) + #[inline(always)] + pub fn bit_is_clear(&self) -> bool { + !self.bit() + } + ///Returns `true` if the bit is set (1) + #[inline(always)] + pub fn bit_is_set(&self) -> bool { + self.bit() + } +} + +///Register writer +/// +///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register +pub struct W { + ///Writable bits + pub(crate) bits: U, + _reg: marker::PhantomData, +} + +impl W { + ///Writes raw bits to the register + #[inline(always)] + pub unsafe fn bits(&mut self, bits: U) -> &mut Self { + self.bits = bits; + self + } +} + +///Used if enumerated values cover not the whole range +#[derive(Clone, Copy, PartialEq)] +pub enum Variant { + ///Expected variant + Val(T), + ///Raw bits + Res(U), +} diff --git a/embassy-stm32/src/can/bx/pac/mod.rs b/embassy-stm32/src/can/bx/pac/mod.rs new file mode 100644 index 000000000..4360c2c73 --- /dev/null +++ b/embassy-stm32/src/can/bx/pac/mod.rs @@ -0,0 +1,9 @@ +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] +use core::marker::PhantomData; +use core::ops::Deref; + +#[doc = "Controller area network"] +pub mod can; +pub mod generic; From fecb65b98862fe4c8c83df0be60dc6810625fa65 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 3 Mar 2024 16:23:40 +1000 Subject: [PATCH 644/760] Make use of internal BXCAN crate work. Tested on stm32f103 with real bus and HIL tests. Fix --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/can/bx/filter.rs | 14 +-- embassy-stm32/src/can/bx/frame.rs | 14 +-- embassy-stm32/src/can/bx/interrupt.rs | 4 +- embassy-stm32/src/can/bx/mod.rs | 20 ++--- embassy-stm32/src/can/bx/pac/can.rs | 96 ++++++++++----------- embassy-stm32/src/can/bx/pac/can/btr.rs | 18 ++-- embassy-stm32/src/can/bx/pac/can/esr.rs | 18 ++-- embassy-stm32/src/can/bx/pac/can/fa1r.rs | 34 ++++---- embassy-stm32/src/can/bx/pac/can/fb.rs | 16 ++-- embassy-stm32/src/can/bx/pac/can/fb/fr1.rs | 8 +- embassy-stm32/src/can/bx/pac/can/fb/fr2.rs | 8 +- embassy-stm32/src/can/bx/pac/can/ffa1r.rs | 34 ++++---- embassy-stm32/src/can/bx/pac/can/fm1r.rs | 34 ++++---- embassy-stm32/src/can/bx/pac/can/fmr.rs | 10 +-- embassy-stm32/src/can/bx/pac/can/fs1r.rs | 34 ++++---- embassy-stm32/src/can/bx/pac/can/ier.rs | 34 ++++---- embassy-stm32/src/can/bx/pac/can/mcr.rs | 26 +++--- embassy-stm32/src/can/bx/pac/can/msr.rs | 24 +++--- embassy-stm32/src/can/bx/pac/can/rfr.rs | 18 ++-- embassy-stm32/src/can/bx/pac/can/rx.rs | 24 +++--- embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs | 10 +-- embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs | 10 +-- embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs | 8 +- embassy-stm32/src/can/bx/pac/can/rx/rir.rs | 10 +-- embassy-stm32/src/can/bx/pac/can/tsr.rs | 50 +++++------ embassy-stm32/src/can/bx/pac/can/tx.rs | 32 +++---- embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs | 14 +-- embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs | 14 +-- embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs | 12 +-- embassy-stm32/src/can/bx/pac/can/tx/tir.rs | 16 ++-- embassy-stm32/src/can/bxcan.rs | 75 ++++++++-------- examples/stm32f1/src/bin/can.rs | 4 +- tests/stm32/src/bin/can.rs | 4 +- 34 files changed, 376 insertions(+), 375 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index b326c26fd..e5e7ba3e3 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,6 @@ critical-section = "1.1" #stm32-metapac = { version = "15" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e7f91751fbbf856e0cb30e50ae6db79f0409b085" } vcell = "0.1.3" -bxcan = "0.7.0" nb = "1.0.0" stm32-fmc = "0.3.0" cfg-if = "1.0.0" @@ -84,6 +83,7 @@ document-features = "0.2.7" static_assertions = { version = "1.1" } volatile-register = { version = "0.2.1" } +bitflags = "2.4.2" @@ -104,7 +104,7 @@ default = ["rt"] rt = ["stm32-metapac/rt"] ## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging -defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] +defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] exti = [] low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bx/filter.rs index acd2e4688..0213e0f44 100644 --- a/embassy-stm32/src/can/bx/filter.rs +++ b/embassy-stm32/src/can/bx/filter.rs @@ -2,8 +2,8 @@ use core::marker::PhantomData; -use crate::pac::can::RegisterBlock; -use crate::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; +use crate::can::bx::pac::can::RegisterBlock; +use crate::can::bx::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers @@ -14,19 +14,19 @@ const F16_IDE: u16 = 0b01000; /// /// This can match data and remote frames using standard IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ListEntry16(u16); /// A 32-bit filter list entry. /// /// This can match data and remote frames using extended or standard IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ListEntry32(u32); /// A 16-bit identifier mask. #[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Mask16 { id: u16, mask: u16, @@ -34,7 +34,7 @@ pub struct Mask16 { /// A 32-bit identifier mask. #[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Mask32 { id: u32, mask: u32, @@ -170,7 +170,7 @@ impl Mask32 { /// The configuration of a filter bank. #[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum BankConfig { List16([ListEntry16; 4]), List32([ListEntry32; 2]), diff --git a/embassy-stm32/src/can/bx/frame.rs b/embassy-stm32/src/can/bx/frame.rs index c1089b044..a7e8d5b20 100644 --- a/embassy-stm32/src/can/bx/frame.rs +++ b/embassy-stm32/src/can/bx/frame.rs @@ -1,14 +1,14 @@ #[cfg(test)] -mod tests; use core::cmp::Ordering; use core::ops::{Deref, DerefMut}; -use crate::{Id, IdReg}; +use crate::can::bx::{Id, IdReg}; /// A CAN data or remote frame. #[derive(Clone, Debug, Eq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +//#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Frame { pub(crate) id: IdReg, pub(crate) data: Data, @@ -128,20 +128,20 @@ pub struct FramePriority(IdReg); /// Ordering is based on the Identifier and frame type (data vs. remote) and can be used to sort /// frames by priority. impl Ord for FramePriority { - fn cmp(&self, other: &Self) -> Ordering { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.0.cmp(&other.0) } } impl PartialOrd for FramePriority { - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PartialEq for FramePriority { fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Ordering::Equal + self.cmp(other) == core::cmp::Ordering::Equal } } @@ -227,7 +227,7 @@ impl PartialEq for Data { impl Eq for Data {} -#[cfg(feature = "unstable-defmt")] +#[cfg(feature = "defmt")] impl defmt::Format for Data { fn format(&self, fmt: defmt::Formatter<'_>) { self.as_ref().format(fmt) diff --git a/embassy-stm32/src/can/bx/interrupt.rs b/embassy-stm32/src/can/bx/interrupt.rs index 17aacf8e0..dac4b7b3c 100644 --- a/embassy-stm32/src/can/bx/interrupt.rs +++ b/embassy-stm32/src/can/bx/interrupt.rs @@ -3,7 +3,7 @@ use core::ops; #[allow(unused_imports)] // for intra-doc links only -use crate::{Can, Rx0}; +use crate::can::bx::{Can, Rx0}; /// bxCAN interrupt sources. /// @@ -18,7 +18,7 @@ use crate::{Can, Rx0}; /// This means that some of the interrupts listed here will result in the same interrupt handler /// being invoked. #[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Interrupt { /// Fires the **TX** interrupt when one of the transmit mailboxes returns to empty state. diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 3cfc09c85..2789d1ff9 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -23,7 +23,7 @@ //! //! | Feature | Description | //! |---------|-------------| -//! | `unstable-defmt` | Implements [`defmt`]'s `Format` trait for the types in this crate.[^1] | +//! | `defmt` | Implements [`defmt`]'s `Format` trait for the types in this crate.[^1] | //! //! [^1]: The specific version of defmt is unspecified and may be updated in a patch release. //! @@ -36,7 +36,7 @@ #![no_std] #![allow(clippy::unnecessary_operation)] // lint is bugged -mod embedded_hal; +//mod embedded_hal; pub mod filter; mod frame; mod id; @@ -47,11 +47,11 @@ mod pac; pub use id::{ExtendedId, Id, StandardId}; -pub use crate::frame::{Data, Frame, FramePriority}; -pub use crate::interrupt::{Interrupt, Interrupts}; -pub use crate::pac::can::RegisterBlock; +pub use crate::can::bx::frame::{Data, Frame, FramePriority}; +pub use crate::can::bx::interrupt::{Interrupt, Interrupts}; +pub use crate::can::bx::pac::can::RegisterBlock; -use crate::filter::MasterFilters; +use crate::can::bx::filter::MasterFilters; use core::cmp::{Ord, Ordering}; use core::convert::{Infallible, TryInto}; use core::marker::PhantomData; @@ -124,7 +124,7 @@ pub enum Error { /// Error that indicates that an incoming message has been lost due to buffer overrun. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct OverrunError { _priv: (), } @@ -140,7 +140,7 @@ pub struct OverrunError { /// have a higher priority than extended frames and data frames have a higher /// priority than remote frames. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] struct IdReg(u32); impl IdReg { @@ -1060,7 +1060,7 @@ fn receive_fifo(can: &RegisterBlock, fifo_nr: usize) -> nb::Result; +#[doc = "CAN_MCR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [mcr](mcr) module"] +pub type MCR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _MCR; #[doc = "`read()` method returns [mcr::R](mcr::R) reader structure"] -impl crate::Readable for MCR {} +impl crate::can::bx::Readable for MCR {} #[doc = "`write(|w| ..)` method takes [mcr::W](mcr::W) writer structure"] -impl crate::Writable for MCR {} +impl crate::can::bx::Writable for MCR {} #[doc = "CAN_MCR"] pub mod mcr; -#[doc = "CAN_MSR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [msr](msr) module"] -pub type MSR = crate::Reg; +#[doc = "CAN_MSR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [msr](msr) module"] +pub type MSR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _MSR; #[doc = "`read()` method returns [msr::R](msr::R) reader structure"] -impl crate::Readable for MSR {} +impl crate::can::bx::Readable for MSR {} #[doc = "`write(|w| ..)` method takes [msr::W](msr::W) writer structure"] -impl crate::Writable for MSR {} +impl crate::can::bx::Writable for MSR {} #[doc = "CAN_MSR"] pub mod msr; -#[doc = "CAN_TSR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tsr](tsr) module"] -pub type TSR = crate::Reg; +#[doc = "CAN_TSR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tsr](tsr) module"] +pub type TSR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _TSR; #[doc = "`read()` method returns [tsr::R](tsr::R) reader structure"] -impl crate::Readable for TSR {} +impl crate::can::bx::Readable for TSR {} #[doc = "`write(|w| ..)` method takes [tsr::W](tsr::W) writer structure"] -impl crate::Writable for TSR {} +impl crate::can::bx::Writable for TSR {} #[doc = "CAN_TSR"] pub mod tsr; -#[doc = "CAN_RF0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rfr](rfr) module"] -pub type RFR = crate::Reg; +#[doc = "CAN_RF0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rfr](rfr) module"] +pub type RFR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _RFR; #[doc = "`read()` method returns [rfr::R](rfr::R) reader structure"] -impl crate::Readable for RFR {} +impl crate::can::bx::Readable for RFR {} #[doc = "`write(|w| ..)` method takes [rfr::W](rfr::W) writer structure"] -impl crate::Writable for RFR {} +impl crate::can::bx::Writable for RFR {} #[doc = "CAN_RF0R"] pub mod rfr; -#[doc = "CAN_IER\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [ier](ier) module"] -pub type IER = crate::Reg; +#[doc = "CAN_IER\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [ier](ier) module"] +pub type IER = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _IER; #[doc = "`read()` method returns [ier::R](ier::R) reader structure"] -impl crate::Readable for IER {} +impl crate::can::bx::Readable for IER {} #[doc = "`write(|w| ..)` method takes [ier::W](ier::W) writer structure"] -impl crate::Writable for IER {} +impl crate::can::bx::Writable for IER {} #[doc = "CAN_IER"] pub mod ier; -#[doc = "CAN_ESR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [esr](esr) module"] -pub type ESR = crate::Reg; +#[doc = "CAN_ESR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [esr](esr) module"] +pub type ESR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _ESR; #[doc = "`read()` method returns [esr::R](esr::R) reader structure"] -impl crate::Readable for ESR {} +impl crate::can::bx::Readable for ESR {} #[doc = "`write(|w| ..)` method takes [esr::W](esr::W) writer structure"] -impl crate::Writable for ESR {} +impl crate::can::bx::Writable for ESR {} #[doc = "CAN_ESR"] pub mod esr; -#[doc = "CAN_BTR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [btr](btr) module"] -pub type BTR = crate::Reg; +#[doc = "CAN_BTR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [btr](btr) module"] +pub type BTR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _BTR; #[doc = "`read()` method returns [btr::R](btr::R) reader structure"] -impl crate::Readable for BTR {} +impl crate::can::bx::Readable for BTR {} #[doc = "`write(|w| ..)` method takes [btr::W](btr::W) writer structure"] -impl crate::Writable for BTR {} +impl crate::can::bx::Writable for BTR {} #[doc = "CAN_BTR"] pub mod btr; -#[doc = "CAN_FMR\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fmr](fmr) module"] -pub type FMR = crate::Reg; +#[doc = "CAN_FMR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fmr](fmr) module"] +pub type FMR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _FMR; #[doc = "`read()` method returns [fmr::R](fmr::R) reader structure"] -impl crate::Readable for FMR {} +impl crate::can::bx::Readable for FMR {} #[doc = "`write(|w| ..)` method takes [fmr::W](fmr::W) writer structure"] -impl crate::Writable for FMR {} +impl crate::can::bx::Writable for FMR {} #[doc = "CAN_FMR"] pub mod fmr; -#[doc = "CAN_FM1R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fm1r](fm1r) module"] -pub type FM1R = crate::Reg; +#[doc = "CAN_FM1R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fm1r](fm1r) module"] +pub type FM1R = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _FM1R; #[doc = "`read()` method returns [fm1r::R](fm1r::R) reader structure"] -impl crate::Readable for FM1R {} +impl crate::can::bx::Readable for FM1R {} #[doc = "`write(|w| ..)` method takes [fm1r::W](fm1r::W) writer structure"] -impl crate::Writable for FM1R {} +impl crate::can::bx::Writable for FM1R {} #[doc = "CAN_FM1R"] pub mod fm1r; -#[doc = "CAN_FS1R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fs1r](fs1r) module"] -pub type FS1R = crate::Reg; +#[doc = "CAN_FS1R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fs1r](fs1r) module"] +pub type FS1R = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _FS1R; #[doc = "`read()` method returns [fs1r::R](fs1r::R) reader structure"] -impl crate::Readable for FS1R {} +impl crate::can::bx::Readable for FS1R {} #[doc = "`write(|w| ..)` method takes [fs1r::W](fs1r::W) writer structure"] -impl crate::Writable for FS1R {} +impl crate::can::bx::Writable for FS1R {} #[doc = "CAN_FS1R"] pub mod fs1r; -#[doc = "CAN_FFA1R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [ffa1r](ffa1r) module"] -pub type FFA1R = crate::Reg; +#[doc = "CAN_FFA1R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [ffa1r](ffa1r) module"] +pub type FFA1R = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _FFA1R; #[doc = "`read()` method returns [ffa1r::R](ffa1r::R) reader structure"] -impl crate::Readable for FFA1R {} +impl crate::can::bx::Readable for FFA1R {} #[doc = "`write(|w| ..)` method takes [ffa1r::W](ffa1r::W) writer structure"] -impl crate::Writable for FFA1R {} +impl crate::can::bx::Writable for FFA1R {} #[doc = "CAN_FFA1R"] pub mod ffa1r; -#[doc = "CAN_FA1R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fa1r](fa1r) module"] -pub type FA1R = crate::Reg; +#[doc = "CAN_FA1R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fa1r](fa1r) module"] +pub type FA1R = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _FA1R; #[doc = "`read()` method returns [fa1r::R](fa1r::R) reader structure"] -impl crate::Readable for FA1R {} +impl crate::can::bx::Readable for FA1R {} #[doc = "`write(|w| ..)` method takes [fa1r::W](fa1r::W) writer structure"] -impl crate::Writable for FA1R {} +impl crate::can::bx::Writable for FA1R {} #[doc = "CAN_FA1R"] pub mod fa1r; diff --git a/embassy-stm32/src/can/bx/pac/can/btr.rs b/embassy-stm32/src/can/bx/pac/can/btr.rs index 0a801c50e..23ca298aa 100644 --- a/embassy-stm32/src/can/bx/pac/can/btr.rs +++ b/embassy-stm32/src/can/bx/pac/can/btr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register BTR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register BTR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register BTR `reset()`'s with value 0"] -impl crate::ResetValue for super::BTR { +impl crate::can::bx::ResetValue for super::BTR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -25,7 +25,7 @@ impl From for bool { } } #[doc = "Reader of field `SILM`"] -pub type SILM_R = crate::R; +pub type SILM_R = crate::can::bx::R; impl SILM_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -100,7 +100,7 @@ impl From for bool { } } #[doc = "Reader of field `LBKM`"] -pub type LBKM_R = crate::R; +pub type LBKM_R = crate::can::bx::R; impl LBKM_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -161,7 +161,7 @@ impl<'a> LBKM_W<'a> { } } #[doc = "Reader of field `SJW`"] -pub type SJW_R = crate::R; +pub type SJW_R = crate::can::bx::R; #[doc = "Write proxy for field `SJW`"] pub struct SJW_W<'a> { w: &'a mut W, @@ -175,7 +175,7 @@ impl<'a> SJW_W<'a> { } } #[doc = "Reader of field `TS2`"] -pub type TS2_R = crate::R; +pub type TS2_R = crate::can::bx::R; #[doc = "Write proxy for field `TS2`"] pub struct TS2_W<'a> { w: &'a mut W, @@ -189,7 +189,7 @@ impl<'a> TS2_W<'a> { } } #[doc = "Reader of field `TS1`"] -pub type TS1_R = crate::R; +pub type TS1_R = crate::can::bx::R; #[doc = "Write proxy for field `TS1`"] pub struct TS1_W<'a> { w: &'a mut W, @@ -203,7 +203,7 @@ impl<'a> TS1_W<'a> { } } #[doc = "Reader of field `BRP`"] -pub type BRP_R = crate::R; +pub type BRP_R = crate::can::bx::R; #[doc = "Write proxy for field `BRP`"] pub struct BRP_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/esr.rs b/embassy-stm32/src/can/bx/pac/can/esr.rs index 9ea7c5a24..ddc414239 100644 --- a/embassy-stm32/src/can/bx/pac/can/esr.rs +++ b/embassy-stm32/src/can/bx/pac/can/esr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register ESR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register ESR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register ESR `reset()`'s with value 0"] -impl crate::ResetValue for super::ESR { +impl crate::can::bx::ResetValue for super::ESR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,9 +11,9 @@ impl crate::ResetValue for super::ESR { } } #[doc = "Reader of field `REC`"] -pub type REC_R = crate::R; +pub type REC_R = crate::can::bx::R; #[doc = "Reader of field `TEC`"] -pub type TEC_R = crate::R; +pub type TEC_R = crate::can::bx::R; #[doc = "LEC\n\nValue on reset: 0"] #[derive(Clone, Copy, Debug, PartialEq)] #[repr(u8)] @@ -42,7 +42,7 @@ impl From for u8 { } } #[doc = "Reader of field `LEC`"] -pub type LEC_R = crate::R; +pub type LEC_R = crate::can::bx::R; impl LEC_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -160,11 +160,11 @@ impl<'a> LEC_W<'a> { } } #[doc = "Reader of field `BOFF`"] -pub type BOFF_R = crate::R; +pub type BOFF_R = crate::can::bx::R; #[doc = "Reader of field `EPVF`"] -pub type EPVF_R = crate::R; +pub type EPVF_R = crate::can::bx::R; #[doc = "Reader of field `EWGF`"] -pub type EWGF_R = crate::R; +pub type EWGF_R = crate::can::bx::R; impl R { #[doc = "Bits 24:31 - REC"] #[inline(always)] diff --git a/embassy-stm32/src/can/bx/pac/can/fa1r.rs b/embassy-stm32/src/can/bx/pac/can/fa1r.rs index 797e4e074..e7b2b365d 100644 --- a/embassy-stm32/src/can/bx/pac/can/fa1r.rs +++ b/embassy-stm32/src/can/bx/pac/can/fa1r.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register FA1R"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register FA1R"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register FA1R `reset()`'s with value 0"] -impl crate::ResetValue for super::FA1R { +impl crate::can::bx::ResetValue for super::FA1R { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::FA1R { } } #[doc = "Reader of field `FACT0`"] -pub type FACT0_R = crate::R; +pub type FACT0_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT0`"] pub struct FACT0_W<'a> { w: &'a mut W, @@ -35,7 +35,7 @@ impl<'a> FACT0_W<'a> { } } #[doc = "Reader of field `FACT1`"] -pub type FACT1_R = crate::R; +pub type FACT1_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT1`"] pub struct FACT1_W<'a> { w: &'a mut W, @@ -59,7 +59,7 @@ impl<'a> FACT1_W<'a> { } } #[doc = "Reader of field `FACT2`"] -pub type FACT2_R = crate::R; +pub type FACT2_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT2`"] pub struct FACT2_W<'a> { w: &'a mut W, @@ -83,7 +83,7 @@ impl<'a> FACT2_W<'a> { } } #[doc = "Reader of field `FACT3`"] -pub type FACT3_R = crate::R; +pub type FACT3_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT3`"] pub struct FACT3_W<'a> { w: &'a mut W, @@ -107,7 +107,7 @@ impl<'a> FACT3_W<'a> { } } #[doc = "Reader of field `FACT4`"] -pub type FACT4_R = crate::R; +pub type FACT4_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT4`"] pub struct FACT4_W<'a> { w: &'a mut W, @@ -131,7 +131,7 @@ impl<'a> FACT4_W<'a> { } } #[doc = "Reader of field `FACT5`"] -pub type FACT5_R = crate::R; +pub type FACT5_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT5`"] pub struct FACT5_W<'a> { w: &'a mut W, @@ -155,7 +155,7 @@ impl<'a> FACT5_W<'a> { } } #[doc = "Reader of field `FACT6`"] -pub type FACT6_R = crate::R; +pub type FACT6_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT6`"] pub struct FACT6_W<'a> { w: &'a mut W, @@ -179,7 +179,7 @@ impl<'a> FACT6_W<'a> { } } #[doc = "Reader of field `FACT7`"] -pub type FACT7_R = crate::R; +pub type FACT7_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT7`"] pub struct FACT7_W<'a> { w: &'a mut W, @@ -203,7 +203,7 @@ impl<'a> FACT7_W<'a> { } } #[doc = "Reader of field `FACT8`"] -pub type FACT8_R = crate::R; +pub type FACT8_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT8`"] pub struct FACT8_W<'a> { w: &'a mut W, @@ -227,7 +227,7 @@ impl<'a> FACT8_W<'a> { } } #[doc = "Reader of field `FACT9`"] -pub type FACT9_R = crate::R; +pub type FACT9_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT9`"] pub struct FACT9_W<'a> { w: &'a mut W, @@ -251,7 +251,7 @@ impl<'a> FACT9_W<'a> { } } #[doc = "Reader of field `FACT10`"] -pub type FACT10_R = crate::R; +pub type FACT10_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT10`"] pub struct FACT10_W<'a> { w: &'a mut W, @@ -275,7 +275,7 @@ impl<'a> FACT10_W<'a> { } } #[doc = "Reader of field `FACT11`"] -pub type FACT11_R = crate::R; +pub type FACT11_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT11`"] pub struct FACT11_W<'a> { w: &'a mut W, @@ -299,7 +299,7 @@ impl<'a> FACT11_W<'a> { } } #[doc = "Reader of field `FACT12`"] -pub type FACT12_R = crate::R; +pub type FACT12_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT12`"] pub struct FACT12_W<'a> { w: &'a mut W, @@ -323,7 +323,7 @@ impl<'a> FACT12_W<'a> { } } #[doc = "Reader of field `FACT13`"] -pub type FACT13_R = crate::R; +pub type FACT13_R = crate::can::bx::R; #[doc = "Write proxy for field `FACT13`"] pub struct FACT13_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/fb.rs b/embassy-stm32/src/can/bx/pac/can/fb.rs index 1b31e37c5..527235b29 100644 --- a/embassy-stm32/src/can/bx/pac/can/fb.rs +++ b/embassy-stm32/src/can/bx/pac/can/fb.rs @@ -1,22 +1,22 @@ -#[doc = "Filter bank 0 register 1\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fr1](fr1) module"] -pub type FR1 = crate::Reg; +#[doc = "Filter bank 0 register 1\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fr1](fr1) module"] +pub type FR1 = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _FR1; #[doc = "`read()` method returns [fr1::R](fr1::R) reader structure"] -impl crate::Readable for FR1 {} +impl crate::can::bx::Readable for FR1 {} #[doc = "`write(|w| ..)` method takes [fr1::W](fr1::W) writer structure"] -impl crate::Writable for FR1 {} +impl crate::can::bx::Writable for FR1 {} #[doc = "Filter bank 0 register 1"] pub mod fr1; -#[doc = "Filter bank 0 register 2\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fr2](fr2) module"] -pub type FR2 = crate::Reg; +#[doc = "Filter bank 0 register 2\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fr2](fr2) module"] +pub type FR2 = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _FR2; #[doc = "`read()` method returns [fr2::R](fr2::R) reader structure"] -impl crate::Readable for FR2 {} +impl crate::can::bx::Readable for FR2 {} #[doc = "`write(|w| ..)` method takes [fr2::W](fr2::W) writer structure"] -impl crate::Writable for FR2 {} +impl crate::can::bx::Writable for FR2 {} #[doc = "Filter bank 0 register 2"] pub mod fr2; diff --git a/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs b/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs index b39d5e8fb..6a80bd308 100644 --- a/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs +++ b/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register FR1"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register FR1"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register FR1 `reset()`'s with value 0"] -impl crate::ResetValue for super::FR1 { +impl crate::can::bx::ResetValue for super::FR1 { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::FR1 { } } #[doc = "Reader of field `FB`"] -pub type FB_R = crate::R; +pub type FB_R = crate::can::bx::R; #[doc = "Write proxy for field `FB`"] pub struct FB_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs b/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs index 1f318894e..097387b9f 100644 --- a/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs +++ b/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register FR2"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register FR2"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register FR2 `reset()`'s with value 0"] -impl crate::ResetValue for super::FR2 { +impl crate::can::bx::ResetValue for super::FR2 { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::FR2 { } } #[doc = "Reader of field `FB`"] -pub type FB_R = crate::R; +pub type FB_R = crate::can::bx::R; #[doc = "Write proxy for field `FB`"] pub struct FB_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/ffa1r.rs b/embassy-stm32/src/can/bx/pac/can/ffa1r.rs index bc3ab0eb9..cf5e04c78 100644 --- a/embassy-stm32/src/can/bx/pac/can/ffa1r.rs +++ b/embassy-stm32/src/can/bx/pac/can/ffa1r.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register FFA1R"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register FFA1R"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register FFA1R `reset()`'s with value 0"] -impl crate::ResetValue for super::FFA1R { +impl crate::can::bx::ResetValue for super::FFA1R { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::FFA1R { } } #[doc = "Reader of field `FFA0`"] -pub type FFA0_R = crate::R; +pub type FFA0_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA0`"] pub struct FFA0_W<'a> { w: &'a mut W, @@ -35,7 +35,7 @@ impl<'a> FFA0_W<'a> { } } #[doc = "Reader of field `FFA1`"] -pub type FFA1_R = crate::R; +pub type FFA1_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA1`"] pub struct FFA1_W<'a> { w: &'a mut W, @@ -59,7 +59,7 @@ impl<'a> FFA1_W<'a> { } } #[doc = "Reader of field `FFA2`"] -pub type FFA2_R = crate::R; +pub type FFA2_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA2`"] pub struct FFA2_W<'a> { w: &'a mut W, @@ -83,7 +83,7 @@ impl<'a> FFA2_W<'a> { } } #[doc = "Reader of field `FFA3`"] -pub type FFA3_R = crate::R; +pub type FFA3_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA3`"] pub struct FFA3_W<'a> { w: &'a mut W, @@ -107,7 +107,7 @@ impl<'a> FFA3_W<'a> { } } #[doc = "Reader of field `FFA4`"] -pub type FFA4_R = crate::R; +pub type FFA4_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA4`"] pub struct FFA4_W<'a> { w: &'a mut W, @@ -131,7 +131,7 @@ impl<'a> FFA4_W<'a> { } } #[doc = "Reader of field `FFA5`"] -pub type FFA5_R = crate::R; +pub type FFA5_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA5`"] pub struct FFA5_W<'a> { w: &'a mut W, @@ -155,7 +155,7 @@ impl<'a> FFA5_W<'a> { } } #[doc = "Reader of field `FFA6`"] -pub type FFA6_R = crate::R; +pub type FFA6_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA6`"] pub struct FFA6_W<'a> { w: &'a mut W, @@ -179,7 +179,7 @@ impl<'a> FFA6_W<'a> { } } #[doc = "Reader of field `FFA7`"] -pub type FFA7_R = crate::R; +pub type FFA7_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA7`"] pub struct FFA7_W<'a> { w: &'a mut W, @@ -203,7 +203,7 @@ impl<'a> FFA7_W<'a> { } } #[doc = "Reader of field `FFA8`"] -pub type FFA8_R = crate::R; +pub type FFA8_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA8`"] pub struct FFA8_W<'a> { w: &'a mut W, @@ -227,7 +227,7 @@ impl<'a> FFA8_W<'a> { } } #[doc = "Reader of field `FFA9`"] -pub type FFA9_R = crate::R; +pub type FFA9_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA9`"] pub struct FFA9_W<'a> { w: &'a mut W, @@ -251,7 +251,7 @@ impl<'a> FFA9_W<'a> { } } #[doc = "Reader of field `FFA10`"] -pub type FFA10_R = crate::R; +pub type FFA10_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA10`"] pub struct FFA10_W<'a> { w: &'a mut W, @@ -275,7 +275,7 @@ impl<'a> FFA10_W<'a> { } } #[doc = "Reader of field `FFA11`"] -pub type FFA11_R = crate::R; +pub type FFA11_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA11`"] pub struct FFA11_W<'a> { w: &'a mut W, @@ -299,7 +299,7 @@ impl<'a> FFA11_W<'a> { } } #[doc = "Reader of field `FFA12`"] -pub type FFA12_R = crate::R; +pub type FFA12_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA12`"] pub struct FFA12_W<'a> { w: &'a mut W, @@ -323,7 +323,7 @@ impl<'a> FFA12_W<'a> { } } #[doc = "Reader of field `FFA13`"] -pub type FFA13_R = crate::R; +pub type FFA13_R = crate::can::bx::R; #[doc = "Write proxy for field `FFA13`"] pub struct FFA13_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/fm1r.rs b/embassy-stm32/src/can/bx/pac/can/fm1r.rs index e0a8dc648..828f1914e 100644 --- a/embassy-stm32/src/can/bx/pac/can/fm1r.rs +++ b/embassy-stm32/src/can/bx/pac/can/fm1r.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register FM1R"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register FM1R"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register FM1R `reset()`'s with value 0"] -impl crate::ResetValue for super::FM1R { +impl crate::can::bx::ResetValue for super::FM1R { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::FM1R { } } #[doc = "Reader of field `FBM0`"] -pub type FBM0_R = crate::R; +pub type FBM0_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM0`"] pub struct FBM0_W<'a> { w: &'a mut W, @@ -35,7 +35,7 @@ impl<'a> FBM0_W<'a> { } } #[doc = "Reader of field `FBM1`"] -pub type FBM1_R = crate::R; +pub type FBM1_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM1`"] pub struct FBM1_W<'a> { w: &'a mut W, @@ -59,7 +59,7 @@ impl<'a> FBM1_W<'a> { } } #[doc = "Reader of field `FBM2`"] -pub type FBM2_R = crate::R; +pub type FBM2_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM2`"] pub struct FBM2_W<'a> { w: &'a mut W, @@ -83,7 +83,7 @@ impl<'a> FBM2_W<'a> { } } #[doc = "Reader of field `FBM3`"] -pub type FBM3_R = crate::R; +pub type FBM3_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM3`"] pub struct FBM3_W<'a> { w: &'a mut W, @@ -107,7 +107,7 @@ impl<'a> FBM3_W<'a> { } } #[doc = "Reader of field `FBM4`"] -pub type FBM4_R = crate::R; +pub type FBM4_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM4`"] pub struct FBM4_W<'a> { w: &'a mut W, @@ -131,7 +131,7 @@ impl<'a> FBM4_W<'a> { } } #[doc = "Reader of field `FBM5`"] -pub type FBM5_R = crate::R; +pub type FBM5_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM5`"] pub struct FBM5_W<'a> { w: &'a mut W, @@ -155,7 +155,7 @@ impl<'a> FBM5_W<'a> { } } #[doc = "Reader of field `FBM6`"] -pub type FBM6_R = crate::R; +pub type FBM6_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM6`"] pub struct FBM6_W<'a> { w: &'a mut W, @@ -179,7 +179,7 @@ impl<'a> FBM6_W<'a> { } } #[doc = "Reader of field `FBM7`"] -pub type FBM7_R = crate::R; +pub type FBM7_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM7`"] pub struct FBM7_W<'a> { w: &'a mut W, @@ -203,7 +203,7 @@ impl<'a> FBM7_W<'a> { } } #[doc = "Reader of field `FBM8`"] -pub type FBM8_R = crate::R; +pub type FBM8_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM8`"] pub struct FBM8_W<'a> { w: &'a mut W, @@ -227,7 +227,7 @@ impl<'a> FBM8_W<'a> { } } #[doc = "Reader of field `FBM9`"] -pub type FBM9_R = crate::R; +pub type FBM9_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM9`"] pub struct FBM9_W<'a> { w: &'a mut W, @@ -251,7 +251,7 @@ impl<'a> FBM9_W<'a> { } } #[doc = "Reader of field `FBM10`"] -pub type FBM10_R = crate::R; +pub type FBM10_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM10`"] pub struct FBM10_W<'a> { w: &'a mut W, @@ -275,7 +275,7 @@ impl<'a> FBM10_W<'a> { } } #[doc = "Reader of field `FBM11`"] -pub type FBM11_R = crate::R; +pub type FBM11_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM11`"] pub struct FBM11_W<'a> { w: &'a mut W, @@ -299,7 +299,7 @@ impl<'a> FBM11_W<'a> { } } #[doc = "Reader of field `FBM12`"] -pub type FBM12_R = crate::R; +pub type FBM12_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM12`"] pub struct FBM12_W<'a> { w: &'a mut W, @@ -323,7 +323,7 @@ impl<'a> FBM12_W<'a> { } } #[doc = "Reader of field `FBM13`"] -pub type FBM13_R = crate::R; +pub type FBM13_R = crate::can::bx::R; #[doc = "Write proxy for field `FBM13`"] pub struct FBM13_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/fmr.rs b/embassy-stm32/src/can/bx/pac/can/fmr.rs index 5701af452..5663ff3cd 100644 --- a/embassy-stm32/src/can/bx/pac/can/fmr.rs +++ b/embassy-stm32/src/can/bx/pac/can/fmr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register FMR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register FMR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register FMR `reset()`'s with value 0"] -impl crate::ResetValue for super::FMR { +impl crate::can::bx::ResetValue for super::FMR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::FMR { } } #[doc = "Reader of field `CAN2SB`"] -pub type CAN2SB_R = crate::R; +pub type CAN2SB_R = crate::can::bx::R; #[doc = "Write proxy for field `CAN2SB`"] pub struct CAN2SB_W<'a> { w: &'a mut W, @@ -25,7 +25,7 @@ impl<'a> CAN2SB_W<'a> { } } #[doc = "Reader of field `FINIT`"] -pub type FINIT_R = crate::R; +pub type FINIT_R = crate::can::bx::R; #[doc = "Write proxy for field `FINIT`"] pub struct FINIT_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/fs1r.rs b/embassy-stm32/src/can/bx/pac/can/fs1r.rs index 7bff8197d..eea27887b 100644 --- a/embassy-stm32/src/can/bx/pac/can/fs1r.rs +++ b/embassy-stm32/src/can/bx/pac/can/fs1r.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register FS1R"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register FS1R"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register FS1R `reset()`'s with value 0"] -impl crate::ResetValue for super::FS1R { +impl crate::can::bx::ResetValue for super::FS1R { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::FS1R { } } #[doc = "Reader of field `FSC0`"] -pub type FSC0_R = crate::R; +pub type FSC0_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC0`"] pub struct FSC0_W<'a> { w: &'a mut W, @@ -35,7 +35,7 @@ impl<'a> FSC0_W<'a> { } } #[doc = "Reader of field `FSC1`"] -pub type FSC1_R = crate::R; +pub type FSC1_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC1`"] pub struct FSC1_W<'a> { w: &'a mut W, @@ -59,7 +59,7 @@ impl<'a> FSC1_W<'a> { } } #[doc = "Reader of field `FSC2`"] -pub type FSC2_R = crate::R; +pub type FSC2_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC2`"] pub struct FSC2_W<'a> { w: &'a mut W, @@ -83,7 +83,7 @@ impl<'a> FSC2_W<'a> { } } #[doc = "Reader of field `FSC3`"] -pub type FSC3_R = crate::R; +pub type FSC3_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC3`"] pub struct FSC3_W<'a> { w: &'a mut W, @@ -107,7 +107,7 @@ impl<'a> FSC3_W<'a> { } } #[doc = "Reader of field `FSC4`"] -pub type FSC4_R = crate::R; +pub type FSC4_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC4`"] pub struct FSC4_W<'a> { w: &'a mut W, @@ -131,7 +131,7 @@ impl<'a> FSC4_W<'a> { } } #[doc = "Reader of field `FSC5`"] -pub type FSC5_R = crate::R; +pub type FSC5_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC5`"] pub struct FSC5_W<'a> { w: &'a mut W, @@ -155,7 +155,7 @@ impl<'a> FSC5_W<'a> { } } #[doc = "Reader of field `FSC6`"] -pub type FSC6_R = crate::R; +pub type FSC6_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC6`"] pub struct FSC6_W<'a> { w: &'a mut W, @@ -179,7 +179,7 @@ impl<'a> FSC6_W<'a> { } } #[doc = "Reader of field `FSC7`"] -pub type FSC7_R = crate::R; +pub type FSC7_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC7`"] pub struct FSC7_W<'a> { w: &'a mut W, @@ -203,7 +203,7 @@ impl<'a> FSC7_W<'a> { } } #[doc = "Reader of field `FSC8`"] -pub type FSC8_R = crate::R; +pub type FSC8_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC8`"] pub struct FSC8_W<'a> { w: &'a mut W, @@ -227,7 +227,7 @@ impl<'a> FSC8_W<'a> { } } #[doc = "Reader of field `FSC9`"] -pub type FSC9_R = crate::R; +pub type FSC9_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC9`"] pub struct FSC9_W<'a> { w: &'a mut W, @@ -251,7 +251,7 @@ impl<'a> FSC9_W<'a> { } } #[doc = "Reader of field `FSC10`"] -pub type FSC10_R = crate::R; +pub type FSC10_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC10`"] pub struct FSC10_W<'a> { w: &'a mut W, @@ -275,7 +275,7 @@ impl<'a> FSC10_W<'a> { } } #[doc = "Reader of field `FSC11`"] -pub type FSC11_R = crate::R; +pub type FSC11_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC11`"] pub struct FSC11_W<'a> { w: &'a mut W, @@ -299,7 +299,7 @@ impl<'a> FSC11_W<'a> { } } #[doc = "Reader of field `FSC12`"] -pub type FSC12_R = crate::R; +pub type FSC12_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC12`"] pub struct FSC12_W<'a> { w: &'a mut W, @@ -323,7 +323,7 @@ impl<'a> FSC12_W<'a> { } } #[doc = "Reader of field `FSC13`"] -pub type FSC13_R = crate::R; +pub type FSC13_R = crate::can::bx::R; #[doc = "Write proxy for field `FSC13`"] pub struct FSC13_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/ier.rs b/embassy-stm32/src/can/bx/pac/can/ier.rs index 3c57331b7..fa73254b7 100644 --- a/embassy-stm32/src/can/bx/pac/can/ier.rs +++ b/embassy-stm32/src/can/bx/pac/can/ier.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register IER"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register IER"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register IER `reset()`'s with value 0"] -impl crate::ResetValue for super::IER { +impl crate::can::bx::ResetValue for super::IER { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -25,7 +25,7 @@ impl From for bool { } } #[doc = "Reader of field `SLKIE`"] -pub type SLKIE_R = crate::R; +pub type SLKIE_R = crate::can::bx::R; impl SLKIE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -100,7 +100,7 @@ impl From for bool { } } #[doc = "Reader of field `WKUIE`"] -pub type WKUIE_R = crate::R; +pub type WKUIE_R = crate::can::bx::R; impl WKUIE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -175,7 +175,7 @@ impl From for bool { } } #[doc = "Reader of field `ERRIE`"] -pub type ERRIE_R = crate::R; +pub type ERRIE_R = crate::can::bx::R; impl ERRIE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -252,7 +252,7 @@ impl From for bool { } } #[doc = "Reader of field `LECIE`"] -pub type LECIE_R = crate::R; +pub type LECIE_R = crate::can::bx::R; impl LECIE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -329,7 +329,7 @@ impl From for bool { } } #[doc = "Reader of field `BOFIE`"] -pub type BOFIE_R = crate::R; +pub type BOFIE_R = crate::can::bx::R; impl BOFIE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -404,7 +404,7 @@ impl From for bool { } } #[doc = "Reader of field `EPVIE`"] -pub type EPVIE_R = crate::R; +pub type EPVIE_R = crate::can::bx::R; impl EPVIE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -479,7 +479,7 @@ impl From for bool { } } #[doc = "Reader of field `EWGIE`"] -pub type EWGIE_R = crate::R; +pub type EWGIE_R = crate::can::bx::R; impl EWGIE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -554,7 +554,7 @@ impl From for bool { } } #[doc = "Reader of field `FOVIE1`"] -pub type FOVIE1_R = crate::R; +pub type FOVIE1_R = crate::can::bx::R; impl FOVIE1_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -629,7 +629,7 @@ impl From for bool { } } #[doc = "Reader of field `FFIE1`"] -pub type FFIE1_R = crate::R; +pub type FFIE1_R = crate::can::bx::R; impl FFIE1_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -706,7 +706,7 @@ impl From for bool { } } #[doc = "Reader of field `FMPIE1`"] -pub type FMPIE1_R = crate::R; +pub type FMPIE1_R = crate::can::bx::R; impl FMPIE1_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -783,7 +783,7 @@ impl From for bool { } } #[doc = "Reader of field `FOVIE0`"] -pub type FOVIE0_R = crate::R; +pub type FOVIE0_R = crate::can::bx::R; impl FOVIE0_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -858,7 +858,7 @@ impl From for bool { } } #[doc = "Reader of field `FFIE0`"] -pub type FFIE0_R = crate::R; +pub type FFIE0_R = crate::can::bx::R; impl FFIE0_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -935,7 +935,7 @@ impl From for bool { } } #[doc = "Reader of field `FMPIE0`"] -pub type FMPIE0_R = crate::R; +pub type FMPIE0_R = crate::can::bx::R; impl FMPIE0_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -1012,7 +1012,7 @@ impl From for bool { } } #[doc = "Reader of field `TMEIE`"] -pub type TMEIE_R = crate::R; +pub type TMEIE_R = crate::can::bx::R; impl TMEIE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] diff --git a/embassy-stm32/src/can/bx/pac/can/mcr.rs b/embassy-stm32/src/can/bx/pac/can/mcr.rs index 5e47c0901..bce9561d9 100644 --- a/embassy-stm32/src/can/bx/pac/can/mcr.rs +++ b/embassy-stm32/src/can/bx/pac/can/mcr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register MCR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register MCR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register MCR `reset()`'s with value 0"] -impl crate::ResetValue for super::MCR { +impl crate::can::bx::ResetValue for super::MCR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::MCR { } } #[doc = "Reader of field `DBF`"] -pub type DBF_R = crate::R; +pub type DBF_R = crate::can::bx::R; #[doc = "Write proxy for field `DBF`"] pub struct DBF_W<'a> { w: &'a mut W, @@ -35,7 +35,7 @@ impl<'a> DBF_W<'a> { } } #[doc = "Reader of field `RESET`"] -pub type RESET_R = crate::R; +pub type RESET_R = crate::can::bx::R; #[doc = "Write proxy for field `RESET`"] pub struct RESET_W<'a> { w: &'a mut W, @@ -59,7 +59,7 @@ impl<'a> RESET_W<'a> { } } #[doc = "Reader of field `TTCM`"] -pub type TTCM_R = crate::R; +pub type TTCM_R = crate::can::bx::R; #[doc = "Write proxy for field `TTCM`"] pub struct TTCM_W<'a> { w: &'a mut W, @@ -83,7 +83,7 @@ impl<'a> TTCM_W<'a> { } } #[doc = "Reader of field `ABOM`"] -pub type ABOM_R = crate::R; +pub type ABOM_R = crate::can::bx::R; #[doc = "Write proxy for field `ABOM`"] pub struct ABOM_W<'a> { w: &'a mut W, @@ -107,7 +107,7 @@ impl<'a> ABOM_W<'a> { } } #[doc = "Reader of field `AWUM`"] -pub type AWUM_R = crate::R; +pub type AWUM_R = crate::can::bx::R; #[doc = "Write proxy for field `AWUM`"] pub struct AWUM_W<'a> { w: &'a mut W, @@ -131,7 +131,7 @@ impl<'a> AWUM_W<'a> { } } #[doc = "Reader of field `NART`"] -pub type NART_R = crate::R; +pub type NART_R = crate::can::bx::R; #[doc = "Write proxy for field `NART`"] pub struct NART_W<'a> { w: &'a mut W, @@ -155,7 +155,7 @@ impl<'a> NART_W<'a> { } } #[doc = "Reader of field `RFLM`"] -pub type RFLM_R = crate::R; +pub type RFLM_R = crate::can::bx::R; #[doc = "Write proxy for field `RFLM`"] pub struct RFLM_W<'a> { w: &'a mut W, @@ -179,7 +179,7 @@ impl<'a> RFLM_W<'a> { } } #[doc = "Reader of field `TXFP`"] -pub type TXFP_R = crate::R; +pub type TXFP_R = crate::can::bx::R; #[doc = "Write proxy for field `TXFP`"] pub struct TXFP_W<'a> { w: &'a mut W, @@ -203,7 +203,7 @@ impl<'a> TXFP_W<'a> { } } #[doc = "Reader of field `SLEEP`"] -pub type SLEEP_R = crate::R; +pub type SLEEP_R = crate::can::bx::R; #[doc = "Write proxy for field `SLEEP`"] pub struct SLEEP_W<'a> { w: &'a mut W, @@ -227,7 +227,7 @@ impl<'a> SLEEP_W<'a> { } } #[doc = "Reader of field `INRQ`"] -pub type INRQ_R = crate::R; +pub type INRQ_R = crate::can::bx::R; #[doc = "Write proxy for field `INRQ`"] pub struct INRQ_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/msr.rs b/embassy-stm32/src/can/bx/pac/can/msr.rs index 18e21c844..2e076b14e 100644 --- a/embassy-stm32/src/can/bx/pac/can/msr.rs +++ b/embassy-stm32/src/can/bx/pac/can/msr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register MSR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register MSR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register MSR `reset()`'s with value 0"] -impl crate::ResetValue for super::MSR { +impl crate::can::bx::ResetValue for super::MSR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,15 +11,15 @@ impl crate::ResetValue for super::MSR { } } #[doc = "Reader of field `RX`"] -pub type RX_R = crate::R; +pub type RX_R = crate::can::bx::R; #[doc = "Reader of field `SAMP`"] -pub type SAMP_R = crate::R; +pub type SAMP_R = crate::can::bx::R; #[doc = "Reader of field `RXM`"] -pub type RXM_R = crate::R; +pub type RXM_R = crate::can::bx::R; #[doc = "Reader of field `TXM`"] -pub type TXM_R = crate::R; +pub type TXM_R = crate::can::bx::R; #[doc = "Reader of field `SLAKI`"] -pub type SLAKI_R = crate::R; +pub type SLAKI_R = crate::can::bx::R; #[doc = "Write proxy for field `SLAKI`"] pub struct SLAKI_W<'a> { w: &'a mut W, @@ -43,7 +43,7 @@ impl<'a> SLAKI_W<'a> { } } #[doc = "Reader of field `WKUI`"] -pub type WKUI_R = crate::R; +pub type WKUI_R = crate::can::bx::R; #[doc = "Write proxy for field `WKUI`"] pub struct WKUI_W<'a> { w: &'a mut W, @@ -67,7 +67,7 @@ impl<'a> WKUI_W<'a> { } } #[doc = "Reader of field `ERRI`"] -pub type ERRI_R = crate::R; +pub type ERRI_R = crate::can::bx::R; #[doc = "Write proxy for field `ERRI`"] pub struct ERRI_W<'a> { w: &'a mut W, @@ -91,9 +91,9 @@ impl<'a> ERRI_W<'a> { } } #[doc = "Reader of field `SLAK`"] -pub type SLAK_R = crate::R; +pub type SLAK_R = crate::can::bx::R; #[doc = "Reader of field `INAK`"] -pub type INAK_R = crate::R; +pub type INAK_R = crate::can::bx::R; impl R { #[doc = "Bit 11 - RX"] #[inline(always)] diff --git a/embassy-stm32/src/can/bx/pac/can/rfr.rs b/embassy-stm32/src/can/bx/pac/can/rfr.rs index 6f5a960d1..1a4047cb4 100644 --- a/embassy-stm32/src/can/bx/pac/can/rfr.rs +++ b/embassy-stm32/src/can/bx/pac/can/rfr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register RF%sR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register RF%sR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register RF%sR `reset()`'s with value 0"] -impl crate::ResetValue for super::RFR { +impl crate::can::bx::ResetValue for super::RFR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -23,12 +23,12 @@ impl From for bool { } } #[doc = "Reader of field `RFOM`"] -pub type RFOM_R = crate::R; +pub type RFOM_R = crate::can::bx::R; impl RFOM_R { #[doc = r"Get enumerated values variant"] #[inline(always)] - pub fn variant(&self) -> crate::Variant { - use crate::Variant::*; + pub fn variant(&self) -> crate::can::bx::Variant { + use crate::can::bx::Variant::*; match self.bits { true => Val(RFOM_A::RELEASE), i => Res(i), @@ -89,7 +89,7 @@ impl From for bool { } } #[doc = "Reader of field `FOVR`"] -pub type FOVR_R = crate::R; +pub type FOVR_R = crate::can::bx::R; impl FOVR_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -171,7 +171,7 @@ impl From for bool { } } #[doc = "Reader of field `FULL`"] -pub type FULL_R = crate::R; +pub type FULL_R = crate::can::bx::R; impl FULL_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -239,7 +239,7 @@ impl<'a> FULL_W<'a> { } } #[doc = "Reader of field `FMP`"] -pub type FMP_R = crate::R; +pub type FMP_R = crate::can::bx::R; impl R { #[doc = "Bit 5 - RFOM0"] #[inline(always)] diff --git a/embassy-stm32/src/can/bx/pac/can/rx.rs b/embassy-stm32/src/can/bx/pac/can/rx.rs index dba344e7c..58ce7be4a 100644 --- a/embassy-stm32/src/can/bx/pac/can/rx.rs +++ b/embassy-stm32/src/can/bx/pac/can/rx.rs @@ -1,36 +1,36 @@ -#[doc = "CAN_RI0R\n\nThis register you can [`read`](crate::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rir](rir) module"] -pub type RIR = crate::Reg; +#[doc = "CAN_RI0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rir](rir) module"] +pub type RIR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _RIR; #[doc = "`read()` method returns [rir::R](rir::R) reader structure"] -impl crate::Readable for RIR {} +impl crate::can::bx::Readable for RIR {} #[doc = "CAN_RI0R"] pub mod rir; -#[doc = "CAN_RDT0R\n\nThis register you can [`read`](crate::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdtr](rdtr) module"] -pub type RDTR = crate::Reg; +#[doc = "CAN_RDT0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdtr](rdtr) module"] +pub type RDTR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _RDTR; #[doc = "`read()` method returns [rdtr::R](rdtr::R) reader structure"] -impl crate::Readable for RDTR {} +impl crate::can::bx::Readable for RDTR {} #[doc = "CAN_RDT0R"] pub mod rdtr; -#[doc = "CAN_RDL0R\n\nThis register you can [`read`](crate::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdlr](rdlr) module"] -pub type RDLR = crate::Reg; +#[doc = "CAN_RDL0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdlr](rdlr) module"] +pub type RDLR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _RDLR; #[doc = "`read()` method returns [rdlr::R](rdlr::R) reader structure"] -impl crate::Readable for RDLR {} +impl crate::can::bx::Readable for RDLR {} #[doc = "CAN_RDL0R"] pub mod rdlr; -#[doc = "CAN_RDH0R\n\nThis register you can [`read`](crate::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdhr](rdhr) module"] -pub type RDHR = crate::Reg; +#[doc = "CAN_RDH0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdhr](rdhr) module"] +pub type RDHR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _RDHR; #[doc = "`read()` method returns [rdhr::R](rdhr::R) reader structure"] -impl crate::Readable for RDHR {} +impl crate::can::bx::Readable for RDHR {} #[doc = "CAN_RDH0R"] pub mod rdhr; diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs index a0e6a52d0..0f3ccc307 100644 --- a/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs +++ b/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs @@ -1,13 +1,13 @@ #[doc = "Reader of register RDHR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Reader of field `DATA7`"] -pub type DATA7_R = crate::R; +pub type DATA7_R = crate::can::bx::R; #[doc = "Reader of field `DATA6`"] -pub type DATA6_R = crate::R; +pub type DATA6_R = crate::can::bx::R; #[doc = "Reader of field `DATA5`"] -pub type DATA5_R = crate::R; +pub type DATA5_R = crate::can::bx::R; #[doc = "Reader of field `DATA4`"] -pub type DATA4_R = crate::R; +pub type DATA4_R = crate::can::bx::R; impl R { #[doc = "Bits 24:31 - DATA7"] #[inline(always)] diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs index e61746669..16d739540 100644 --- a/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs +++ b/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs @@ -1,13 +1,13 @@ #[doc = "Reader of register RDLR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Reader of field `DATA3`"] -pub type DATA3_R = crate::R; +pub type DATA3_R = crate::can::bx::R; #[doc = "Reader of field `DATA2`"] -pub type DATA2_R = crate::R; +pub type DATA2_R = crate::can::bx::R; #[doc = "Reader of field `DATA1`"] -pub type DATA1_R = crate::R; +pub type DATA1_R = crate::can::bx::R; #[doc = "Reader of field `DATA0`"] -pub type DATA0_R = crate::R; +pub type DATA0_R = crate::can::bx::R; impl R { #[doc = "Bits 24:31 - DATA3"] #[inline(always)] diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs index 6778a7b4a..4a48e1f2e 100644 --- a/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs +++ b/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs @@ -1,11 +1,11 @@ #[doc = "Reader of register RDTR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Reader of field `TIME`"] -pub type TIME_R = crate::R; +pub type TIME_R = crate::can::bx::R; #[doc = "Reader of field `FMI`"] -pub type FMI_R = crate::R; +pub type FMI_R = crate::can::bx::R; #[doc = "Reader of field `DLC`"] -pub type DLC_R = crate::R; +pub type DLC_R = crate::can::bx::R; impl R { #[doc = "Bits 16:31 - TIME"] #[inline(always)] diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rir.rs b/embassy-stm32/src/can/bx/pac/can/rx/rir.rs index c0e4248f4..22e37b1cd 100644 --- a/embassy-stm32/src/can/bx/pac/can/rx/rir.rs +++ b/embassy-stm32/src/can/bx/pac/can/rx/rir.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register RIR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Reader of field `STID`"] -pub type STID_R = crate::R; +pub type STID_R = crate::can::bx::R; #[doc = "Reader of field `EXID`"] -pub type EXID_R = crate::R; +pub type EXID_R = crate::can::bx::R; #[doc = "IDE\n\nValue on reset: 0"] #[derive(Clone, Copy, Debug, PartialEq)] pub enum IDE_A { @@ -19,7 +19,7 @@ impl From for bool { } } #[doc = "Reader of field `IDE`"] -pub type IDE_R = crate::R; +pub type IDE_R = crate::can::bx::R; impl IDE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -55,7 +55,7 @@ impl From for bool { } } #[doc = "Reader of field `RTR`"] -pub type RTR_R = crate::R; +pub type RTR_R = crate::can::bx::R; impl RTR_R { #[doc = r"Get enumerated values variant"] #[inline(always)] diff --git a/embassy-stm32/src/can/bx/pac/can/tsr.rs b/embassy-stm32/src/can/bx/pac/can/tsr.rs index 2527b36a5..3317b7bd5 100644 --- a/embassy-stm32/src/can/bx/pac/can/tsr.rs +++ b/embassy-stm32/src/can/bx/pac/can/tsr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register TSR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register TSR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register TSR `reset()`'s with value 0"] -impl crate::ResetValue for super::TSR { +impl crate::can::bx::ResetValue for super::TSR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,21 +11,21 @@ impl crate::ResetValue for super::TSR { } } #[doc = "Reader of field `LOW2`"] -pub type LOW2_R = crate::R; +pub type LOW2_R = crate::can::bx::R; #[doc = "Reader of field `LOW1`"] -pub type LOW1_R = crate::R; +pub type LOW1_R = crate::can::bx::R; #[doc = "Reader of field `LOW0`"] -pub type LOW0_R = crate::R; +pub type LOW0_R = crate::can::bx::R; #[doc = "Reader of field `TME2`"] -pub type TME2_R = crate::R; +pub type TME2_R = crate::can::bx::R; #[doc = "Reader of field `TME1`"] -pub type TME1_R = crate::R; +pub type TME1_R = crate::can::bx::R; #[doc = "Reader of field `TME0`"] -pub type TME0_R = crate::R; +pub type TME0_R = crate::can::bx::R; #[doc = "Reader of field `CODE`"] -pub type CODE_R = crate::R; +pub type CODE_R = crate::can::bx::R; #[doc = "Reader of field `ABRQ2`"] -pub type ABRQ2_R = crate::R; +pub type ABRQ2_R = crate::can::bx::R; #[doc = "Write proxy for field `ABRQ2`"] pub struct ABRQ2_W<'a> { w: &'a mut W, @@ -49,7 +49,7 @@ impl<'a> ABRQ2_W<'a> { } } #[doc = "Reader of field `TERR2`"] -pub type TERR2_R = crate::R; +pub type TERR2_R = crate::can::bx::R; #[doc = "Write proxy for field `TERR2`"] pub struct TERR2_W<'a> { w: &'a mut W, @@ -73,7 +73,7 @@ impl<'a> TERR2_W<'a> { } } #[doc = "Reader of field `ALST2`"] -pub type ALST2_R = crate::R; +pub type ALST2_R = crate::can::bx::R; #[doc = "Write proxy for field `ALST2`"] pub struct ALST2_W<'a> { w: &'a mut W, @@ -97,7 +97,7 @@ impl<'a> ALST2_W<'a> { } } #[doc = "Reader of field `TXOK2`"] -pub type TXOK2_R = crate::R; +pub type TXOK2_R = crate::can::bx::R; #[doc = "Write proxy for field `TXOK2`"] pub struct TXOK2_W<'a> { w: &'a mut W, @@ -121,7 +121,7 @@ impl<'a> TXOK2_W<'a> { } } #[doc = "Reader of field `RQCP2`"] -pub type RQCP2_R = crate::R; +pub type RQCP2_R = crate::can::bx::R; #[doc = "Write proxy for field `RQCP2`"] pub struct RQCP2_W<'a> { w: &'a mut W, @@ -145,7 +145,7 @@ impl<'a> RQCP2_W<'a> { } } #[doc = "Reader of field `ABRQ1`"] -pub type ABRQ1_R = crate::R; +pub type ABRQ1_R = crate::can::bx::R; #[doc = "Write proxy for field `ABRQ1`"] pub struct ABRQ1_W<'a> { w: &'a mut W, @@ -169,7 +169,7 @@ impl<'a> ABRQ1_W<'a> { } } #[doc = "Reader of field `TERR1`"] -pub type TERR1_R = crate::R; +pub type TERR1_R = crate::can::bx::R; #[doc = "Write proxy for field `TERR1`"] pub struct TERR1_W<'a> { w: &'a mut W, @@ -193,7 +193,7 @@ impl<'a> TERR1_W<'a> { } } #[doc = "Reader of field `ALST1`"] -pub type ALST1_R = crate::R; +pub type ALST1_R = crate::can::bx::R; #[doc = "Write proxy for field `ALST1`"] pub struct ALST1_W<'a> { w: &'a mut W, @@ -217,7 +217,7 @@ impl<'a> ALST1_W<'a> { } } #[doc = "Reader of field `TXOK1`"] -pub type TXOK1_R = crate::R; +pub type TXOK1_R = crate::can::bx::R; #[doc = "Write proxy for field `TXOK1`"] pub struct TXOK1_W<'a> { w: &'a mut W, @@ -241,7 +241,7 @@ impl<'a> TXOK1_W<'a> { } } #[doc = "Reader of field `RQCP1`"] -pub type RQCP1_R = crate::R; +pub type RQCP1_R = crate::can::bx::R; #[doc = "Write proxy for field `RQCP1`"] pub struct RQCP1_W<'a> { w: &'a mut W, @@ -265,7 +265,7 @@ impl<'a> RQCP1_W<'a> { } } #[doc = "Reader of field `ABRQ0`"] -pub type ABRQ0_R = crate::R; +pub type ABRQ0_R = crate::can::bx::R; #[doc = "Write proxy for field `ABRQ0`"] pub struct ABRQ0_W<'a> { w: &'a mut W, @@ -289,7 +289,7 @@ impl<'a> ABRQ0_W<'a> { } } #[doc = "Reader of field `TERR0`"] -pub type TERR0_R = crate::R; +pub type TERR0_R = crate::can::bx::R; #[doc = "Write proxy for field `TERR0`"] pub struct TERR0_W<'a> { w: &'a mut W, @@ -313,7 +313,7 @@ impl<'a> TERR0_W<'a> { } } #[doc = "Reader of field `ALST0`"] -pub type ALST0_R = crate::R; +pub type ALST0_R = crate::can::bx::R; #[doc = "Write proxy for field `ALST0`"] pub struct ALST0_W<'a> { w: &'a mut W, @@ -337,7 +337,7 @@ impl<'a> ALST0_W<'a> { } } #[doc = "Reader of field `TXOK0`"] -pub type TXOK0_R = crate::R; +pub type TXOK0_R = crate::can::bx::R; #[doc = "Write proxy for field `TXOK0`"] pub struct TXOK0_W<'a> { w: &'a mut W, @@ -361,7 +361,7 @@ impl<'a> TXOK0_W<'a> { } } #[doc = "Reader of field `RQCP0`"] -pub type RQCP0_R = crate::R; +pub type RQCP0_R = crate::can::bx::R; #[doc = "Write proxy for field `RQCP0`"] pub struct RQCP0_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/tx.rs b/embassy-stm32/src/can/bx/pac/can/tx.rs index 7b926bd14..f45eb47cc 100644 --- a/embassy-stm32/src/can/bx/pac/can/tx.rs +++ b/embassy-stm32/src/can/bx/pac/can/tx.rs @@ -1,44 +1,44 @@ -#[doc = "CAN_TI0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tir](tir) module"] -pub type TIR = crate::Reg; +#[doc = "CAN_TI0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tir](tir) module"] +pub type TIR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _TIR; #[doc = "`read()` method returns [tir::R](tir::R) reader structure"] -impl crate::Readable for TIR {} +impl crate::can::bx::Readable for TIR {} #[doc = "`write(|w| ..)` method takes [tir::W](tir::W) writer structure"] -impl crate::Writable for TIR {} +impl crate::can::bx::Writable for TIR {} #[doc = "CAN_TI0R"] pub mod tir; -#[doc = "CAN_TDT0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdtr](tdtr) module"] -pub type TDTR = crate::Reg; +#[doc = "CAN_TDT0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdtr](tdtr) module"] +pub type TDTR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _TDTR; #[doc = "`read()` method returns [tdtr::R](tdtr::R) reader structure"] -impl crate::Readable for TDTR {} +impl crate::can::bx::Readable for TDTR {} #[doc = "`write(|w| ..)` method takes [tdtr::W](tdtr::W) writer structure"] -impl crate::Writable for TDTR {} +impl crate::can::bx::Writable for TDTR {} #[doc = "CAN_TDT0R"] pub mod tdtr; -#[doc = "CAN_TDL0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdlr](tdlr) module"] -pub type TDLR = crate::Reg; +#[doc = "CAN_TDL0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdlr](tdlr) module"] +pub type TDLR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _TDLR; #[doc = "`read()` method returns [tdlr::R](tdlr::R) reader structure"] -impl crate::Readable for TDLR {} +impl crate::can::bx::Readable for TDLR {} #[doc = "`write(|w| ..)` method takes [tdlr::W](tdlr::W) writer structure"] -impl crate::Writable for TDLR {} +impl crate::can::bx::Writable for TDLR {} #[doc = "CAN_TDL0R"] pub mod tdlr; -#[doc = "CAN_TDH0R\n\nThis register you can [`read`](crate::generic::Reg::read), [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero), [`modify`](crate::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdhr](tdhr) module"] -pub type TDHR = crate::Reg; +#[doc = "CAN_TDH0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdhr](tdhr) module"] +pub type TDHR = crate::can::bx::Reg; #[allow(missing_docs)] #[doc(hidden)] pub struct _TDHR; #[doc = "`read()` method returns [tdhr::R](tdhr::R) reader structure"] -impl crate::Readable for TDHR {} +impl crate::can::bx::Readable for TDHR {} #[doc = "`write(|w| ..)` method takes [tdhr::W](tdhr::W) writer structure"] -impl crate::Writable for TDHR {} +impl crate::can::bx::Writable for TDHR {} #[doc = "CAN_TDH0R"] pub mod tdhr; diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs index 240fa94f0..9c2209b99 100644 --- a/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs +++ b/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register TDHR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register TDHR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register TDHR `reset()`'s with value 0"] -impl crate::ResetValue for super::TDHR { +impl crate::can::bx::ResetValue for super::TDHR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::TDHR { } } #[doc = "Reader of field `DATA7`"] -pub type DATA7_R = crate::R; +pub type DATA7_R = crate::can::bx::R; #[doc = "Write proxy for field `DATA7`"] pub struct DATA7_W<'a> { w: &'a mut W, @@ -25,7 +25,7 @@ impl<'a> DATA7_W<'a> { } } #[doc = "Reader of field `DATA6`"] -pub type DATA6_R = crate::R; +pub type DATA6_R = crate::can::bx::R; #[doc = "Write proxy for field `DATA6`"] pub struct DATA6_W<'a> { w: &'a mut W, @@ -39,7 +39,7 @@ impl<'a> DATA6_W<'a> { } } #[doc = "Reader of field `DATA5`"] -pub type DATA5_R = crate::R; +pub type DATA5_R = crate::can::bx::R; #[doc = "Write proxy for field `DATA5`"] pub struct DATA5_W<'a> { w: &'a mut W, @@ -53,7 +53,7 @@ impl<'a> DATA5_W<'a> { } } #[doc = "Reader of field `DATA4`"] -pub type DATA4_R = crate::R; +pub type DATA4_R = crate::can::bx::R; #[doc = "Write proxy for field `DATA4`"] pub struct DATA4_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs index c4c855d46..d67589f99 100644 --- a/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs +++ b/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register TDLR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register TDLR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register TDLR `reset()`'s with value 0"] -impl crate::ResetValue for super::TDLR { +impl crate::can::bx::ResetValue for super::TDLR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::TDLR { } } #[doc = "Reader of field `DATA3`"] -pub type DATA3_R = crate::R; +pub type DATA3_R = crate::can::bx::R; #[doc = "Write proxy for field `DATA3`"] pub struct DATA3_W<'a> { w: &'a mut W, @@ -25,7 +25,7 @@ impl<'a> DATA3_W<'a> { } } #[doc = "Reader of field `DATA2`"] -pub type DATA2_R = crate::R; +pub type DATA2_R = crate::can::bx::R; #[doc = "Write proxy for field `DATA2`"] pub struct DATA2_W<'a> { w: &'a mut W, @@ -39,7 +39,7 @@ impl<'a> DATA2_W<'a> { } } #[doc = "Reader of field `DATA1`"] -pub type DATA1_R = crate::R; +pub type DATA1_R = crate::can::bx::R; #[doc = "Write proxy for field `DATA1`"] pub struct DATA1_W<'a> { w: &'a mut W, @@ -53,7 +53,7 @@ impl<'a> DATA1_W<'a> { } } #[doc = "Reader of field `DATA0`"] -pub type DATA0_R = crate::R; +pub type DATA0_R = crate::can::bx::R; #[doc = "Write proxy for field `DATA0`"] pub struct DATA0_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs index 310bca497..cf748ba29 100644 --- a/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs +++ b/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register TDTR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register TDTR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register TDTR `reset()`'s with value 0"] -impl crate::ResetValue for super::TDTR { +impl crate::can::bx::ResetValue for super::TDTR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::TDTR { } } #[doc = "Reader of field `TIME`"] -pub type TIME_R = crate::R; +pub type TIME_R = crate::can::bx::R; #[doc = "Write proxy for field `TIME`"] pub struct TIME_W<'a> { w: &'a mut W, @@ -25,7 +25,7 @@ impl<'a> TIME_W<'a> { } } #[doc = "Reader of field `TGT`"] -pub type TGT_R = crate::R; +pub type TGT_R = crate::can::bx::R; #[doc = "Write proxy for field `TGT`"] pub struct TGT_W<'a> { w: &'a mut W, @@ -49,7 +49,7 @@ impl<'a> TGT_W<'a> { } } #[doc = "Reader of field `DLC`"] -pub type DLC_R = crate::R; +pub type DLC_R = crate::can::bx::R; #[doc = "Write proxy for field `DLC`"] pub struct DLC_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tir.rs b/embassy-stm32/src/can/bx/pac/can/tx/tir.rs index 12bc3d1f3..2d2dd0ca7 100644 --- a/embassy-stm32/src/can/bx/pac/can/tx/tir.rs +++ b/embassy-stm32/src/can/bx/pac/can/tx/tir.rs @@ -1,9 +1,9 @@ #[doc = "Reader of register TIR"] -pub type R = crate::R; +pub type R = crate::can::bx::R; #[doc = "Writer for register TIR"] -pub type W = crate::W; +pub type W = crate::can::bx::W; #[doc = "Register TIR `reset()`'s with value 0"] -impl crate::ResetValue for super::TIR { +impl crate::can::bx::ResetValue for super::TIR { type Type = u32; #[inline(always)] fn reset_value() -> Self::Type { @@ -11,7 +11,7 @@ impl crate::ResetValue for super::TIR { } } #[doc = "Reader of field `STID`"] -pub type STID_R = crate::R; +pub type STID_R = crate::can::bx::R; #[doc = "Write proxy for field `STID`"] pub struct STID_W<'a> { w: &'a mut W, @@ -25,7 +25,7 @@ impl<'a> STID_W<'a> { } } #[doc = "Reader of field `EXID`"] -pub type EXID_R = crate::R; +pub type EXID_R = crate::can::bx::R; #[doc = "Write proxy for field `EXID`"] pub struct EXID_W<'a> { w: &'a mut W, @@ -53,7 +53,7 @@ impl From for bool { } } #[doc = "Reader of field `IDE`"] -pub type IDE_R = crate::R; +pub type IDE_R = crate::can::bx::R; impl IDE_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -128,7 +128,7 @@ impl From for bool { } } #[doc = "Reader of field `RTR`"] -pub type RTR_R = crate::R; +pub type RTR_R = crate::can::bx::R; impl RTR_R { #[doc = r"Get enumerated values variant"] #[inline(always)] @@ -189,7 +189,7 @@ impl<'a> RTR_W<'a> { } } #[doc = "Reader of field `TXRQ`"] -pub type TXRQ_R = crate::R; +pub type TXRQ_R = crate::can::bx::R; #[doc = "Write proxy for field `TXRQ`"] pub struct TXRQ_W<'a> { w: &'a mut W, diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 7e00eca6f..cd394c951 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -4,8 +4,9 @@ use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::task::Poll; -pub use bxcan; -use bxcan::{Data, ExtendedId, Frame, Id, StandardId}; +pub mod bx; + +use bx::{Data, ExtendedId, Frame, Id, StandardId}; use embassy_hal_internal::{into_ref, PeripheralRef}; use futures::FutureExt; @@ -29,7 +30,7 @@ pub struct Envelope { #[cfg(feature = "time")] pub ts: embassy_time::Instant, /// The actual CAN frame. - pub frame: bxcan::Frame, + pub frame: crate::can::bx::Frame, } /// Interrupt handler. @@ -93,7 +94,7 @@ impl interrupt::typelevel::Handler for SceInterrup /// CAN driver pub struct Can<'d, T: Instance> { - can: bxcan::Can>, + can: crate::can::bx::Can>, } /// Error returned by `try_read` @@ -166,7 +167,7 @@ impl<'d, T: Instance> Can<'d, T> { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); + let can = crate::can::bx::Can::builder(BxcanInstance(peri)).leave_disabled(); Self { can } } @@ -198,19 +199,19 @@ impl<'d, T: Instance> Can<'d, T> { /// Queues the message to be sent. /// /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. - pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { + pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { self.split().0.write(frame).await } /// Attempts to transmit a frame without blocking. /// /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. - pub fn try_write(&mut self, frame: &Frame) -> Result { + pub fn try_write(&mut self, frame: &Frame) -> Result { self.split().0.try_write(frame) } /// Waits for a specific transmit mailbox to become empty - pub async fn flush(&self, mb: bxcan::Mailbox) { + pub async fn flush(&self, mb: crate::can::bx::Mailbox) { CanTx::::flush_inner(mb).await } @@ -304,23 +305,23 @@ impl<'d, T: Instance> Can<'d, T> { } } -impl<'d, T: Instance> AsMut>> for Can<'d, T> { +impl<'d, T: Instance> AsMut>> for Can<'d, T> { /// Get mutable access to the lower-level driver from the `bxcan` crate. - fn as_mut(&mut self) -> &mut bxcan::Can> { + fn as_mut(&mut self) -> &mut crate::can::bx::Can> { &mut self.can } } /// CAN driver, transmit half. pub struct CanTx<'c, 'd, T: Instance> { - tx: &'c mut bxcan::Tx>, + tx: &'c mut crate::can::bx::Tx>, } impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { /// Queues the message to be sent. /// /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. - pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { + pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { poll_fn(|cx| { T::state().tx_waker.register(cx.waker()); if let Ok(status) = self.tx.transmit(frame) { @@ -335,11 +336,11 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { /// Attempts to transmit a frame without blocking. /// /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. - pub fn try_write(&mut self, frame: &Frame) -> Result { + pub fn try_write(&mut self, frame: &Frame) -> Result { self.tx.transmit(frame).map_err(|_| TryWriteError::Full) } - async fn flush_inner(mb: bxcan::Mailbox) { + async fn flush_inner(mb: crate::can::bx::Mailbox) { poll_fn(|cx| { T::state().tx_waker.register(cx.waker()); if T::regs().tsr().read().tme(mb.index()) { @@ -352,7 +353,7 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { } /// Waits for a specific transmit mailbox to become empty - pub async fn flush(&self, mb: bxcan::Mailbox) { + pub async fn flush(&self, mb: crate::can::bx::Mailbox) { Self::flush_inner(mb).await } @@ -361,9 +362,9 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { T::state().tx_waker.register(cx.waker()); let tsr = T::regs().tsr().read(); - if tsr.tme(bxcan::Mailbox::Mailbox0.index()) - || tsr.tme(bxcan::Mailbox::Mailbox1.index()) - || tsr.tme(bxcan::Mailbox::Mailbox2.index()) + if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) + || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) + || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) { return Poll::Ready(()); } @@ -383,9 +384,9 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { T::state().tx_waker.register(cx.waker()); let tsr = T::regs().tsr().read(); - if tsr.tme(bxcan::Mailbox::Mailbox0.index()) - && tsr.tme(bxcan::Mailbox::Mailbox1.index()) - && tsr.tme(bxcan::Mailbox::Mailbox2.index()) + if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) + && tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) + && tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) { return Poll::Ready(()); } @@ -404,8 +405,8 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { /// CAN driver, receive half. #[allow(dead_code)] pub struct CanRx<'c, 'd, T: Instance> { - rx0: &'c mut bxcan::Rx0>, - rx1: &'c mut bxcan::Rx1>, + rx0: &'c mut crate::can::bx::Rx0>, + rx1: &'c mut crate::can::bx::Rx1>, } impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { @@ -478,7 +479,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> { } impl<'d, T: Instance> Deref for Can<'d, T> { - type Target = bxcan::Can>; + type Target = crate::can::bx::Can>; fn deref(&self) -> &Self::Target { &self.can @@ -515,7 +516,7 @@ pub(crate) mod sealed { } pub trait Instance { - const REGISTERS: *mut bxcan::RegisterBlock; + const REGISTERS: *mut crate::can::bx::RegisterBlock; fn regs() -> crate::pac::can::Can; fn state() -> &'static State; @@ -537,14 +538,14 @@ pub trait Instance: sealed::Instance + RccPeripheral + 'static { /// BXCAN instance newtype. pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); -unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { - const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS; +unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> { + const REGISTERS: *mut crate::can::bx::RegisterBlock = T::REGISTERS; } foreach_peripheral!( (can, $inst:ident) => { impl sealed::Instance for peripherals::$inst { - const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; + const REGISTERS: *mut crate::can::bx::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; fn regs() -> crate::pac::can::Can { crate::pac::$inst @@ -567,7 +568,7 @@ foreach_peripheral!( foreach_peripheral!( (can, CAN) => { - unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN> { + unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN> { const NUM_FILTER_BANKS: u8 = 14; } }; @@ -582,19 +583,19 @@ foreach_peripheral!( ))] { // Most L4 devices and some F7 devices use the name "CAN1" // even if there is no "CAN2" peripheral. - unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { + unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { const NUM_FILTER_BANKS: u8 = 14; } } else { - unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { + unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { const NUM_FILTER_BANKS: u8 = 28; } - unsafe impl<'d> bxcan::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {} + unsafe impl<'d> crate::can::bx::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {} } } }; (can, CAN3) => { - unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN3> { + unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN3> { const NUM_FILTER_BANKS: u8 = 14; } }; @@ -607,12 +608,12 @@ trait Index { fn index(&self) -> usize; } -impl Index for bxcan::Mailbox { +impl Index for crate::can::bx::Mailbox { fn index(&self) -> usize { match self { - bxcan::Mailbox::Mailbox0 => 0, - bxcan::Mailbox::Mailbox1 => 1, - bxcan::Mailbox::Mailbox2 => 2, + crate::can::bx::Mailbox::Mailbox0 => 0, + crate::can::bx::Mailbox::Mailbox1 => 1, + crate::can::bx::Mailbox::Mailbox2 => 2, } } } diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index c1c4f8359..176fc888f 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::can::bxcan::filter::Mask32; -use embassy_stm32::can::bxcan::{Fifo, Frame, Id, StandardId}; +use embassy_stm32::can::bx::filter::Mask32; +use embassy_stm32::can::bx::{Fifo, Frame, Id, StandardId}; use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; use embassy_stm32::peripherals::CAN; use embassy_stm32::{bind_interrupts, Config}; diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index f4effa244..e869e8fb9 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -9,8 +9,8 @@ use common::*; use defmt::assert; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; -use embassy_stm32::can::bxcan::filter::Mask32; -use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; +use embassy_stm32::can::bx::filter::Mask32; +use embassy_stm32::can::bx::{Fifo, Frame, StandardId}; use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN1; From 34687a0956f4bd6a736dcf9748eaa98040dfddae Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 3 Mar 2024 16:53:31 +1000 Subject: [PATCH 645/760] Apply cargo fmt Formatting. --- embassy-stm32/src/can/bx/filter.rs | 22 ++------ embassy-stm32/src/can/bx/frame.rs | 10 +--- embassy-stm32/src/can/bx/mod.rs | 90 +++++++++--------------------- 3 files changed, 32 insertions(+), 90 deletions(-) diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bx/filter.rs index 0213e0f44..c149d37ea 100644 --- a/embassy-stm32/src/can/bx/filter.rs +++ b/embassy-stm32/src/can/bx/filter.rs @@ -286,12 +286,7 @@ impl MasterFilters<'_, I> { /// - `index`: the filter index. /// - `fifo`: the receive FIFO the filter should pass accepted messages to. /// - `config`: the filter configuration. - pub fn enable_bank( - &mut self, - index: u8, - fifo: Fifo, - config: impl Into, - ) -> &mut Self { + pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into) -> &mut Self { self.banks_imm().enable(index, fifo, config.into()); self } @@ -380,12 +375,7 @@ impl SlaveFilters<'_, I> { /// - `index`: the filter index. /// - `fifo`: the receive FIFO the filter should pass accepted messages to. /// - `config`: the filter configuration. - pub fn enable_bank( - &mut self, - index: u8, - fifo: Fifo, - config: impl Into, - ) -> &mut Self { + pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into) -> &mut Self { self.banks_imm().enable(index, fifo, config.into()); self } @@ -415,9 +405,7 @@ impl FilterBanks<'_> { fn disable(&mut self, index: u8) { self.assert_bank_index(index); - self.can - .fa1r - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << index)) }) + self.can.fa1r.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << index)) }) } fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) { @@ -482,9 +470,7 @@ impl FilterBanks<'_> { }); // Set active. - self.can - .fa1r - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << index)) }) + self.can.fa1r.modify(|r, w| unsafe { w.bits(r.bits() | (1 << index)) }) } } diff --git a/embassy-stm32/src/can/bx/frame.rs b/embassy-stm32/src/can/bx/frame.rs index a7e8d5b20..2a51d1b15 100644 --- a/embassy-stm32/src/can/bx/frame.rs +++ b/embassy-stm32/src/can/bx/frame.rs @@ -22,10 +22,7 @@ impl Frame { Id::Extended(id) => IdReg::new_extended(id), }; - Self { - id, - data: data.into(), - } + Self { id, data: data.into() } } /// Creates a new remote frame with configurable data length code (DLC). @@ -182,10 +179,7 @@ impl Data { /// Creates an empty data payload containing 0 bytes. #[inline] pub const fn empty() -> Self { - Self { - len: 0, - bytes: [0; 8], - } + Self { len: 0, bytes: [0; 8] } } } diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 2789d1ff9..d6e023217 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -19,21 +19,8 @@ //! //! - Support for querying error states and handling error interrupts is incomplete. //! -//! # Cargo Features -//! -//! | Feature | Description | -//! |---------|-------------| -//! | `defmt` | Implements [`defmt`]'s `Format` trait for the types in this crate.[^1] | -//! -//! [^1]: The specific version of defmt is unspecified and may be updated in a patch release. -//! -//! [`defmt`]: https://docs.rs/defmt -//! [`embedded-hal`]: https://docs.rs/embedded-hal -#![doc(html_root_url = "https://docs.rs/bxcan/0.7.0")] // Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default -#![doc(test(attr(deny(unused_imports, unused_must_use))))] -#![no_std] #![allow(clippy::unnecessary_operation)] // lint is bugged //mod embedded_hal; @@ -45,20 +32,19 @@ mod interrupt; #[allow(clippy::all)] // generated code mod pac; -pub use id::{ExtendedId, Id, StandardId}; - -pub use crate::can::bx::frame::{Data, Frame, FramePriority}; -pub use crate::can::bx::interrupt::{Interrupt, Interrupts}; -pub use crate::can::bx::pac::can::RegisterBlock; - -use crate::can::bx::filter::MasterFilters; use core::cmp::{Ord, Ordering}; use core::convert::{Infallible, TryInto}; use core::marker::PhantomData; use core::mem; use core::ptr::NonNull; -use self::pac::generic::*; // To make the PAC extraction build +pub use id::{ExtendedId, Id, StandardId}; + +use self::pac::generic::*; +use crate::can::bx::filter::MasterFilters; +pub use crate::can::bx::frame::{Data, Frame, FramePriority}; +pub use crate::can::bx::interrupt::{Interrupt, Interrupts}; +pub use crate::can::bx::pac::can::RegisterBlock; // To make the PAC extraction build /// A bxCAN peripheral instance. /// @@ -186,9 +172,7 @@ impl IdReg { if self.is_extended() { Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) } else { - Id::Standard(unsafe { - StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) - }) + Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) }) } } @@ -229,12 +213,9 @@ impl Ord for IdReg { .reverse() .then(Ordering::Greater) } - (Id::Extended(a), Id::Standard(b)) => a - .standard_id() - .as_raw() - .cmp(&b.as_raw()) - .reverse() - .then(Ordering::Less), + (Id::Extended(a), Id::Standard(b)) => { + a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less) + } } } } @@ -326,8 +307,7 @@ impl CanConfig<'_, I> { /// Leaves initialization mode, enters sleep mode. fn leave_init_mode(&mut self) { let can = self.can.registers(); - can.mcr - .modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + can.mcr.modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); loop { let msr = can.msr.read(); if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { @@ -426,8 +406,7 @@ impl CanBuilder { /// Leaves initialization mode, enters sleep mode. fn leave_init_mode(&mut self) { let can = self.can.registers(); - can.mcr - .modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + can.mcr.modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); loop { let msr = can.msr.read(); if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { @@ -448,15 +427,11 @@ where { /// Creates a [`CanBuilder`] for constructing a CAN interface. pub fn builder(instance: I) -> CanBuilder { - let can_builder = CanBuilder { - can: Can { instance }, - }; + let can_builder = CanBuilder { can: Can { instance } }; let can_reg = can_builder.can.registers(); // Enter init mode. - can_reg - .mcr - .modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); + can_reg.mcr.modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); loop { let msr = can_reg.msr.read(); if msr.slak().bit_is_clear() && msr.inak().bit_is_set() { @@ -505,8 +480,7 @@ where let can = self.registers(); // Enter init mode. - can.mcr - .modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); + can.mcr.modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); loop { let msr = can.msr.read(); if msr.slak().bit_is_clear() && msr.inak().bit_is_set() { @@ -541,8 +515,7 @@ where let can = self.registers(); let msr = can.msr.read(); if msr.slak().bit_is_set() { - can.mcr - .modify(|_, w| w.abom().set_bit().sleep().clear_bit()); + can.mcr.modify(|_, w| w.abom().set_bit().sleep().clear_bit()); Err(nb::Error::WouldBlock) } else { Ok(()) @@ -554,8 +527,7 @@ where /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. pub fn sleep(&mut self) { let can = self.registers(); - can.mcr - .modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + can.mcr.modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); loop { let msr = can.msr.read(); if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { @@ -570,8 +542,7 @@ where /// frame will cause that interrupt. pub fn wakeup(&mut self) { let can = self.registers(); - can.mcr - .modify(|_, w| w.sleep().clear_bit().inrq().clear_bit()); + can.mcr.modify(|_, w| w.sleep().clear_bit().inrq().clear_bit()); loop { let msr = can.msr.read(); if msr.slak().bit_is_clear() && msr.inak().bit_is_clear() { @@ -791,8 +762,7 @@ where let tsr = can.tsr.read(); let idx = tsr.code().bits() as usize; - let frame_is_pending = - tsr.tme0().bit_is_clear() || tsr.tme1().bit_is_clear() || tsr.tme2().bit_is_clear(); + let frame_is_pending = tsr.tme0().bit_is_clear() || tsr.tme1().bit_is_clear() || tsr.tme2().bit_is_clear(); let pending_frame = if frame_is_pending { // High priority frames are transmitted first by the mailbox system. // Frames with identical identifier shall be transmitted in FIFO order. @@ -860,20 +830,12 @@ where debug_assert!(idx < 3); let mb = unsafe { &can.tx.get_unchecked(idx) }; - mb.tdtr - .write(|w| unsafe { w.dlc().bits(frame.dlc() as u8) }); - mb.tdlr.write(|w| unsafe { - w.bits(u32::from_ne_bytes( - frame.data.bytes[0..4].try_into().unwrap(), - )) - }); - mb.tdhr.write(|w| unsafe { - w.bits(u32::from_ne_bytes( - frame.data.bytes[4..8].try_into().unwrap(), - )) - }); - mb.tir - .write(|w| unsafe { w.bits(frame.id.0).txrq().set_bit() }); + mb.tdtr.write(|w| unsafe { w.dlc().bits(frame.dlc() as u8) }); + mb.tdlr + .write(|w| unsafe { w.bits(u32::from_ne_bytes(frame.data.bytes[0..4].try_into().unwrap())) }); + mb.tdhr + .write(|w| unsafe { w.bits(u32::from_ne_bytes(frame.data.bytes[4..8].try_into().unwrap())) }); + mb.tir.write(|w| unsafe { w.bits(frame.id.0).txrq().set_bit() }); } fn read_pending_mailbox(&mut self, idx: usize) -> Option { From b0f05e768225ae321cb08a469fa4a384cb8523ab Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 3 Mar 2024 20:45:51 +1000 Subject: [PATCH 646/760] Remove unused. --- embassy-stm32/src/can/bx/interrupt.rs | 130 -------------------------- embassy-stm32/src/can/bx/mod.rs | 72 -------------- 2 files changed, 202 deletions(-) delete mode 100644 embassy-stm32/src/can/bx/interrupt.rs diff --git a/embassy-stm32/src/can/bx/interrupt.rs b/embassy-stm32/src/can/bx/interrupt.rs deleted file mode 100644 index dac4b7b3c..000000000 --- a/embassy-stm32/src/can/bx/interrupt.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Interrupt types. - -use core::ops; - -#[allow(unused_imports)] // for intra-doc links only -use crate::can::bx::{Can, Rx0}; - -/// bxCAN interrupt sources. -/// -/// These can be individually enabled and disabled in the bxCAN peripheral. Note that the bxCAN -/// peripheral only exposes 4 interrupts to the microcontroller: -/// -/// * TX -/// * RX FIFO 1 -/// * RX FIFO 2 -/// * SCE (Status Change Error) -/// -/// This means that some of the interrupts listed here will result in the same interrupt handler -/// being invoked. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Interrupt { - /// Fires the **TX** interrupt when one of the transmit mailboxes returns to empty state. - /// - /// This usually happens because its message was either transmitted successfully, or - /// transmission was aborted successfully. - /// - /// The interrupt handler must clear the interrupt condition by calling - /// [`Can::clear_request_completed_flag`] or [`Can::clear_tx_interrupt`]. - TransmitMailboxEmpty = 1 << 0, - - /// Fires the **RX FIFO 0** interrupt when FIFO 0 holds a message. - /// - /// The interrupt handler must clear the interrupt condition by receiving all messages from the - /// FIFO by calling [`Can::receive`] or [`Rx0::receive`]. - Fifo0MessagePending = 1 << 1, - - /// Fires the **RX FIFO 0** interrupt when FIFO 0 holds 3 incoming messages. - /// - /// The interrupt handler must clear the interrupt condition by receiving at least one message - /// from the FIFO (making it no longer "full"). This can be done by calling [`Can::receive`] or - /// [`Rx0::receive`]. - Fifo0Full = 1 << 2, - - /// Fires the **RX FIFO 0** interrupt when FIFO 0 drops an incoming message. - /// - /// The interrupt handler must clear the interrupt condition by calling [`Can::receive`] or - /// [`Rx0::receive`] (which will return an error). - Fifo0Overrun = 1 << 3, - - /// Fires the **RX FIFO 1** interrupt when FIFO 1 holds a message. - /// - /// Behavior is otherwise identical to [`Self::Fifo0MessagePending`]. - Fifo1MessagePending = 1 << 4, - - /// Fires the **RX FIFO 1** interrupt when FIFO 1 holds 3 incoming messages. - /// - /// Behavior is otherwise identical to [`Self::Fifo0Full`]. - Fifo1Full = 1 << 5, - - /// Fires the **RX FIFO 1** interrupt when FIFO 1 drops an incoming message. - /// - /// Behavior is otherwise identical to [`Self::Fifo0Overrun`]. - Fifo1Overrun = 1 << 6, - - Error = 1 << 15, - - /// Fires the **SCE** interrupt when an incoming CAN frame is detected while the peripheral is - /// in sleep mode. - /// - /// The interrupt handler must clear the interrupt condition by calling - /// [`Can::clear_wakeup_interrupt`]. - Wakeup = 1 << 16, - - /// Fires the **SCE** interrupt when the peripheral enters sleep mode. - /// - /// The interrupt handler must clear the interrupt condition by calling - /// [`Can::clear_sleep_interrupt`]. - Sleep = 1 << 17, -} - -bitflags::bitflags! { - /// A set of bxCAN interrupts. - pub struct Interrupts: u32 { - const TRANSMIT_MAILBOX_EMPTY = 1 << 0; - const FIFO0_MESSAGE_PENDING = 1 << 1; - const FIFO0_FULL = 1 << 2; - const FIFO0_OVERRUN = 1 << 3; - const FIFO1_MESSAGE_PENDING = 1 << 4; - const FIFO1_FULL = 1 << 5; - const FIFO1_OVERRUN = 1 << 6; - const ERROR = 1 << 15; - const WAKEUP = 1 << 16; - const SLEEP = 1 << 17; - } -} - -impl From for Interrupts { - #[inline] - fn from(i: Interrupt) -> Self { - Self::from_bits_truncate(i as u32) - } -} - -/// Adds an interrupt to the interrupt set. -impl ops::BitOrAssign for Interrupts { - #[inline] - fn bitor_assign(&mut self, rhs: Interrupt) { - *self |= Self::from(rhs); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn interrupt_flags() { - assert_eq!(Interrupts::from(Interrupt::Sleep), Interrupts::SLEEP); - assert_eq!( - Interrupts::from(Interrupt::TransmitMailboxEmpty), - Interrupts::TRANSMIT_MAILBOX_EMPTY - ); - - let mut ints = Interrupts::FIFO0_FULL; - ints |= Interrupt::Fifo1Full; - assert_eq!(ints, Interrupts::FIFO0_FULL | Interrupts::FIFO1_FULL); - } -} diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index d6e023217..c5801abec 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -27,7 +27,6 @@ pub mod filter; mod frame; mod id; -mod interrupt; #[allow(clippy::all)] // generated code mod pac; @@ -43,7 +42,6 @@ pub use id::{ExtendedId, Id, StandardId}; use self::pac::generic::*; use crate::can::bx::filter::MasterFilters; pub use crate::can::bx::frame::{Data, Frame, FramePriority}; -pub use crate::can::bx::interrupt::{Interrupt, Interrupts}; pub use crate::can::bx::pac::can::RegisterBlock; // To make the PAC extraction build /// A bxCAN peripheral instance. @@ -551,76 +549,6 @@ where } } - /// Starts listening for a CAN interrupt. - pub fn enable_interrupt(&mut self, interrupt: Interrupt) { - self.enable_interrupts(Interrupts::from_bits_truncate(interrupt as u32)) - } - - /// Starts listening for a set of CAN interrupts. - pub fn enable_interrupts(&mut self, interrupts: Interrupts) { - self.registers() - .ier - .modify(|r, w| unsafe { w.bits(r.bits() | interrupts.bits()) }) - } - - /// Stops listening for a CAN interrupt. - pub fn disable_interrupt(&mut self, interrupt: Interrupt) { - self.disable_interrupts(Interrupts::from_bits_truncate(interrupt as u32)) - } - - /// Stops listening for a set of CAN interrupts. - pub fn disable_interrupts(&mut self, interrupts: Interrupts) { - self.registers() - .ier - .modify(|r, w| unsafe { w.bits(r.bits() & !interrupts.bits()) }) - } - - /// Clears the pending flag of [`Interrupt::Sleep`]. - pub fn clear_sleep_interrupt(&self) { - let can = self.registers(); - // Read-only register with write-1-to-clear, so `&self` is sufficient. - can.msr.write(|w| w.slaki().set_bit()); - } - - /// Clears the pending flag of [`Interrupt::Wakeup`]. - pub fn clear_wakeup_interrupt(&self) { - let can = self.registers(); - // Read-only register with write-1-to-clear, so `&self` is sufficient. - can.msr.write(|w| w.wkui().set_bit()); - } - - /// Clears the "Request Completed" (RQCP) flag of a transmit mailbox. - /// - /// Returns the [`Mailbox`] whose flag was cleared. If no mailbox has the flag set, returns - /// `None`. - /// - /// Once this function returns `None`, a pending [`Interrupt::TransmitMailboxEmpty`] is - /// considered acknowledged. - pub fn clear_request_completed_flag(&mut self) -> Option { - let can = self.registers(); - let tsr = can.tsr.read(); - if tsr.rqcp0().bit_is_set() { - can.tsr.modify(|_, w| w.rqcp0().set_bit()); - Some(Mailbox::Mailbox0) - } else if tsr.rqcp1().bit_is_set() { - can.tsr.modify(|_, w| w.rqcp1().set_bit()); - Some(Mailbox::Mailbox1) - } else if tsr.rqcp2().bit_is_set() { - can.tsr.modify(|_, w| w.rqcp2().set_bit()); - Some(Mailbox::Mailbox2) - } else { - None - } - } - - /// Clears a pending TX interrupt ([`Interrupt::TransmitMailboxEmpty`]). - /// - /// This does not return the mailboxes that have finished tranmission. If you need that - /// information, call [`Can::clear_request_completed_flag`] instead. - pub fn clear_tx_interrupt(&mut self) { - while self.clear_request_completed_flag().is_some() {} - } - /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. /// /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). From 455cc40261884b0a358e775fd4f411fa77ce27c9 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 3 Mar 2024 20:27:08 +1000 Subject: [PATCH 647/760] Port registers access to using Embassy PAC Use stm32-metapac for filters module. --- embassy-stm32/src/can/bx/filter.rs | 99 +++----- embassy-stm32/src/can/bx/frame.rs | 1 - embassy-stm32/src/can/bx/mod.rs | 370 +++++++++++++---------------- embassy-stm32/src/can/bxcan.rs | 27 +-- 4 files changed, 218 insertions(+), 279 deletions(-) diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bx/filter.rs index c149d37ea..64f020fc7 100644 --- a/embassy-stm32/src/can/bx/filter.rs +++ b/embassy-stm32/src/can/bx/filter.rs @@ -2,7 +2,6 @@ use core::marker::PhantomData; -use crate::can::bx::pac::can::RegisterBlock; use crate::can::bx::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames @@ -213,19 +212,18 @@ pub struct MasterFilters<'a, I: FilterOwner> { /// On chips with splittable filter banks, this value can be dynamic. bank_count: u8, _can: PhantomData<&'a mut I>, + canregs: crate::pac::can::Can, } // NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it // exists. impl MasterFilters<'_, I> { - pub(crate) unsafe fn new() -> Self { - let can = &*I::REGISTERS; - + pub(crate) unsafe fn new(canregs: crate::pac::can::Can) -> Self { // Enable initialization mode. - can.fmr.modify(|_, w| w.finit().set_bit()); + canregs.fmr().modify(|reg| reg.set_finit(true)); // Read the filter split value. - let bank_count = can.fmr.read().can2sb().bits(); + let bank_count = canregs.fmr().read().can2sb(); // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all // of them to the master peripheral, and in devices with 28, assigns them 50/50 to @@ -234,18 +232,15 @@ impl MasterFilters<'_, I> { Self { bank_count, _can: PhantomData, + canregs, } } - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } - } - - fn banks_imm(&self) -> FilterBanks<'_> { + fn banks_imm(&self) -> FilterBanks { FilterBanks { start_idx: 0, bank_count: self.bank_count, - can: self.registers(), + canregs: self.canregs, } } @@ -296,9 +291,7 @@ impl MasterFilters<'_, I> { /// Sets the index at which the filter banks owned by the slave peripheral start. pub fn set_split(&mut self, split_index: u8) -> &mut Self { assert!(split_index <= I::NUM_FILTER_BANKS); - self.registers() - .fmr - .modify(|_, w| unsafe { w.can2sb().bits(split_index) }); + self.canregs.fmr().modify(|reg| reg.set_can2sb(split_index)); self.bank_count = split_index; self } @@ -310,6 +303,7 @@ impl MasterFilters<'_, I> { start_idx: self.bank_count, bank_count: I::NUM_FILTER_BANKS - self.bank_count, _can: PhantomData, + canregs: self.canregs, } } } @@ -317,10 +311,8 @@ impl MasterFilters<'_, I> { impl Drop for MasterFilters<'_, I> { #[inline] fn drop(&mut self) { - let can = self.registers(); - // Leave initialization mode. - can.fmr.modify(|_, w| w.finit().clear_bit()); + self.canregs.fmr().modify(|regs| regs.set_finit(false)); } } @@ -329,18 +321,15 @@ pub struct SlaveFilters<'a, I: Instance> { start_idx: u8, bank_count: u8, _can: PhantomData<&'a mut I>, + canregs: crate::pac::can::Can, } impl SlaveFilters<'_, I> { - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } - } - - fn banks_imm(&self) -> FilterBanks<'_> { + fn banks_imm(&self) -> FilterBanks { FilterBanks { start_idx: self.start_idx, bank_count: self.bank_count, - can: self.registers(), + canregs: self.canregs, } } @@ -381,20 +370,22 @@ impl SlaveFilters<'_, I> { } } -struct FilterBanks<'a> { +struct FilterBanks { start_idx: u8, bank_count: u8, - can: &'a RegisterBlock, + canregs: crate::pac::can::Can, } -impl FilterBanks<'_> { +impl FilterBanks { fn clear(&mut self) { let mask = filter_bitmask(self.start_idx, self.bank_count); - self.can.fa1r.modify(|r, w| { - let bits = r.bits(); - // Clear all bits in `mask`. - unsafe { w.bits(bits & !mask) } + self.canregs.fa1r().modify(|reg| { + for i in 0..28usize { + if (0x01u32 << i) & mask != 0 { + reg.set_fact(i, false); + } + } }); } @@ -404,8 +395,7 @@ impl FilterBanks<'_> { fn disable(&mut self, index: u8) { self.assert_bank_index(index); - - self.can.fa1r.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << index)) }) + self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, false)) } fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) { @@ -413,27 +403,11 @@ impl FilterBanks<'_> { // Configure mode. let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_)); - self.can.fm1r.modify(|r, w| { - let mut bits = r.bits(); - if mode { - bits |= 1 << index; - } else { - bits &= !(1 << index); - } - unsafe { w.bits(bits) } - }); + self.canregs.fm1r().modify(|reg| reg.set_fbm(index as usize, mode)); // Configure scale. let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_)); - self.can.fs1r.modify(|r, w| { - let mut bits = r.bits(); - if scale { - bits |= 1 << index; - } else { - bits &= !(1 << index); - } - unsafe { w.bits(bits) } - }); + self.canregs.fs1r().modify(|reg| reg.set_fsc(index as usize, scale)); // Configure filter register. let (fxr1, fxr2); @@ -455,22 +429,23 @@ impl FilterBanks<'_> { fxr2 = a.mask; } }; - let bank = &self.can.fb[usize::from(index)]; - bank.fr1.write(|w| unsafe { w.bits(fxr1) }); - bank.fr2.write(|w| unsafe { w.bits(fxr2) }); + let bank = self.canregs.fb(index as usize); + bank.fr1().write(|w| w.0 = fxr1); + bank.fr2().write(|w| w.0 = fxr2); // Assign to the right FIFO - self.can.ffa1r.modify(|r, w| unsafe { - let mut bits = r.bits(); - match fifo { - Fifo::Fifo0 => bits &= !(1 << index), - Fifo::Fifo1 => bits |= 1 << index, - } - w.bits(bits) + self.canregs.ffa1r().modify(|reg| { + reg.set_ffa( + index as usize, + match fifo { + Fifo::Fifo0 => false, + Fifo::Fifo1 => true, + }, + ) }); // Set active. - self.can.fa1r.modify(|r, w| unsafe { w.bits(r.bits() | (1 << index)) }) + self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, true)) } } diff --git a/embassy-stm32/src/can/bx/frame.rs b/embassy-stm32/src/can/bx/frame.rs index 2a51d1b15..828f375be 100644 --- a/embassy-stm32/src/can/bx/frame.rs +++ b/embassy-stm32/src/can/bx/frame.rs @@ -1,5 +1,4 @@ #[cfg(test)] - use core::cmp::Ordering; use core::ops::{Deref, DerefMut}; diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index c5801abec..eee8a33a6 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -35,7 +35,6 @@ use core::cmp::{Ord, Ordering}; use core::convert::{Infallible, TryInto}; use core::marker::PhantomData; use core::mem; -use core::ptr::NonNull; pub use id::{ExtendedId, Id, StandardId}; @@ -125,7 +124,7 @@ pub struct OverrunError { /// priority than remote frames. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -struct IdReg(u32); +pub(crate) struct IdReg(u32); impl IdReg { const STANDARD_SHIFT: u32 = 21; @@ -243,23 +242,25 @@ impl CanConfig<'_, I> { /// /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` /// parameter to this method. - pub fn set_bit_timing(self, btr: u32) -> Self { - self.can.set_bit_timing(btr); + pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { + self.can.set_bit_timing(bt); self } /// Enables or disables loopback mode: Internally connects the TX and RX /// signals together. pub fn set_loopback(self, enabled: bool) -> Self { - let can = self.can.registers(); - can.btr.modify(|_, w| w.lbkm().bit(enabled)); + self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); self } /// Enables or disables silent mode: Disconnects the TX signal from the pin. pub fn set_silent(self, enabled: bool) -> Self { - let can = self.can.registers(); - can.btr.modify(|_, w| w.silm().bit(enabled)); + let mode = match enabled { + false => stm32_metapac::can::vals::Silm::NORMAL, + true => stm32_metapac::can::vals::Silm::SILENT, + }; + self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); self } @@ -270,8 +271,7 @@ impl CanConfig<'_, I> { /// /// Automatic retransmission is enabled by default. pub fn set_automatic_retransmit(self, enabled: bool) -> Self { - let can = self.can.registers(); - can.mcr.modify(|_, w| w.nart().bit(!enabled)); + self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); self } @@ -304,11 +304,13 @@ impl CanConfig<'_, I> { /// Leaves initialization mode, enters sleep mode. fn leave_init_mode(&mut self) { - let can = self.can.registers(); - can.mcr.modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + self.can.canregs.mcr().modify(|reg| { + reg.set_sleep(true); + reg.set_inrq(false); + }); loop { - let msr = can.msr.read(); - if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { + let msr = self.can.canregs.msr().read(); + if msr.slak() && !msr.inak() { break; } } @@ -341,23 +343,24 @@ impl CanBuilder { /// /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` /// parameter to this method. - pub fn set_bit_timing(mut self, btr: u32) -> Self { - self.can.set_bit_timing(btr); + pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { + self.can.set_bit_timing(bt); self } - /// Enables or disables loopback mode: Internally connects the TX and RX /// signals together. pub fn set_loopback(self, enabled: bool) -> Self { - let can = self.can.registers(); - can.btr.modify(|_, w| w.lbkm().bit(enabled)); + self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); self } /// Enables or disables silent mode: Disconnects the TX signal from the pin. pub fn set_silent(self, enabled: bool) -> Self { - let can = self.can.registers(); - can.btr.modify(|_, w| w.silm().bit(enabled)); + let mode = match enabled { + false => stm32_metapac::can::vals::Silm::NORMAL, + true => stm32_metapac::can::vals::Silm::SILENT, + }; + self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); self } @@ -368,8 +371,7 @@ impl CanBuilder { /// /// Automatic retransmission is enabled by default. pub fn set_automatic_retransmit(self, enabled: bool) -> Self { - let can = self.can.registers(); - can.mcr.modify(|_, w| w.nart().bit(!enabled)); + self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); self } @@ -403,11 +405,13 @@ impl CanBuilder { /// Leaves initialization mode, enters sleep mode. fn leave_init_mode(&mut self) { - let can = self.can.registers(); - can.mcr.modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + self.can.canregs.mcr().modify(|reg| { + reg.set_sleep(true); + reg.set_inrq(false); + }); loop { - let msr = can.msr.read(); - if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { + let msr = self.can.canregs.msr().read(); + if msr.slak() && !msr.inak() { break; } } @@ -417,6 +421,7 @@ impl CanBuilder { /// Interface to a bxCAN peripheral. pub struct Can { instance: I, + canregs: crate::pac::can::Can, } impl Can @@ -424,15 +429,18 @@ where I: Instance, { /// Creates a [`CanBuilder`] for constructing a CAN interface. - pub fn builder(instance: I) -> CanBuilder { - let can_builder = CanBuilder { can: Can { instance } }; + pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder { + let can_builder = CanBuilder { + can: Can { instance, canregs }, + }; - let can_reg = can_builder.can.registers(); - // Enter init mode. - can_reg.mcr.modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); + canregs.mcr().modify(|reg| { + reg.set_sleep(false); + reg.set_inrq(true); + }); loop { - let msr = can_reg.msr.read(); - if msr.slak().bit_is_clear() && msr.inak().bit_is_set() { + let msr = canregs.msr().read(); + if !msr.slak() && msr.inak() { break; } } @@ -440,18 +448,16 @@ where can_builder } - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } - } - - fn set_bit_timing(&mut self, btr: u32) { - // Mask of all non-reserved BTR bits, except the mode flags. - const MASK: u32 = 0x037F_03FF; - - let can = self.registers(); - can.btr.modify(|r, w| unsafe { - let mode_bits = r.bits() & 0xC000_0000; - w.bits(mode_bits | (btr & MASK)) + fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { + let prescaler = u16::from(bt.prescaler) & 0x1FF; + let seg1 = u8::from(bt.seg1); + let seg2 = u8::from(bt.seg2) & 0x7F; + let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; + self.canregs.btr().modify(|reg| { + reg.set_brp(prescaler - 1); + reg.set_ts(0, seg1 - 1); + reg.set_ts(1, seg2 - 1); + reg.set_sjw(sync_jump_width - 1); }); } @@ -467,7 +473,7 @@ where /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to /// enter sleep mode. pub fn free(self) -> I { - self.registers().mcr.write(|w| w.reset().set_bit()); + self.canregs.mcr().write(|reg| reg.set_reset(true)); self.instance } @@ -475,13 +481,13 @@ where /// /// Calling this method will enter initialization mode. pub fn modify_config(&mut self) -> CanConfig<'_, I> { - let can = self.registers(); - - // Enter init mode. - can.mcr.modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); + self.canregs.mcr().modify(|reg| { + reg.set_sleep(false); + reg.set_inrq(true); + }); loop { - let msr = can.msr.read(); - if msr.slak().bit_is_clear() && msr.inak().bit_is_set() { + let msr = self.canregs.msr().read(); + if !msr.slak() && msr.inak() { break; } } @@ -497,8 +503,7 @@ where /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming /// frame. pub fn set_automatic_wakeup(&mut self, enabled: bool) { - let can = self.registers(); - can.mcr.modify(|_, w| w.awum().bit(enabled)); + self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); } /// Leaves initialization mode and enables the peripheral (non-blocking version). @@ -510,10 +515,12 @@ where /// in the background. The peripheral is enabled and ready to use when this method returns /// successfully. pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { - let can = self.registers(); - let msr = can.msr.read(); - if msr.slak().bit_is_set() { - can.mcr.modify(|_, w| w.abom().set_bit().sleep().clear_bit()); + let msr = self.canregs.msr().read(); + if msr.slak() { + self.canregs.mcr().modify(|reg| { + reg.set_abom(true); + reg.set_sleep(false); + }); Err(nb::Error::WouldBlock) } else { Ok(()) @@ -524,11 +531,13 @@ where /// /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. pub fn sleep(&mut self) { - let can = self.registers(); - can.mcr.modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + self.canregs.mcr().modify(|reg| { + reg.set_sleep(true); + reg.set_inrq(false); + }); loop { - let msr = can.msr.read(); - if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { + let msr = self.canregs.msr().read(); + if msr.slak() && !msr.inak() { break; } } @@ -539,11 +548,13 @@ where /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN /// frame will cause that interrupt. pub fn wakeup(&mut self) { - let can = self.registers(); - can.mcr.modify(|_, w| w.sleep().clear_bit().inrq().clear_bit()); + self.canregs.mcr().modify(|reg| { + reg.set_sleep(false); + reg.set_inrq(false); + }); loop { - let msr = can.msr.read(); - if msr.slak().bit_is_clear() && msr.inak().bit_is_clear() { + let msr = self.canregs.msr().read(); + if !msr.slak() && !msr.inak() { break; } } @@ -560,13 +571,13 @@ where /// [`TransmitStatus::dequeued_frame`]. pub fn transmit(&mut self, frame: &Frame) -> nb::Result { // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure().transmit(frame) } + unsafe { Tx::::conjure(self.canregs).transmit(frame) } } /// Returns `true` if no frame is pending for transmission. pub fn is_transmitter_idle(&self) -> bool { // Safety: Read-only operation. - unsafe { Tx::::conjure().is_idle() } + unsafe { Tx::::conjure(self.canregs).is_idle() } } /// Attempts to abort the sending of a frame that is pending in a mailbox. @@ -578,7 +589,7 @@ where /// returns `true`. pub fn abort(&mut self, mailbox: Mailbox) -> bool { // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure().abort(mailbox) } + unsafe { Tx::::conjure(self.canregs).abort(mailbox) } } /// Returns a received frame if available. @@ -589,8 +600,8 @@ where /// Returns `Err` when a frame was lost due to buffer overrun. pub fn receive(&mut self) -> nb::Result { // Safety: We have a `&mut self` and have unique access to the peripheral. - let mut rx0 = unsafe { Rx0::::conjure() }; - let mut rx1 = unsafe { Rx1::::conjure() }; + let mut rx0 = unsafe { Rx0::::conjure(self.canregs) }; + let mut rx1 = unsafe { Rx1::::conjure(self.canregs) }; match rx0.receive() { Err(nb::Error::WouldBlock) => rx1.receive(), @@ -599,30 +610,35 @@ where } /// Returns a reference to the RX FIFO 0. - pub fn rx0(&mut self) -> &mut Rx0 { + pub fn rx0(&mut self) -> Rx0 { // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. - unsafe { Rx0::conjure_by_ref() } + unsafe { Rx0::conjure(self.canregs) } } /// Returns a reference to the RX FIFO 1. - pub fn rx1(&mut self) -> &mut Rx1 { + pub fn rx1(&mut self) -> Rx1 { // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. - unsafe { Rx1::conjure_by_ref() } + unsafe { Rx1::conjure(self.canregs) } } - /// Splits this `Can` instance into transmitting and receiving halves, by reference. - pub fn split_by_ref(&mut self) -> (&mut Tx, &mut Rx0, &mut Rx1) { + pub fn split_by_ref(&mut self) -> (Tx, Rx0, Rx1) { // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. - let tx = unsafe { Tx::conjure_by_ref() }; - let rx0 = unsafe { Rx0::conjure_by_ref() }; - let rx1 = unsafe { Rx1::conjure_by_ref() }; + let tx = unsafe { Tx::conjure(self.canregs) }; + let rx0 = unsafe { Rx0::conjure(self.canregs) }; + let rx1 = unsafe { Rx1::conjure(self.canregs) }; (tx, rx0, rx1) } /// Consumes this `Can` instance and splits it into transmitting and receiving halves. pub fn split(self) -> (Tx, Rx0, Rx1) { // Safety: `Self` is not `Copy` and is destroyed by moving it into this method. - unsafe { (Tx::conjure(), Rx0::conjure(), Rx1::conjure()) } + unsafe { + ( + Tx::conjure(self.canregs), + Rx0::conjure(self.canregs), + Rx1::conjure(self.canregs), + ) + } } } @@ -632,46 +648,25 @@ impl Can { /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master /// peripheral instead. pub fn modify_filters(&mut self) -> MasterFilters<'_, I> { - unsafe { MasterFilters::new() } + unsafe { MasterFilters::new(self.canregs) } } } /// Interface to the CAN transmitter part. pub struct Tx { _can: PhantomData, -} - -#[inline] -const fn ok_mask(idx: usize) -> u32 { - 0x02 << (8 * idx) -} - -#[inline] -const fn abort_mask(idx: usize) -> u32 { - 0x80 << (8 * idx) + canregs: crate::pac::can::Can, } impl Tx where I: Instance, { - unsafe fn conjure() -> Self { - Self { _can: PhantomData } - } - - /// Creates a `&mut Self` out of thin air. - /// - /// This is only safe if it is the only way to access a `Tx`. - unsafe fn conjure_by_ref<'a>() -> &'a mut Self { - // Cause out of bounds access when `Self` is not zero-sized. - [()][core::mem::size_of::()]; - - // Any aligned pointer is valid for ZSTs. - &mut *NonNull::dangling().as_ptr() - } - - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } + unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { + Self { + _can: PhantomData, + canregs, + } } /// Puts a CAN frame in a transmit mailbox for transmission on the bus. @@ -684,13 +679,11 @@ where /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as /// [`TransmitStatus::dequeued_frame`]. pub fn transmit(&mut self, frame: &Frame) -> nb::Result { - let can = self.registers(); - // Get the index of the next free mailbox or the one with the lowest priority. - let tsr = can.tsr.read(); - let idx = tsr.code().bits() as usize; + let tsr = self.canregs.tsr().read(); + let idx = tsr.code() as usize; - let frame_is_pending = tsr.tme0().bit_is_clear() || tsr.tme1().bit_is_clear() || tsr.tme2().bit_is_clear(); + let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); let pending_frame = if frame_is_pending { // High priority frames are transmitted first by the mailbox system. // Frames with identical identifier shall be transmitted in FIFO order. @@ -701,8 +694,7 @@ where self.check_priority(1, frame.id)?; self.check_priority(2, frame.id)?; - let all_frames_are_pending = - tsr.tme0().bit_is_clear() && tsr.tme1().bit_is_clear() && tsr.tme2().bit_is_clear(); + let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); if all_frames_are_pending { // No free mailbox is available. This can only happen when three frames with // ascending priority (descending IDs) were requested for transmission and all @@ -735,15 +727,14 @@ where /// Returns `Ok` when the mailbox is free or if it contains pending frame with a /// lower priority (higher ID) than the identifier `id`. fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { - let can = self.registers(); - // Read the pending frame's id to check its priority. assert!(idx < 3); - let tir = &can.tx[idx].tir.read(); + let tir = &self.canregs.tx(idx).tir().read(); + //let tir = &can.tx[idx].tir.read(); // Check the priority by comparing the identifiers. But first make sure the // frame has not finished the transmission (`TXRQ` == 0) in the meantime. - if tir.txrq().bit_is_set() && id <= IdReg::from_register(tir.bits()) { + if tir.txrq() && id <= IdReg::from_register(tir.0) { // There's a mailbox whose priority is higher or equal // the priority of the new frame. return Err(nb::Error::WouldBlock); @@ -753,33 +744,34 @@ where } fn write_mailbox(&mut self, idx: usize, frame: &Frame) { - let can = self.registers(); - debug_assert!(idx < 3); - let mb = unsafe { &can.tx.get_unchecked(idx) }; - mb.tdtr.write(|w| unsafe { w.dlc().bits(frame.dlc() as u8) }); - mb.tdlr - .write(|w| unsafe { w.bits(u32::from_ne_bytes(frame.data.bytes[0..4].try_into().unwrap())) }); - mb.tdhr - .write(|w| unsafe { w.bits(u32::from_ne_bytes(frame.data.bytes[4..8].try_into().unwrap())) }); - mb.tir.write(|w| unsafe { w.bits(frame.id.0).txrq().set_bit() }); + let mb = self.canregs.tx(idx); + mb.tdtr().write(|w| w.set_dlc(frame.dlc() as u8)); + + mb.tdlr() + .write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[0..4].try_into().unwrap())); + mb.tdhr() + .write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[4..8].try_into().unwrap())); + mb.tir().write(|w| { + w.0 = frame.id.0; + w.set_txrq(true); + }); } fn read_pending_mailbox(&mut self, idx: usize) -> Option { if self.abort_by_index(idx) { - let can = self.registers(); debug_assert!(idx < 3); - let mb = unsafe { &can.tx.get_unchecked(idx) }; + let mb = self.canregs.tx(idx); // Read back the pending frame. let mut pending_frame = Frame { - id: IdReg(mb.tir.read().bits()), + id: IdReg(mb.tir().read().0), data: Data::empty(), }; - pending_frame.data.bytes[0..4].copy_from_slice(&mb.tdlr.read().bits().to_ne_bytes()); - pending_frame.data.bytes[4..8].copy_from_slice(&mb.tdhr.read().bits().to_ne_bytes()); - pending_frame.data.len = mb.tdtr.read().dlc().bits(); + pending_frame.data.bytes[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); + pending_frame.data.bytes[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); + pending_frame.data.len = mb.tdtr().read().dlc(); Some(pending_frame) } else { @@ -793,15 +785,13 @@ where /// Tries to abort a pending frame. Returns `true` when aborted. fn abort_by_index(&mut self, idx: usize) -> bool { - let can = self.registers(); - - can.tsr.write(|w| unsafe { w.bits(abort_mask(idx)) }); + self.canregs.tsr().write(|reg| reg.set_abrq(idx, true)); // Wait for the abort request to be finished. loop { - let tsr = can.tsr.read().bits(); - if tsr & abort_mask(idx) == 0 { - break tsr & ok_mask(idx) == 0; + let tsr = self.canregs.tsr().read(); + if false == tsr.abrq(idx) { + break tsr.txok(idx) == false; } } } @@ -816,11 +806,11 @@ where pub fn abort(&mut self, mailbox: Mailbox) -> bool { // If the mailbox is empty, the value of TXOKx depends on what happened with the previous // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. - let tsr = self.registers().tsr.read(); + let tsr = self.canregs.tsr().read(); let mailbox_empty = match mailbox { - Mailbox::Mailbox0 => tsr.tme0().bit_is_set(), - Mailbox::Mailbox1 => tsr.tme1().bit_is_set(), - Mailbox::Mailbox2 => tsr.tme2().bit_is_set(), + Mailbox::Mailbox0 => tsr.tme(0), + Mailbox::Mailbox1 => tsr.tme(1), + Mailbox::Mailbox2 => tsr.tme(2), }; if mailbox_empty { false @@ -831,119 +821,101 @@ where /// Returns `true` if no frame is pending for transmission. pub fn is_idle(&self) -> bool { - let can = self.registers(); - let tsr = can.tsr.read(); - tsr.tme0().bit_is_set() && tsr.tme1().bit_is_set() && tsr.tme2().bit_is_set() + let tsr = self.canregs.tsr().read(); + tsr.tme(0) && tsr.tme(1) && tsr.tme(2) } /// Clears the request complete flag for all mailboxes. pub fn clear_interrupt_flags(&mut self) { - let can = self.registers(); - can.tsr - .write(|w| w.rqcp2().set_bit().rqcp1().set_bit().rqcp0().set_bit()); + self.canregs.tsr().write(|reg| { + reg.set_rqcp(0, true); + reg.set_rqcp(1, true); + reg.set_rqcp(2, true); + }); } } /// Interface to receiver FIFO 0. pub struct Rx0 { _can: PhantomData, + canregs: crate::pac::can::Can, } impl Rx0 where I: Instance, { - unsafe fn conjure() -> Self { - Self { _can: PhantomData } - } - - /// Creates a `&mut Self` out of thin air. - /// - /// This is only safe if it is the only way to access an `Rx`. - unsafe fn conjure_by_ref<'a>() -> &'a mut Self { - // Cause out of bounds access when `Self` is not zero-sized. - [()][core::mem::size_of::()]; - - // Any aligned pointer is valid for ZSTs. - &mut *NonNull::dangling().as_ptr() + unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { + Self { + _can: PhantomData, + canregs, + } } /// Returns a received frame if available. /// /// Returns `Err` when a frame was lost due to buffer overrun. pub fn receive(&mut self) -> nb::Result { - receive_fifo(self.registers(), 0) - } - - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } + receive_fifo(self.canregs, 0) } } /// Interface to receiver FIFO 1. pub struct Rx1 { _can: PhantomData, + canregs: crate::pac::can::Can, } impl Rx1 where I: Instance, { - unsafe fn conjure() -> Self { - Self { _can: PhantomData } - } - - /// Creates a `&mut Self` out of thin air. - /// - /// This is only safe if it is the only way to access an `Rx`. - unsafe fn conjure_by_ref<'a>() -> &'a mut Self { - // Cause out of bounds access when `Self` is not zero-sized. - [()][core::mem::size_of::()]; - - // Any aligned pointer is valid for ZSTs. - &mut *NonNull::dangling().as_ptr() + unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { + Self { + _can: PhantomData, + canregs, + } } /// Returns a received frame if available. /// /// Returns `Err` when a frame was lost due to buffer overrun. pub fn receive(&mut self) -> nb::Result { - receive_fifo(self.registers(), 1) - } - - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } + receive_fifo(self.canregs, 1) } } -fn receive_fifo(can: &RegisterBlock, fifo_nr: usize) -> nb::Result { +fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result { assert!(fifo_nr < 2); - let rfr = &can.rfr[fifo_nr]; - let rx = &can.rx[fifo_nr]; + let rfr = canregs.rfr(fifo_nr); + let rx = canregs.rx(fifo_nr); + + //let rfr = &can.rfr[fifo_nr]; + //let rx = &can.rx[fifo_nr]; // Check if a frame is available in the mailbox. let rfr_read = rfr.read(); - if rfr_read.fmp().bits() == 0 { + if rfr_read.fmp() == 0 { return Err(nb::Error::WouldBlock); } // Check for RX FIFO overrun. - if rfr_read.fovr().bit_is_set() { - rfr.write(|w| w.fovr().set_bit()); + if rfr_read.fovr() { + rfr.write(|w| w.set_fovr(true)); return Err(nb::Error::Other(OverrunError { _priv: () })); } // Read the frame. let mut frame = Frame { - id: IdReg(rx.rir.read().bits()), + id: IdReg(rx.rir().read().0), data: [0; 8].into(), }; - frame.data[0..4].copy_from_slice(&rx.rdlr.read().bits().to_ne_bytes()); - frame.data[4..8].copy_from_slice(&rx.rdhr.read().bits().to_ne_bytes()); - frame.data.len = rx.rdtr.read().dlc().bits(); + frame.data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes()); + frame.data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes()); + frame.data.len = rx.rdtr().read().dlc(); // Release the mailbox. - rfr.write(|w| w.rfom().set_bit()); + rfr.write(|w| w.set_rfom(true)); Ok(frame) } diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index cd394c951..3a3411aaa 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -167,21 +167,14 @@ impl<'d, T: Instance> Can<'d, T> { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - let can = crate::can::bx::Can::builder(BxcanInstance(peri)).leave_disabled(); + let can = crate::can::bx::Can::builder(BxcanInstance(peri), T::regs()).leave_disabled(); Self { can } } /// Set CAN bit rate. pub fn set_bitrate(&mut self, bitrate: u32) { let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); - let sjw = u8::from(bit_timing.sync_jump_width) as u32; - let seg1 = u8::from(bit_timing.seg1) as u32; - let seg2 = u8::from(bit_timing.seg2) as u32; - let prescaler = u16::from(bit_timing.prescaler) as u32; - self.can - .modify_config() - .set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1)) - .leave_disabled(); + self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); } /// Enables the peripheral and synchronizes with the bus. @@ -299,7 +292,7 @@ impl<'d, T: Instance> Can<'d, T> { /// Split the CAN driver into transmit and receive halves. /// /// Useful for doing separate transmit/receive tasks. - pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { + pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { let (tx, rx0, rx1) = self.can.split_by_ref(); (CanTx { tx }, CanRx { rx0, rx1 }) } @@ -313,11 +306,11 @@ impl<'d, T: Instance> AsMut>> for Can<' } /// CAN driver, transmit half. -pub struct CanTx<'c, 'd, T: Instance> { - tx: &'c mut crate::can::bx::Tx>, +pub struct CanTx<'d, T: Instance> { + tx: crate::can::bx::Tx>, } -impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { +impl<'d, T: Instance> CanTx<'d, T> { /// Queues the message to be sent. /// /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. @@ -404,12 +397,12 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { /// CAN driver, receive half. #[allow(dead_code)] -pub struct CanRx<'c, 'd, T: Instance> { - rx0: &'c mut crate::can::bx::Rx0>, - rx1: &'c mut crate::can::bx::Rx1>, +pub struct CanRx<'d, T: Instance> { + rx0: crate::can::bx::Rx0>, + rx1: crate::can::bx::Rx1>, } -impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { +impl<'d, T: Instance> CanRx<'d, T> { /// Read a CAN frame. /// /// If no CAN frame is in the RX buffer, this will wait until there is one. From a9ff38003bebbb87aea2405437155d5312326803 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Tue, 5 Mar 2024 20:27:52 +1000 Subject: [PATCH 648/760] Documentation. . --- embassy-stm32/src/can/bx/filter.rs | 4 ++++ embassy-stm32/src/can/bx/mod.rs | 4 +++- examples/stm32f1/src/bin/can.rs | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bx/filter.rs index 64f020fc7..51766aa31 100644 --- a/embassy-stm32/src/can/bx/filter.rs +++ b/embassy-stm32/src/can/bx/filter.rs @@ -171,9 +171,13 @@ impl Mask32 { #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum BankConfig { + /// Specify up to 4 exact standard CAN ID's. List16([ListEntry16; 4]), + /// Specify up to 2 exact standard or extended CAN ID's. List32([ListEntry32; 2]), + /// Specify up to 2 standard ID's with masks. Mask16([Mask16; 2]), + /// Specify a single extended ID with mask. Mask32(Mask32), } diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index eee8a33a6..375bc27f7 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -621,7 +621,7 @@ where unsafe { Rx1::conjure(self.canregs) } } - pub fn split_by_ref(&mut self) -> (Tx, Rx0, Rx1) { + pub(crate) fn split_by_ref(&mut self) -> (Tx, Rx0, Rx1) { // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. let tx = unsafe { Tx::conjure(self.canregs) }; let rx0 = unsafe { Rx0::conjure(self.canregs) }; @@ -924,7 +924,9 @@ fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result match env.frame.id() { Id::Extended(id) => { - defmt::println!("Extended Frame id={:x}", id.as_raw()); + defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap()); } Id::Standard(id) => { - defmt::println!("Standard Frame id={:x}", id.as_raw()); + defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap()); } }, Err(err) => { From 65b38cf75504339033c56b39ce23da0b697a35a5 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Tue, 5 Mar 2024 20:51:05 +1000 Subject: [PATCH 649/760] Fix examples and improve imports required. --- embassy-stm32/src/can/bxcan.rs | 2 +- examples/stm32f1/src/bin/can.rs | 9 +++++---- examples/stm32f4/src/bin/can.rs | 7 ++++--- examples/stm32f7/src/bin/can.rs | 21 ++++++++++++++------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 3a3411aaa..3b7c5c242 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -6,7 +6,7 @@ use core::task::Poll; pub mod bx; -use bx::{Data, ExtendedId, Frame, Id, StandardId}; +pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Id, StandardId}; use embassy_hal_internal::{into_ref, PeripheralRef}; use futures::FutureExt; diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index 130b3905a..00d61096f 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -3,9 +3,10 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::can::bx::filter::Mask32; -use embassy_stm32::can::bx::{Fifo, Frame, Id, StandardId}; -use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; +use embassy_stm32::can::{ + filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, + TxInterruptHandler, +}; use embassy_stm32::peripherals::CAN; use embassy_stm32::{bind_interrupts, Config}; use {defmt_rtt as _, panic_probe as _}; @@ -31,7 +32,7 @@ async fn main(_spawner: Spawner) { can.as_mut() .modify_filters() - .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all()); can.as_mut() .modify_config() diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index d074b4265..b20af8cf1 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs @@ -4,9 +4,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; -use embassy_stm32::can::bxcan::filter::Mask32; -use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; -use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; +use embassy_stm32::can::filter::Mask32; +use embassy_stm32::can::{ + Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler, +}; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN1; use embassy_time::Instant; diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index bcfdb67a8..c3e14bbf4 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -1,16 +1,18 @@ #![no_std] #![no_main] +use core::num::{NonZeroU16, NonZeroU8}; + use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::bind_interrupts; -use embassy_stm32::can::bxcan::filter::Mask32; -use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; +use embassy_stm32::can::filter::Mask32; use embassy_stm32::can::{ - Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, + Can, CanTx, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, + TxInterruptHandler, }; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN3; +use embassy_stm32::{bind_interrupts, can}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -22,7 +24,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) { +pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { loop { let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); tx.write(&frame).await; @@ -51,13 +53,18 @@ async fn main(spawner: Spawner) { can.as_mut() .modify_config() - .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/ + .set_bit_timing(can::util::NominalBitTiming { + prescaler: NonZeroU16::new(2).unwrap(), + seg1: NonZeroU8::new(13).unwrap(), + seg2: NonZeroU8::new(2).unwrap(), + sync_jump_width: NonZeroU8::new(1).unwrap(), + }) // http://www.bittiming.can-wiki.info/ .set_loopback(true) .enable(); let (tx, mut rx) = can.split(); - static CAN_TX: StaticCell> = StaticCell::new(); + static CAN_TX: StaticCell> = StaticCell::new(); let tx = CAN_TX.init(tx); spawner.spawn(send_can_message(tx)).unwrap(); From 9ba379fb9eed304de96309d5a47a984ba7ed5ee1 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 7 Mar 2024 08:11:10 +1000 Subject: [PATCH 650/760] Remove usage of old PAC Formatting --- embassy-stm32/src/can/bx/mod.rs | 9 +-------- embassy-stm32/src/can/bxcan.rs | 7 +------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 375bc27f7..2bfa827a8 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -29,8 +29,6 @@ mod frame; mod id; #[allow(clippy::all)] // generated code -mod pac; - use core::cmp::{Ord, Ordering}; use core::convert::{Infallible, TryInto}; use core::marker::PhantomData; @@ -38,10 +36,8 @@ use core::mem; pub use id::{ExtendedId, Id, StandardId}; -use self::pac::generic::*; use crate::can::bx::filter::MasterFilters; pub use crate::can::bx::frame::{Data, Frame, FramePriority}; -pub use crate::can::bx::pac::can::RegisterBlock; // To make the PAC extraction build /// A bxCAN peripheral instance. /// @@ -56,10 +52,7 @@ pub use crate::can::bx::pac::can::RegisterBlock; // To make the PAC extraction b /// register block. /// * `REGISTERS` is a pointer to that peripheral's register block and can be safely accessed for as /// long as ownership or a borrow of the implementing type is present. -pub unsafe trait Instance { - /// Pointer to the instance's register block. - const REGISTERS: *mut RegisterBlock; -} +pub unsafe trait Instance {} /// A bxCAN instance that owns filter banks. /// diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 3b7c5c242..acd831937 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -509,8 +509,6 @@ pub(crate) mod sealed { } pub trait Instance { - const REGISTERS: *mut crate::can::bx::RegisterBlock; - fn regs() -> crate::pac::can::Can; fn state() -> &'static State; } @@ -531,14 +529,11 @@ pub trait Instance: sealed::Instance + RccPeripheral + 'static { /// BXCAN instance newtype. pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); -unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> { - const REGISTERS: *mut crate::can::bx::RegisterBlock = T::REGISTERS; -} +unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> {} foreach_peripheral!( (can, $inst:ident) => { impl sealed::Instance for peripherals::$inst { - const REGISTERS: *mut crate::can::bx::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; fn regs() -> crate::pac::can::Can { crate::pac::$inst From 98e7a0a423de98c32863e2949b381efa7b5cdead Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 7 Mar 2024 08:09:49 +1000 Subject: [PATCH 651/760] Remove old PAC from bscan crate. --- embassy-stm32/src/can/bx/pac/can.rs | 213 ---- embassy-stm32/src/can/bx/pac/can/btr.rs | 282 ----- embassy-stm32/src/can/bx/pac/can/esr.rs | 206 ---- embassy-stm32/src/can/bx/pac/can/fa1r.rs | 492 -------- embassy-stm32/src/can/bx/pac/can/fb.rs | 22 - embassy-stm32/src/can/bx/pac/can/fb/fr1.rs | 40 - embassy-stm32/src/can/bx/pac/can/fb/fr2.rs | 40 - embassy-stm32/src/can/bx/pac/can/ffa1r.rs | 492 -------- embassy-stm32/src/can/bx/pac/can/fm1r.rs | 492 -------- embassy-stm32/src/can/bx/pac/can/fmr.rs | 74 -- embassy-stm32/src/can/bx/pac/can/fs1r.rs | 492 -------- embassy-stm32/src/can/bx/pac/can/ier.rs | 1218 ------------------- embassy-stm32/src/can/bx/pac/can/mcr.rs | 356 ------ embassy-stm32/src/can/bx/pac/can/msr.rs | 160 --- embassy-stm32/src/can/bx/pac/can/rfr.rs | 281 ----- embassy-stm32/src/can/bx/pac/can/rx.rs | 36 - embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs | 32 - embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs | 32 - embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs | 25 - embassy-stm32/src/can/bx/pac/can/rx/rir.rs | 100 -- embassy-stm32/src/can/bx/pac/can/tsr.rs | 575 --------- embassy-stm32/src/can/bx/pac/can/tx.rs | 44 - embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs | 112 -- embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs | 112 -- embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs | 98 -- embassy-stm32/src/can/bx/pac/can/tx/tir.rs | 268 ---- embassy-stm32/src/can/bx/pac/generic.rs | 256 ---- embassy-stm32/src/can/bx/pac/mod.rs | 9 - 28 files changed, 6559 deletions(-) delete mode 100644 embassy-stm32/src/can/bx/pac/can.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/btr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/esr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/fa1r.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/fb.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/fb/fr1.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/fb/fr2.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/ffa1r.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/fm1r.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/fmr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/fs1r.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/ier.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/mcr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/msr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/rfr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/rx.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/rx/rir.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/tsr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/tx.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs delete mode 100644 embassy-stm32/src/can/bx/pac/can/tx/tir.rs delete mode 100644 embassy-stm32/src/can/bx/pac/generic.rs delete mode 100644 embassy-stm32/src/can/bx/pac/mod.rs diff --git a/embassy-stm32/src/can/bx/pac/can.rs b/embassy-stm32/src/can/bx/pac/can.rs deleted file mode 100644 index 726f5d0ae..000000000 --- a/embassy-stm32/src/can/bx/pac/can.rs +++ /dev/null @@ -1,213 +0,0 @@ -/// Register block of bxCAN peripherals. -#[repr(C)] -pub struct RegisterBlock { - #[doc = "0x00 - CAN_MCR"] - pub(crate) mcr: MCR, - #[doc = "0x04 - CAN_MSR"] - pub(crate) msr: MSR, - #[doc = "0x08 - CAN_TSR"] - pub(crate) tsr: TSR, - #[doc = "0x0c - CAN_RF0R"] - pub(crate) rfr: [RFR; 2], - #[doc = "0x14 - CAN_IER"] - pub(crate) ier: IER, - #[doc = "0x18 - CAN_ESR"] - pub(crate) esr: ESR, - #[doc = "0x1c - CAN_BTR"] - pub(crate) btr: BTR, - _reserved7: [u8; 352usize], - #[doc = "0x180 - CAN Transmit cluster"] - pub(crate) tx: [TX; 3], - #[doc = "0x1b0 - CAN Receive cluster"] - pub(crate) rx: [RX; 2], - _reserved9: [u8; 48usize], - #[doc = "0x200 - CAN_FMR"] - pub(crate) fmr: FMR, - #[doc = "0x204 - CAN_FM1R"] - pub(crate) fm1r: FM1R, - _reserved11: [u8; 4usize], - #[doc = "0x20c - CAN_FS1R"] - pub(crate) fs1r: FS1R, - _reserved12: [u8; 4usize], - #[doc = "0x214 - CAN_FFA1R"] - pub(crate) ffa1r: FFA1R, - _reserved13: [u8; 4usize], - #[doc = "0x21c - CAN_FA1R"] - pub(crate) fa1r: FA1R, - _reserved14: [u8; 32usize], - #[doc = "0x240 - CAN Filter Bank cluster"] - pub(crate) fb: [FB; 28], // UP TO 28, but 14 in some devices -} -#[doc = r"Register block"] -#[repr(C)] -pub struct TX { - #[doc = "0x00 - CAN_TI0R"] - pub tir: self::tx::TIR, - #[doc = "0x04 - CAN_TDT0R"] - pub tdtr: self::tx::TDTR, - #[doc = "0x08 - CAN_TDL0R"] - pub tdlr: self::tx::TDLR, - #[doc = "0x0c - CAN_TDH0R"] - pub tdhr: self::tx::TDHR, -} -#[doc = r"Register block"] -#[doc = "CAN Transmit cluster"] -pub mod tx; -#[doc = r"Register block"] -#[repr(C)] -pub struct RX { - #[doc = "0x00 - CAN_RI0R"] - pub rir: self::rx::RIR, - #[doc = "0x04 - CAN_RDT0R"] - pub rdtr: self::rx::RDTR, - #[doc = "0x08 - CAN_RDL0R"] - pub rdlr: self::rx::RDLR, - #[doc = "0x0c - CAN_RDH0R"] - pub rdhr: self::rx::RDHR, -} -#[doc = r"Register block"] -#[doc = "CAN Receive cluster"] -pub mod rx; -#[doc = r"Register block"] -#[repr(C)] -pub struct FB { - #[doc = "0x00 - Filter bank 0 register 1"] - pub fr1: self::fb::FR1, - #[doc = "0x04 - Filter bank 0 register 2"] - pub fr2: self::fb::FR2, -} -#[doc = r"Register block"] -#[doc = "CAN Filter Bank cluster"] -pub mod fb; -#[doc = "CAN_MCR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [mcr](mcr) module"] -pub type MCR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _MCR; -#[doc = "`read()` method returns [mcr::R](mcr::R) reader structure"] -impl crate::can::bx::Readable for MCR {} -#[doc = "`write(|w| ..)` method takes [mcr::W](mcr::W) writer structure"] -impl crate::can::bx::Writable for MCR {} -#[doc = "CAN_MCR"] -pub mod mcr; -#[doc = "CAN_MSR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [msr](msr) module"] -pub type MSR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _MSR; -#[doc = "`read()` method returns [msr::R](msr::R) reader structure"] -impl crate::can::bx::Readable for MSR {} -#[doc = "`write(|w| ..)` method takes [msr::W](msr::W) writer structure"] -impl crate::can::bx::Writable for MSR {} -#[doc = "CAN_MSR"] -pub mod msr; -#[doc = "CAN_TSR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tsr](tsr) module"] -pub type TSR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _TSR; -#[doc = "`read()` method returns [tsr::R](tsr::R) reader structure"] -impl crate::can::bx::Readable for TSR {} -#[doc = "`write(|w| ..)` method takes [tsr::W](tsr::W) writer structure"] -impl crate::can::bx::Writable for TSR {} -#[doc = "CAN_TSR"] -pub mod tsr; -#[doc = "CAN_RF0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rfr](rfr) module"] -pub type RFR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _RFR; -#[doc = "`read()` method returns [rfr::R](rfr::R) reader structure"] -impl crate::can::bx::Readable for RFR {} -#[doc = "`write(|w| ..)` method takes [rfr::W](rfr::W) writer structure"] -impl crate::can::bx::Writable for RFR {} -#[doc = "CAN_RF0R"] -pub mod rfr; -#[doc = "CAN_IER\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [ier](ier) module"] -pub type IER = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _IER; -#[doc = "`read()` method returns [ier::R](ier::R) reader structure"] -impl crate::can::bx::Readable for IER {} -#[doc = "`write(|w| ..)` method takes [ier::W](ier::W) writer structure"] -impl crate::can::bx::Writable for IER {} -#[doc = "CAN_IER"] -pub mod ier; -#[doc = "CAN_ESR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [esr](esr) module"] -pub type ESR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _ESR; -#[doc = "`read()` method returns [esr::R](esr::R) reader structure"] -impl crate::can::bx::Readable for ESR {} -#[doc = "`write(|w| ..)` method takes [esr::W](esr::W) writer structure"] -impl crate::can::bx::Writable for ESR {} -#[doc = "CAN_ESR"] -pub mod esr; -#[doc = "CAN_BTR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [btr](btr) module"] -pub type BTR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _BTR; -#[doc = "`read()` method returns [btr::R](btr::R) reader structure"] -impl crate::can::bx::Readable for BTR {} -#[doc = "`write(|w| ..)` method takes [btr::W](btr::W) writer structure"] -impl crate::can::bx::Writable for BTR {} -#[doc = "CAN_BTR"] -pub mod btr; -#[doc = "CAN_FMR\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fmr](fmr) module"] -pub type FMR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _FMR; -#[doc = "`read()` method returns [fmr::R](fmr::R) reader structure"] -impl crate::can::bx::Readable for FMR {} -#[doc = "`write(|w| ..)` method takes [fmr::W](fmr::W) writer structure"] -impl crate::can::bx::Writable for FMR {} -#[doc = "CAN_FMR"] -pub mod fmr; -#[doc = "CAN_FM1R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fm1r](fm1r) module"] -pub type FM1R = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _FM1R; -#[doc = "`read()` method returns [fm1r::R](fm1r::R) reader structure"] -impl crate::can::bx::Readable for FM1R {} -#[doc = "`write(|w| ..)` method takes [fm1r::W](fm1r::W) writer structure"] -impl crate::can::bx::Writable for FM1R {} -#[doc = "CAN_FM1R"] -pub mod fm1r; -#[doc = "CAN_FS1R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fs1r](fs1r) module"] -pub type FS1R = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _FS1R; -#[doc = "`read()` method returns [fs1r::R](fs1r::R) reader structure"] -impl crate::can::bx::Readable for FS1R {} -#[doc = "`write(|w| ..)` method takes [fs1r::W](fs1r::W) writer structure"] -impl crate::can::bx::Writable for FS1R {} -#[doc = "CAN_FS1R"] -pub mod fs1r; -#[doc = "CAN_FFA1R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [ffa1r](ffa1r) module"] -pub type FFA1R = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _FFA1R; -#[doc = "`read()` method returns [ffa1r::R](ffa1r::R) reader structure"] -impl crate::can::bx::Readable for FFA1R {} -#[doc = "`write(|w| ..)` method takes [ffa1r::W](ffa1r::W) writer structure"] -impl crate::can::bx::Writable for FFA1R {} -#[doc = "CAN_FFA1R"] -pub mod ffa1r; -#[doc = "CAN_FA1R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fa1r](fa1r) module"] -pub type FA1R = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _FA1R; -#[doc = "`read()` method returns [fa1r::R](fa1r::R) reader structure"] -impl crate::can::bx::Readable for FA1R {} -#[doc = "`write(|w| ..)` method takes [fa1r::W](fa1r::W) writer structure"] -impl crate::can::bx::Writable for FA1R {} -#[doc = "CAN_FA1R"] -pub mod fa1r; diff --git a/embassy-stm32/src/can/bx/pac/can/btr.rs b/embassy-stm32/src/can/bx/pac/can/btr.rs deleted file mode 100644 index 23ca298aa..000000000 --- a/embassy-stm32/src/can/bx/pac/can/btr.rs +++ /dev/null @@ -1,282 +0,0 @@ -#[doc = "Reader of register BTR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register BTR"] -pub type W = crate::can::bx::W; -#[doc = "Register BTR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::BTR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "SILM\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum SILM_A { - #[doc = "0: Normal operation"] - NORMAL = 0, - #[doc = "1: Silent Mode"] - SILENT = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: SILM_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `SILM`"] -pub type SILM_R = crate::can::bx::R; -impl SILM_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> SILM_A { - match self.bits { - false => SILM_A::NORMAL, - true => SILM_A::SILENT, - } - } - #[doc = "Checks if the value of the field is `NORMAL`"] - #[inline(always)] - pub fn is_normal(&self) -> bool { - *self == SILM_A::NORMAL - } - #[doc = "Checks if the value of the field is `SILENT`"] - #[inline(always)] - pub fn is_silent(&self) -> bool { - *self == SILM_A::SILENT - } -} -#[doc = "Write proxy for field `SILM`"] -pub struct SILM_W<'a> { - w: &'a mut W, -} -impl<'a> SILM_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: SILM_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "Normal operation"] - #[inline(always)] - pub fn normal(self) -> &'a mut W { - self.variant(SILM_A::NORMAL) - } - #[doc = "Silent Mode"] - #[inline(always)] - pub fn silent(self) -> &'a mut W { - self.variant(SILM_A::SILENT) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 31)) | (((value as u32) & 0x01) << 31); - self.w - } -} -#[doc = "LBKM\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum LBKM_A { - #[doc = "0: Loop Back Mode disabled"] - DISABLED = 0, - #[doc = "1: Loop Back Mode enabled"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: LBKM_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `LBKM`"] -pub type LBKM_R = crate::can::bx::R; -impl LBKM_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> LBKM_A { - match self.bits { - false => LBKM_A::DISABLED, - true => LBKM_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == LBKM_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == LBKM_A::ENABLED - } -} -#[doc = "Write proxy for field `LBKM`"] -pub struct LBKM_W<'a> { - w: &'a mut W, -} -impl<'a> LBKM_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: LBKM_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "Loop Back Mode disabled"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(LBKM_A::DISABLED) - } - #[doc = "Loop Back Mode enabled"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(LBKM_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 30)) | (((value as u32) & 0x01) << 30); - self.w - } -} -#[doc = "Reader of field `SJW`"] -pub type SJW_R = crate::can::bx::R; -#[doc = "Write proxy for field `SJW`"] -pub struct SJW_W<'a> { - w: &'a mut W, -} -impl<'a> SJW_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x03 << 24)) | (((value as u32) & 0x03) << 24); - self.w - } -} -#[doc = "Reader of field `TS2`"] -pub type TS2_R = crate::can::bx::R; -#[doc = "Write proxy for field `TS2`"] -pub struct TS2_W<'a> { - w: &'a mut W, -} -impl<'a> TS2_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x07 << 20)) | (((value as u32) & 0x07) << 20); - self.w - } -} -#[doc = "Reader of field `TS1`"] -pub type TS1_R = crate::can::bx::R; -#[doc = "Write proxy for field `TS1`"] -pub struct TS1_W<'a> { - w: &'a mut W, -} -impl<'a> TS1_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x0f << 16)) | (((value as u32) & 0x0f) << 16); - self.w - } -} -#[doc = "Reader of field `BRP`"] -pub type BRP_R = crate::can::bx::R; -#[doc = "Write proxy for field `BRP`"] -pub struct BRP_W<'a> { - w: &'a mut W, -} -impl<'a> BRP_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u16) -> &'a mut W { - self.w.bits = (self.w.bits & !0x03ff) | ((value as u32) & 0x03ff); - self.w - } -} -impl R { - #[doc = "Bit 31 - SILM"] - #[inline(always)] - pub fn silm(&self) -> SILM_R { - SILM_R::new(((self.bits >> 31) & 0x01) != 0) - } - #[doc = "Bit 30 - LBKM"] - #[inline(always)] - pub fn lbkm(&self) -> LBKM_R { - LBKM_R::new(((self.bits >> 30) & 0x01) != 0) - } - #[doc = "Bits 24:25 - SJW"] - #[inline(always)] - pub fn sjw(&self) -> SJW_R { - SJW_R::new(((self.bits >> 24) & 0x03) as u8) - } - #[doc = "Bits 20:22 - TS2"] - #[inline(always)] - pub fn ts2(&self) -> TS2_R { - TS2_R::new(((self.bits >> 20) & 0x07) as u8) - } - #[doc = "Bits 16:19 - TS1"] - #[inline(always)] - pub fn ts1(&self) -> TS1_R { - TS1_R::new(((self.bits >> 16) & 0x0f) as u8) - } - #[doc = "Bits 0:9 - BRP"] - #[inline(always)] - pub fn brp(&self) -> BRP_R { - BRP_R::new((self.bits & 0x03ff) as u16) - } -} -impl W { - #[doc = "Bit 31 - SILM"] - #[inline(always)] - pub fn silm(&mut self) -> SILM_W { - SILM_W { w: self } - } - #[doc = "Bit 30 - LBKM"] - #[inline(always)] - pub fn lbkm(&mut self) -> LBKM_W { - LBKM_W { w: self } - } - #[doc = "Bits 24:25 - SJW"] - #[inline(always)] - pub fn sjw(&mut self) -> SJW_W { - SJW_W { w: self } - } - #[doc = "Bits 20:22 - TS2"] - #[inline(always)] - pub fn ts2(&mut self) -> TS2_W { - TS2_W { w: self } - } - #[doc = "Bits 16:19 - TS1"] - #[inline(always)] - pub fn ts1(&mut self) -> TS1_W { - TS1_W { w: self } - } - #[doc = "Bits 0:9 - BRP"] - #[inline(always)] - pub fn brp(&mut self) -> BRP_W { - BRP_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/esr.rs b/embassy-stm32/src/can/bx/pac/can/esr.rs deleted file mode 100644 index ddc414239..000000000 --- a/embassy-stm32/src/can/bx/pac/can/esr.rs +++ /dev/null @@ -1,206 +0,0 @@ -#[doc = "Reader of register ESR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register ESR"] -pub type W = crate::can::bx::W; -#[doc = "Register ESR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::ESR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `REC`"] -pub type REC_R = crate::can::bx::R; -#[doc = "Reader of field `TEC`"] -pub type TEC_R = crate::can::bx::R; -#[doc = "LEC\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -#[repr(u8)] -pub enum LEC_A { - #[doc = "0: No Error"] - NOERROR = 0, - #[doc = "1: Stuff Error"] - STUFF = 1, - #[doc = "2: Form Error"] - FORM = 2, - #[doc = "3: Acknowledgment Error"] - ACK = 3, - #[doc = "4: Bit recessive Error"] - BITRECESSIVE = 4, - #[doc = "5: Bit dominant Error"] - BITDOMINANT = 5, - #[doc = "6: CRC Error"] - CRC = 6, - #[doc = "7: Set by software"] - CUSTOM = 7, -} -impl From for u8 { - #[inline(always)] - fn from(variant: LEC_A) -> Self { - variant as _ - } -} -#[doc = "Reader of field `LEC`"] -pub type LEC_R = crate::can::bx::R; -impl LEC_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> LEC_A { - match self.bits { - 0 => LEC_A::NOERROR, - 1 => LEC_A::STUFF, - 2 => LEC_A::FORM, - 3 => LEC_A::ACK, - 4 => LEC_A::BITRECESSIVE, - 5 => LEC_A::BITDOMINANT, - 6 => LEC_A::CRC, - 7 => LEC_A::CUSTOM, - _ => unreachable!(), - } - } - #[doc = "Checks if the value of the field is `NOERROR`"] - #[inline(always)] - pub fn is_no_error(&self) -> bool { - *self == LEC_A::NOERROR - } - #[doc = "Checks if the value of the field is `STUFF`"] - #[inline(always)] - pub fn is_stuff(&self) -> bool { - *self == LEC_A::STUFF - } - #[doc = "Checks if the value of the field is `FORM`"] - #[inline(always)] - pub fn is_form(&self) -> bool { - *self == LEC_A::FORM - } - #[doc = "Checks if the value of the field is `ACK`"] - #[inline(always)] - pub fn is_ack(&self) -> bool { - *self == LEC_A::ACK - } - #[doc = "Checks if the value of the field is `BITRECESSIVE`"] - #[inline(always)] - pub fn is_bit_recessive(&self) -> bool { - *self == LEC_A::BITRECESSIVE - } - #[doc = "Checks if the value of the field is `BITDOMINANT`"] - #[inline(always)] - pub fn is_bit_dominant(&self) -> bool { - *self == LEC_A::BITDOMINANT - } - #[doc = "Checks if the value of the field is `CRC`"] - #[inline(always)] - pub fn is_crc(&self) -> bool { - *self == LEC_A::CRC - } - #[doc = "Checks if the value of the field is `CUSTOM`"] - #[inline(always)] - pub fn is_custom(&self) -> bool { - *self == LEC_A::CUSTOM - } -} -#[doc = "Write proxy for field `LEC`"] -pub struct LEC_W<'a> { - w: &'a mut W, -} -impl<'a> LEC_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: LEC_A) -> &'a mut W { - { - self.bits(variant.into()) - } - } - #[doc = "No Error"] - #[inline(always)] - pub fn no_error(self) -> &'a mut W { - self.variant(LEC_A::NOERROR) - } - #[doc = "Stuff Error"] - #[inline(always)] - pub fn stuff(self) -> &'a mut W { - self.variant(LEC_A::STUFF) - } - #[doc = "Form Error"] - #[inline(always)] - pub fn form(self) -> &'a mut W { - self.variant(LEC_A::FORM) - } - #[doc = "Acknowledgment Error"] - #[inline(always)] - pub fn ack(self) -> &'a mut W { - self.variant(LEC_A::ACK) - } - #[doc = "Bit recessive Error"] - #[inline(always)] - pub fn bit_recessive(self) -> &'a mut W { - self.variant(LEC_A::BITRECESSIVE) - } - #[doc = "Bit dominant Error"] - #[inline(always)] - pub fn bit_dominant(self) -> &'a mut W { - self.variant(LEC_A::BITDOMINANT) - } - #[doc = "CRC Error"] - #[inline(always)] - pub fn crc(self) -> &'a mut W { - self.variant(LEC_A::CRC) - } - #[doc = "Set by software"] - #[inline(always)] - pub fn custom(self) -> &'a mut W { - self.variant(LEC_A::CUSTOM) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x07 << 4)) | (((value as u32) & 0x07) << 4); - self.w - } -} -#[doc = "Reader of field `BOFF`"] -pub type BOFF_R = crate::can::bx::R; -#[doc = "Reader of field `EPVF`"] -pub type EPVF_R = crate::can::bx::R; -#[doc = "Reader of field `EWGF`"] -pub type EWGF_R = crate::can::bx::R; -impl R { - #[doc = "Bits 24:31 - REC"] - #[inline(always)] - pub fn rec(&self) -> REC_R { - REC_R::new(((self.bits >> 24) & 0xff) as u8) - } - #[doc = "Bits 16:23 - TEC"] - #[inline(always)] - pub fn tec(&self) -> TEC_R { - TEC_R::new(((self.bits >> 16) & 0xff) as u8) - } - #[doc = "Bits 4:6 - LEC"] - #[inline(always)] - pub fn lec(&self) -> LEC_R { - LEC_R::new(((self.bits >> 4) & 0x07) as u8) - } - #[doc = "Bit 2 - BOFF"] - #[inline(always)] - pub fn boff(&self) -> BOFF_R { - BOFF_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 1 - EPVF"] - #[inline(always)] - pub fn epvf(&self) -> EPVF_R { - EPVF_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 0 - EWGF"] - #[inline(always)] - pub fn ewgf(&self) -> EWGF_R { - EWGF_R::new((self.bits & 0x01) != 0) - } -} -impl W { - #[doc = "Bits 4:6 - LEC"] - #[inline(always)] - pub fn lec(&mut self) -> LEC_W { - LEC_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/fa1r.rs b/embassy-stm32/src/can/bx/pac/can/fa1r.rs deleted file mode 100644 index e7b2b365d..000000000 --- a/embassy-stm32/src/can/bx/pac/can/fa1r.rs +++ /dev/null @@ -1,492 +0,0 @@ -#[doc = "Reader of register FA1R"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register FA1R"] -pub type W = crate::can::bx::W; -#[doc = "Register FA1R `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::FA1R { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `FACT0`"] -pub type FACT0_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT0`"] -pub struct FACT0_W<'a> { - w: &'a mut W, -} -impl<'a> FACT0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -#[doc = "Reader of field `FACT1`"] -pub type FACT1_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT1`"] -pub struct FACT1_W<'a> { - w: &'a mut W, -} -impl<'a> FACT1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); - self.w - } -} -#[doc = "Reader of field `FACT2`"] -pub type FACT2_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT2`"] -pub struct FACT2_W<'a> { - w: &'a mut W, -} -impl<'a> FACT2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "Reader of field `FACT3`"] -pub type FACT3_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT3`"] -pub struct FACT3_W<'a> { - w: &'a mut W, -} -impl<'a> FACT3_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "Reader of field `FACT4`"] -pub type FACT4_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT4`"] -pub struct FACT4_W<'a> { - w: &'a mut W, -} -impl<'a> FACT4_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); - self.w - } -} -#[doc = "Reader of field `FACT5`"] -pub type FACT5_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT5`"] -pub struct FACT5_W<'a> { - w: &'a mut W, -} -impl<'a> FACT5_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); - self.w - } -} -#[doc = "Reader of field `FACT6`"] -pub type FACT6_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT6`"] -pub struct FACT6_W<'a> { - w: &'a mut W, -} -impl<'a> FACT6_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); - self.w - } -} -#[doc = "Reader of field `FACT7`"] -pub type FACT7_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT7`"] -pub struct FACT7_W<'a> { - w: &'a mut W, -} -impl<'a> FACT7_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); - self.w - } -} -#[doc = "Reader of field `FACT8`"] -pub type FACT8_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT8`"] -pub struct FACT8_W<'a> { - w: &'a mut W, -} -impl<'a> FACT8_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); - self.w - } -} -#[doc = "Reader of field `FACT9`"] -pub type FACT9_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT9`"] -pub struct FACT9_W<'a> { - w: &'a mut W, -} -impl<'a> FACT9_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); - self.w - } -} -#[doc = "Reader of field `FACT10`"] -pub type FACT10_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT10`"] -pub struct FACT10_W<'a> { - w: &'a mut W, -} -impl<'a> FACT10_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); - self.w - } -} -#[doc = "Reader of field `FACT11`"] -pub type FACT11_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT11`"] -pub struct FACT11_W<'a> { - w: &'a mut W, -} -impl<'a> FACT11_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); - self.w - } -} -#[doc = "Reader of field `FACT12`"] -pub type FACT12_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT12`"] -pub struct FACT12_W<'a> { - w: &'a mut W, -} -impl<'a> FACT12_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 12)) | (((value as u32) & 0x01) << 12); - self.w - } -} -#[doc = "Reader of field `FACT13`"] -pub type FACT13_R = crate::can::bx::R; -#[doc = "Write proxy for field `FACT13`"] -pub struct FACT13_W<'a> { - w: &'a mut W, -} -impl<'a> FACT13_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 13)) | (((value as u32) & 0x01) << 13); - self.w - } -} -impl R { - #[doc = "Bit 0 - Filter active"] - #[inline(always)] - pub fn fact0(&self) -> FACT0_R { - FACT0_R::new((self.bits & 0x01) != 0) - } - #[doc = "Bit 1 - Filter active"] - #[inline(always)] - pub fn fact1(&self) -> FACT1_R { - FACT1_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 2 - Filter active"] - #[inline(always)] - pub fn fact2(&self) -> FACT2_R { - FACT2_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 3 - Filter active"] - #[inline(always)] - pub fn fact3(&self) -> FACT3_R { - FACT3_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bit 4 - Filter active"] - #[inline(always)] - pub fn fact4(&self) -> FACT4_R { - FACT4_R::new(((self.bits >> 4) & 0x01) != 0) - } - #[doc = "Bit 5 - Filter active"] - #[inline(always)] - pub fn fact5(&self) -> FACT5_R { - FACT5_R::new(((self.bits >> 5) & 0x01) != 0) - } - #[doc = "Bit 6 - Filter active"] - #[inline(always)] - pub fn fact6(&self) -> FACT6_R { - FACT6_R::new(((self.bits >> 6) & 0x01) != 0) - } - #[doc = "Bit 7 - Filter active"] - #[inline(always)] - pub fn fact7(&self) -> FACT7_R { - FACT7_R::new(((self.bits >> 7) & 0x01) != 0) - } - #[doc = "Bit 8 - Filter active"] - #[inline(always)] - pub fn fact8(&self) -> FACT8_R { - FACT8_R::new(((self.bits >> 8) & 0x01) != 0) - } - #[doc = "Bit 9 - Filter active"] - #[inline(always)] - pub fn fact9(&self) -> FACT9_R { - FACT9_R::new(((self.bits >> 9) & 0x01) != 0) - } - #[doc = "Bit 10 - Filter active"] - #[inline(always)] - pub fn fact10(&self) -> FACT10_R { - FACT10_R::new(((self.bits >> 10) & 0x01) != 0) - } - #[doc = "Bit 11 - Filter active"] - #[inline(always)] - pub fn fact11(&self) -> FACT11_R { - FACT11_R::new(((self.bits >> 11) & 0x01) != 0) - } - #[doc = "Bit 12 - Filter active"] - #[inline(always)] - pub fn fact12(&self) -> FACT12_R { - FACT12_R::new(((self.bits >> 12) & 0x01) != 0) - } - #[doc = "Bit 13 - Filter active"] - #[inline(always)] - pub fn fact13(&self) -> FACT13_R { - FACT13_R::new(((self.bits >> 13) & 0x01) != 0) - } -} -impl W { - #[doc = "Bit 0 - Filter active"] - #[inline(always)] - pub fn fact0(&mut self) -> FACT0_W { - FACT0_W { w: self } - } - #[doc = "Bit 1 - Filter active"] - #[inline(always)] - pub fn fact1(&mut self) -> FACT1_W { - FACT1_W { w: self } - } - #[doc = "Bit 2 - Filter active"] - #[inline(always)] - pub fn fact2(&mut self) -> FACT2_W { - FACT2_W { w: self } - } - #[doc = "Bit 3 - Filter active"] - #[inline(always)] - pub fn fact3(&mut self) -> FACT3_W { - FACT3_W { w: self } - } - #[doc = "Bit 4 - Filter active"] - #[inline(always)] - pub fn fact4(&mut self) -> FACT4_W { - FACT4_W { w: self } - } - #[doc = "Bit 5 - Filter active"] - #[inline(always)] - pub fn fact5(&mut self) -> FACT5_W { - FACT5_W { w: self } - } - #[doc = "Bit 6 - Filter active"] - #[inline(always)] - pub fn fact6(&mut self) -> FACT6_W { - FACT6_W { w: self } - } - #[doc = "Bit 7 - Filter active"] - #[inline(always)] - pub fn fact7(&mut self) -> FACT7_W { - FACT7_W { w: self } - } - #[doc = "Bit 8 - Filter active"] - #[inline(always)] - pub fn fact8(&mut self) -> FACT8_W { - FACT8_W { w: self } - } - #[doc = "Bit 9 - Filter active"] - #[inline(always)] - pub fn fact9(&mut self) -> FACT9_W { - FACT9_W { w: self } - } - #[doc = "Bit 10 - Filter active"] - #[inline(always)] - pub fn fact10(&mut self) -> FACT10_W { - FACT10_W { w: self } - } - #[doc = "Bit 11 - Filter active"] - #[inline(always)] - pub fn fact11(&mut self) -> FACT11_W { - FACT11_W { w: self } - } - #[doc = "Bit 12 - Filter active"] - #[inline(always)] - pub fn fact12(&mut self) -> FACT12_W { - FACT12_W { w: self } - } - #[doc = "Bit 13 - Filter active"] - #[inline(always)] - pub fn fact13(&mut self) -> FACT13_W { - FACT13_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/fb.rs b/embassy-stm32/src/can/bx/pac/can/fb.rs deleted file mode 100644 index 527235b29..000000000 --- a/embassy-stm32/src/can/bx/pac/can/fb.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[doc = "Filter bank 0 register 1\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fr1](fr1) module"] -pub type FR1 = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _FR1; -#[doc = "`read()` method returns [fr1::R](fr1::R) reader structure"] -impl crate::can::bx::Readable for FR1 {} -#[doc = "`write(|w| ..)` method takes [fr1::W](fr1::W) writer structure"] -impl crate::can::bx::Writable for FR1 {} -#[doc = "Filter bank 0 register 1"] -pub mod fr1; -#[doc = "Filter bank 0 register 2\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [fr2](fr2) module"] -pub type FR2 = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _FR2; -#[doc = "`read()` method returns [fr2::R](fr2::R) reader structure"] -impl crate::can::bx::Readable for FR2 {} -#[doc = "`write(|w| ..)` method takes [fr2::W](fr2::W) writer structure"] -impl crate::can::bx::Writable for FR2 {} -#[doc = "Filter bank 0 register 2"] -pub mod fr2; diff --git a/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs b/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs deleted file mode 100644 index 6a80bd308..000000000 --- a/embassy-stm32/src/can/bx/pac/can/fb/fr1.rs +++ /dev/null @@ -1,40 +0,0 @@ -#[doc = "Reader of register FR1"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register FR1"] -pub type W = crate::can::bx::W; -#[doc = "Register FR1 `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::FR1 { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `FB`"] -pub type FB_R = crate::can::bx::R; -#[doc = "Write proxy for field `FB`"] -pub struct FB_W<'a> { - w: &'a mut W, -} -impl<'a> FB_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u32) -> &'a mut W { - self.w.bits = (self.w.bits & !0xffff_ffff) | ((value as u32) & 0xffff_ffff); - self.w - } -} -impl R { - #[doc = "Bits 0:31 - Filter bits"] - #[inline(always)] - pub fn fb(&self) -> FB_R { - FB_R::new((self.bits & 0xffff_ffff) as u32) - } -} -impl W { - #[doc = "Bits 0:31 - Filter bits"] - #[inline(always)] - pub fn fb(&mut self) -> FB_W { - FB_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs b/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs deleted file mode 100644 index 097387b9f..000000000 --- a/embassy-stm32/src/can/bx/pac/can/fb/fr2.rs +++ /dev/null @@ -1,40 +0,0 @@ -#[doc = "Reader of register FR2"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register FR2"] -pub type W = crate::can::bx::W; -#[doc = "Register FR2 `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::FR2 { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `FB`"] -pub type FB_R = crate::can::bx::R; -#[doc = "Write proxy for field `FB`"] -pub struct FB_W<'a> { - w: &'a mut W, -} -impl<'a> FB_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u32) -> &'a mut W { - self.w.bits = (self.w.bits & !0xffff_ffff) | ((value as u32) & 0xffff_ffff); - self.w - } -} -impl R { - #[doc = "Bits 0:31 - Filter bits"] - #[inline(always)] - pub fn fb(&self) -> FB_R { - FB_R::new((self.bits & 0xffff_ffff) as u32) - } -} -impl W { - #[doc = "Bits 0:31 - Filter bits"] - #[inline(always)] - pub fn fb(&mut self) -> FB_W { - FB_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/ffa1r.rs b/embassy-stm32/src/can/bx/pac/can/ffa1r.rs deleted file mode 100644 index cf5e04c78..000000000 --- a/embassy-stm32/src/can/bx/pac/can/ffa1r.rs +++ /dev/null @@ -1,492 +0,0 @@ -#[doc = "Reader of register FFA1R"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register FFA1R"] -pub type W = crate::can::bx::W; -#[doc = "Register FFA1R `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::FFA1R { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `FFA0`"] -pub type FFA0_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA0`"] -pub struct FFA0_W<'a> { - w: &'a mut W, -} -impl<'a> FFA0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -#[doc = "Reader of field `FFA1`"] -pub type FFA1_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA1`"] -pub struct FFA1_W<'a> { - w: &'a mut W, -} -impl<'a> FFA1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); - self.w - } -} -#[doc = "Reader of field `FFA2`"] -pub type FFA2_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA2`"] -pub struct FFA2_W<'a> { - w: &'a mut W, -} -impl<'a> FFA2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "Reader of field `FFA3`"] -pub type FFA3_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA3`"] -pub struct FFA3_W<'a> { - w: &'a mut W, -} -impl<'a> FFA3_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "Reader of field `FFA4`"] -pub type FFA4_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA4`"] -pub struct FFA4_W<'a> { - w: &'a mut W, -} -impl<'a> FFA4_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); - self.w - } -} -#[doc = "Reader of field `FFA5`"] -pub type FFA5_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA5`"] -pub struct FFA5_W<'a> { - w: &'a mut W, -} -impl<'a> FFA5_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); - self.w - } -} -#[doc = "Reader of field `FFA6`"] -pub type FFA6_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA6`"] -pub struct FFA6_W<'a> { - w: &'a mut W, -} -impl<'a> FFA6_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); - self.w - } -} -#[doc = "Reader of field `FFA7`"] -pub type FFA7_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA7`"] -pub struct FFA7_W<'a> { - w: &'a mut W, -} -impl<'a> FFA7_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); - self.w - } -} -#[doc = "Reader of field `FFA8`"] -pub type FFA8_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA8`"] -pub struct FFA8_W<'a> { - w: &'a mut W, -} -impl<'a> FFA8_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); - self.w - } -} -#[doc = "Reader of field `FFA9`"] -pub type FFA9_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA9`"] -pub struct FFA9_W<'a> { - w: &'a mut W, -} -impl<'a> FFA9_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); - self.w - } -} -#[doc = "Reader of field `FFA10`"] -pub type FFA10_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA10`"] -pub struct FFA10_W<'a> { - w: &'a mut W, -} -impl<'a> FFA10_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); - self.w - } -} -#[doc = "Reader of field `FFA11`"] -pub type FFA11_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA11`"] -pub struct FFA11_W<'a> { - w: &'a mut W, -} -impl<'a> FFA11_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); - self.w - } -} -#[doc = "Reader of field `FFA12`"] -pub type FFA12_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA12`"] -pub struct FFA12_W<'a> { - w: &'a mut W, -} -impl<'a> FFA12_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 12)) | (((value as u32) & 0x01) << 12); - self.w - } -} -#[doc = "Reader of field `FFA13`"] -pub type FFA13_R = crate::can::bx::R; -#[doc = "Write proxy for field `FFA13`"] -pub struct FFA13_W<'a> { - w: &'a mut W, -} -impl<'a> FFA13_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 13)) | (((value as u32) & 0x01) << 13); - self.w - } -} -impl R { - #[doc = "Bit 0 - Filter FIFO assignment for filter 0"] - #[inline(always)] - pub fn ffa0(&self) -> FFA0_R { - FFA0_R::new((self.bits & 0x01) != 0) - } - #[doc = "Bit 1 - Filter FIFO assignment for filter 1"] - #[inline(always)] - pub fn ffa1(&self) -> FFA1_R { - FFA1_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 2 - Filter FIFO assignment for filter 2"] - #[inline(always)] - pub fn ffa2(&self) -> FFA2_R { - FFA2_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 3 - Filter FIFO assignment for filter 3"] - #[inline(always)] - pub fn ffa3(&self) -> FFA3_R { - FFA3_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bit 4 - Filter FIFO assignment for filter 4"] - #[inline(always)] - pub fn ffa4(&self) -> FFA4_R { - FFA4_R::new(((self.bits >> 4) & 0x01) != 0) - } - #[doc = "Bit 5 - Filter FIFO assignment for filter 5"] - #[inline(always)] - pub fn ffa5(&self) -> FFA5_R { - FFA5_R::new(((self.bits >> 5) & 0x01) != 0) - } - #[doc = "Bit 6 - Filter FIFO assignment for filter 6"] - #[inline(always)] - pub fn ffa6(&self) -> FFA6_R { - FFA6_R::new(((self.bits >> 6) & 0x01) != 0) - } - #[doc = "Bit 7 - Filter FIFO assignment for filter 7"] - #[inline(always)] - pub fn ffa7(&self) -> FFA7_R { - FFA7_R::new(((self.bits >> 7) & 0x01) != 0) - } - #[doc = "Bit 8 - Filter FIFO assignment for filter 8"] - #[inline(always)] - pub fn ffa8(&self) -> FFA8_R { - FFA8_R::new(((self.bits >> 8) & 0x01) != 0) - } - #[doc = "Bit 9 - Filter FIFO assignment for filter 9"] - #[inline(always)] - pub fn ffa9(&self) -> FFA9_R { - FFA9_R::new(((self.bits >> 9) & 0x01) != 0) - } - #[doc = "Bit 10 - Filter FIFO assignment for filter 10"] - #[inline(always)] - pub fn ffa10(&self) -> FFA10_R { - FFA10_R::new(((self.bits >> 10) & 0x01) != 0) - } - #[doc = "Bit 11 - Filter FIFO assignment for filter 11"] - #[inline(always)] - pub fn ffa11(&self) -> FFA11_R { - FFA11_R::new(((self.bits >> 11) & 0x01) != 0) - } - #[doc = "Bit 12 - Filter FIFO assignment for filter 12"] - #[inline(always)] - pub fn ffa12(&self) -> FFA12_R { - FFA12_R::new(((self.bits >> 12) & 0x01) != 0) - } - #[doc = "Bit 13 - Filter FIFO assignment for filter 13"] - #[inline(always)] - pub fn ffa13(&self) -> FFA13_R { - FFA13_R::new(((self.bits >> 13) & 0x01) != 0) - } -} -impl W { - #[doc = "Bit 0 - Filter FIFO assignment for filter 0"] - #[inline(always)] - pub fn ffa0(&mut self) -> FFA0_W { - FFA0_W { w: self } - } - #[doc = "Bit 1 - Filter FIFO assignment for filter 1"] - #[inline(always)] - pub fn ffa1(&mut self) -> FFA1_W { - FFA1_W { w: self } - } - #[doc = "Bit 2 - Filter FIFO assignment for filter 2"] - #[inline(always)] - pub fn ffa2(&mut self) -> FFA2_W { - FFA2_W { w: self } - } - #[doc = "Bit 3 - Filter FIFO assignment for filter 3"] - #[inline(always)] - pub fn ffa3(&mut self) -> FFA3_W { - FFA3_W { w: self } - } - #[doc = "Bit 4 - Filter FIFO assignment for filter 4"] - #[inline(always)] - pub fn ffa4(&mut self) -> FFA4_W { - FFA4_W { w: self } - } - #[doc = "Bit 5 - Filter FIFO assignment for filter 5"] - #[inline(always)] - pub fn ffa5(&mut self) -> FFA5_W { - FFA5_W { w: self } - } - #[doc = "Bit 6 - Filter FIFO assignment for filter 6"] - #[inline(always)] - pub fn ffa6(&mut self) -> FFA6_W { - FFA6_W { w: self } - } - #[doc = "Bit 7 - Filter FIFO assignment for filter 7"] - #[inline(always)] - pub fn ffa7(&mut self) -> FFA7_W { - FFA7_W { w: self } - } - #[doc = "Bit 8 - Filter FIFO assignment for filter 8"] - #[inline(always)] - pub fn ffa8(&mut self) -> FFA8_W { - FFA8_W { w: self } - } - #[doc = "Bit 9 - Filter FIFO assignment for filter 9"] - #[inline(always)] - pub fn ffa9(&mut self) -> FFA9_W { - FFA9_W { w: self } - } - #[doc = "Bit 10 - Filter FIFO assignment for filter 10"] - #[inline(always)] - pub fn ffa10(&mut self) -> FFA10_W { - FFA10_W { w: self } - } - #[doc = "Bit 11 - Filter FIFO assignment for filter 11"] - #[inline(always)] - pub fn ffa11(&mut self) -> FFA11_W { - FFA11_W { w: self } - } - #[doc = "Bit 12 - Filter FIFO assignment for filter 12"] - #[inline(always)] - pub fn ffa12(&mut self) -> FFA12_W { - FFA12_W { w: self } - } - #[doc = "Bit 13 - Filter FIFO assignment for filter 13"] - #[inline(always)] - pub fn ffa13(&mut self) -> FFA13_W { - FFA13_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/fm1r.rs b/embassy-stm32/src/can/bx/pac/can/fm1r.rs deleted file mode 100644 index 828f1914e..000000000 --- a/embassy-stm32/src/can/bx/pac/can/fm1r.rs +++ /dev/null @@ -1,492 +0,0 @@ -#[doc = "Reader of register FM1R"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register FM1R"] -pub type W = crate::can::bx::W; -#[doc = "Register FM1R `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::FM1R { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `FBM0`"] -pub type FBM0_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM0`"] -pub struct FBM0_W<'a> { - w: &'a mut W, -} -impl<'a> FBM0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -#[doc = "Reader of field `FBM1`"] -pub type FBM1_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM1`"] -pub struct FBM1_W<'a> { - w: &'a mut W, -} -impl<'a> FBM1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); - self.w - } -} -#[doc = "Reader of field `FBM2`"] -pub type FBM2_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM2`"] -pub struct FBM2_W<'a> { - w: &'a mut W, -} -impl<'a> FBM2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "Reader of field `FBM3`"] -pub type FBM3_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM3`"] -pub struct FBM3_W<'a> { - w: &'a mut W, -} -impl<'a> FBM3_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "Reader of field `FBM4`"] -pub type FBM4_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM4`"] -pub struct FBM4_W<'a> { - w: &'a mut W, -} -impl<'a> FBM4_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); - self.w - } -} -#[doc = "Reader of field `FBM5`"] -pub type FBM5_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM5`"] -pub struct FBM5_W<'a> { - w: &'a mut W, -} -impl<'a> FBM5_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); - self.w - } -} -#[doc = "Reader of field `FBM6`"] -pub type FBM6_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM6`"] -pub struct FBM6_W<'a> { - w: &'a mut W, -} -impl<'a> FBM6_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); - self.w - } -} -#[doc = "Reader of field `FBM7`"] -pub type FBM7_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM7`"] -pub struct FBM7_W<'a> { - w: &'a mut W, -} -impl<'a> FBM7_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); - self.w - } -} -#[doc = "Reader of field `FBM8`"] -pub type FBM8_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM8`"] -pub struct FBM8_W<'a> { - w: &'a mut W, -} -impl<'a> FBM8_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); - self.w - } -} -#[doc = "Reader of field `FBM9`"] -pub type FBM9_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM9`"] -pub struct FBM9_W<'a> { - w: &'a mut W, -} -impl<'a> FBM9_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); - self.w - } -} -#[doc = "Reader of field `FBM10`"] -pub type FBM10_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM10`"] -pub struct FBM10_W<'a> { - w: &'a mut W, -} -impl<'a> FBM10_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); - self.w - } -} -#[doc = "Reader of field `FBM11`"] -pub type FBM11_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM11`"] -pub struct FBM11_W<'a> { - w: &'a mut W, -} -impl<'a> FBM11_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); - self.w - } -} -#[doc = "Reader of field `FBM12`"] -pub type FBM12_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM12`"] -pub struct FBM12_W<'a> { - w: &'a mut W, -} -impl<'a> FBM12_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 12)) | (((value as u32) & 0x01) << 12); - self.w - } -} -#[doc = "Reader of field `FBM13`"] -pub type FBM13_R = crate::can::bx::R; -#[doc = "Write proxy for field `FBM13`"] -pub struct FBM13_W<'a> { - w: &'a mut W, -} -impl<'a> FBM13_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 13)) | (((value as u32) & 0x01) << 13); - self.w - } -} -impl R { - #[doc = "Bit 0 - Filter mode"] - #[inline(always)] - pub fn fbm0(&self) -> FBM0_R { - FBM0_R::new((self.bits & 0x01) != 0) - } - #[doc = "Bit 1 - Filter mode"] - #[inline(always)] - pub fn fbm1(&self) -> FBM1_R { - FBM1_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 2 - Filter mode"] - #[inline(always)] - pub fn fbm2(&self) -> FBM2_R { - FBM2_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 3 - Filter mode"] - #[inline(always)] - pub fn fbm3(&self) -> FBM3_R { - FBM3_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bit 4 - Filter mode"] - #[inline(always)] - pub fn fbm4(&self) -> FBM4_R { - FBM4_R::new(((self.bits >> 4) & 0x01) != 0) - } - #[doc = "Bit 5 - Filter mode"] - #[inline(always)] - pub fn fbm5(&self) -> FBM5_R { - FBM5_R::new(((self.bits >> 5) & 0x01) != 0) - } - #[doc = "Bit 6 - Filter mode"] - #[inline(always)] - pub fn fbm6(&self) -> FBM6_R { - FBM6_R::new(((self.bits >> 6) & 0x01) != 0) - } - #[doc = "Bit 7 - Filter mode"] - #[inline(always)] - pub fn fbm7(&self) -> FBM7_R { - FBM7_R::new(((self.bits >> 7) & 0x01) != 0) - } - #[doc = "Bit 8 - Filter mode"] - #[inline(always)] - pub fn fbm8(&self) -> FBM8_R { - FBM8_R::new(((self.bits >> 8) & 0x01) != 0) - } - #[doc = "Bit 9 - Filter mode"] - #[inline(always)] - pub fn fbm9(&self) -> FBM9_R { - FBM9_R::new(((self.bits >> 9) & 0x01) != 0) - } - #[doc = "Bit 10 - Filter mode"] - #[inline(always)] - pub fn fbm10(&self) -> FBM10_R { - FBM10_R::new(((self.bits >> 10) & 0x01) != 0) - } - #[doc = "Bit 11 - Filter mode"] - #[inline(always)] - pub fn fbm11(&self) -> FBM11_R { - FBM11_R::new(((self.bits >> 11) & 0x01) != 0) - } - #[doc = "Bit 12 - Filter mode"] - #[inline(always)] - pub fn fbm12(&self) -> FBM12_R { - FBM12_R::new(((self.bits >> 12) & 0x01) != 0) - } - #[doc = "Bit 13 - Filter mode"] - #[inline(always)] - pub fn fbm13(&self) -> FBM13_R { - FBM13_R::new(((self.bits >> 13) & 0x01) != 0) - } -} -impl W { - #[doc = "Bit 0 - Filter mode"] - #[inline(always)] - pub fn fbm0(&mut self) -> FBM0_W { - FBM0_W { w: self } - } - #[doc = "Bit 1 - Filter mode"] - #[inline(always)] - pub fn fbm1(&mut self) -> FBM1_W { - FBM1_W { w: self } - } - #[doc = "Bit 2 - Filter mode"] - #[inline(always)] - pub fn fbm2(&mut self) -> FBM2_W { - FBM2_W { w: self } - } - #[doc = "Bit 3 - Filter mode"] - #[inline(always)] - pub fn fbm3(&mut self) -> FBM3_W { - FBM3_W { w: self } - } - #[doc = "Bit 4 - Filter mode"] - #[inline(always)] - pub fn fbm4(&mut self) -> FBM4_W { - FBM4_W { w: self } - } - #[doc = "Bit 5 - Filter mode"] - #[inline(always)] - pub fn fbm5(&mut self) -> FBM5_W { - FBM5_W { w: self } - } - #[doc = "Bit 6 - Filter mode"] - #[inline(always)] - pub fn fbm6(&mut self) -> FBM6_W { - FBM6_W { w: self } - } - #[doc = "Bit 7 - Filter mode"] - #[inline(always)] - pub fn fbm7(&mut self) -> FBM7_W { - FBM7_W { w: self } - } - #[doc = "Bit 8 - Filter mode"] - #[inline(always)] - pub fn fbm8(&mut self) -> FBM8_W { - FBM8_W { w: self } - } - #[doc = "Bit 9 - Filter mode"] - #[inline(always)] - pub fn fbm9(&mut self) -> FBM9_W { - FBM9_W { w: self } - } - #[doc = "Bit 10 - Filter mode"] - #[inline(always)] - pub fn fbm10(&mut self) -> FBM10_W { - FBM10_W { w: self } - } - #[doc = "Bit 11 - Filter mode"] - #[inline(always)] - pub fn fbm11(&mut self) -> FBM11_W { - FBM11_W { w: self } - } - #[doc = "Bit 12 - Filter mode"] - #[inline(always)] - pub fn fbm12(&mut self) -> FBM12_W { - FBM12_W { w: self } - } - #[doc = "Bit 13 - Filter mode"] - #[inline(always)] - pub fn fbm13(&mut self) -> FBM13_W { - FBM13_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/fmr.rs b/embassy-stm32/src/can/bx/pac/can/fmr.rs deleted file mode 100644 index 5663ff3cd..000000000 --- a/embassy-stm32/src/can/bx/pac/can/fmr.rs +++ /dev/null @@ -1,74 +0,0 @@ -#[doc = "Reader of register FMR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register FMR"] -pub type W = crate::can::bx::W; -#[doc = "Register FMR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::FMR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `CAN2SB`"] -pub type CAN2SB_R = crate::can::bx::R; -#[doc = "Write proxy for field `CAN2SB`"] -pub struct CAN2SB_W<'a> { - w: &'a mut W, -} -impl<'a> CAN2SB_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x3f << 8)) | (((value as u32) & 0x3f) << 8); - self.w - } -} -#[doc = "Reader of field `FINIT`"] -pub type FINIT_R = crate::can::bx::R; -#[doc = "Write proxy for field `FINIT`"] -pub struct FINIT_W<'a> { - w: &'a mut W, -} -impl<'a> FINIT_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -impl R { - #[doc = "Bits 8:13 - CAN2SB"] - #[inline(always)] - pub fn can2sb(&self) -> CAN2SB_R { - CAN2SB_R::new(((self.bits >> 8) & 0x3f) as u8) - } - #[doc = "Bit 0 - FINIT"] - #[inline(always)] - pub fn finit(&self) -> FINIT_R { - FINIT_R::new((self.bits & 0x01) != 0) - } -} -impl W { - #[doc = "Bits 8:13 - CAN2SB"] - #[inline(always)] - pub fn can2sb(&mut self) -> CAN2SB_W { - CAN2SB_W { w: self } - } - #[doc = "Bit 0 - FINIT"] - #[inline(always)] - pub fn finit(&mut self) -> FINIT_W { - FINIT_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/fs1r.rs b/embassy-stm32/src/can/bx/pac/can/fs1r.rs deleted file mode 100644 index eea27887b..000000000 --- a/embassy-stm32/src/can/bx/pac/can/fs1r.rs +++ /dev/null @@ -1,492 +0,0 @@ -#[doc = "Reader of register FS1R"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register FS1R"] -pub type W = crate::can::bx::W; -#[doc = "Register FS1R `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::FS1R { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `FSC0`"] -pub type FSC0_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC0`"] -pub struct FSC0_W<'a> { - w: &'a mut W, -} -impl<'a> FSC0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -#[doc = "Reader of field `FSC1`"] -pub type FSC1_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC1`"] -pub struct FSC1_W<'a> { - w: &'a mut W, -} -impl<'a> FSC1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); - self.w - } -} -#[doc = "Reader of field `FSC2`"] -pub type FSC2_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC2`"] -pub struct FSC2_W<'a> { - w: &'a mut W, -} -impl<'a> FSC2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "Reader of field `FSC3`"] -pub type FSC3_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC3`"] -pub struct FSC3_W<'a> { - w: &'a mut W, -} -impl<'a> FSC3_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "Reader of field `FSC4`"] -pub type FSC4_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC4`"] -pub struct FSC4_W<'a> { - w: &'a mut W, -} -impl<'a> FSC4_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); - self.w - } -} -#[doc = "Reader of field `FSC5`"] -pub type FSC5_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC5`"] -pub struct FSC5_W<'a> { - w: &'a mut W, -} -impl<'a> FSC5_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); - self.w - } -} -#[doc = "Reader of field `FSC6`"] -pub type FSC6_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC6`"] -pub struct FSC6_W<'a> { - w: &'a mut W, -} -impl<'a> FSC6_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); - self.w - } -} -#[doc = "Reader of field `FSC7`"] -pub type FSC7_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC7`"] -pub struct FSC7_W<'a> { - w: &'a mut W, -} -impl<'a> FSC7_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); - self.w - } -} -#[doc = "Reader of field `FSC8`"] -pub type FSC8_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC8`"] -pub struct FSC8_W<'a> { - w: &'a mut W, -} -impl<'a> FSC8_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); - self.w - } -} -#[doc = "Reader of field `FSC9`"] -pub type FSC9_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC9`"] -pub struct FSC9_W<'a> { - w: &'a mut W, -} -impl<'a> FSC9_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); - self.w - } -} -#[doc = "Reader of field `FSC10`"] -pub type FSC10_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC10`"] -pub struct FSC10_W<'a> { - w: &'a mut W, -} -impl<'a> FSC10_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); - self.w - } -} -#[doc = "Reader of field `FSC11`"] -pub type FSC11_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC11`"] -pub struct FSC11_W<'a> { - w: &'a mut W, -} -impl<'a> FSC11_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); - self.w - } -} -#[doc = "Reader of field `FSC12`"] -pub type FSC12_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC12`"] -pub struct FSC12_W<'a> { - w: &'a mut W, -} -impl<'a> FSC12_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 12)) | (((value as u32) & 0x01) << 12); - self.w - } -} -#[doc = "Reader of field `FSC13`"] -pub type FSC13_R = crate::can::bx::R; -#[doc = "Write proxy for field `FSC13`"] -pub struct FSC13_W<'a> { - w: &'a mut W, -} -impl<'a> FSC13_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 13)) | (((value as u32) & 0x01) << 13); - self.w - } -} -impl R { - #[doc = "Bit 0 - Filter scale configuration"] - #[inline(always)] - pub fn fsc0(&self) -> FSC0_R { - FSC0_R::new((self.bits & 0x01) != 0) - } - #[doc = "Bit 1 - Filter scale configuration"] - #[inline(always)] - pub fn fsc1(&self) -> FSC1_R { - FSC1_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 2 - Filter scale configuration"] - #[inline(always)] - pub fn fsc2(&self) -> FSC2_R { - FSC2_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 3 - Filter scale configuration"] - #[inline(always)] - pub fn fsc3(&self) -> FSC3_R { - FSC3_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bit 4 - Filter scale configuration"] - #[inline(always)] - pub fn fsc4(&self) -> FSC4_R { - FSC4_R::new(((self.bits >> 4) & 0x01) != 0) - } - #[doc = "Bit 5 - Filter scale configuration"] - #[inline(always)] - pub fn fsc5(&self) -> FSC5_R { - FSC5_R::new(((self.bits >> 5) & 0x01) != 0) - } - #[doc = "Bit 6 - Filter scale configuration"] - #[inline(always)] - pub fn fsc6(&self) -> FSC6_R { - FSC6_R::new(((self.bits >> 6) & 0x01) != 0) - } - #[doc = "Bit 7 - Filter scale configuration"] - #[inline(always)] - pub fn fsc7(&self) -> FSC7_R { - FSC7_R::new(((self.bits >> 7) & 0x01) != 0) - } - #[doc = "Bit 8 - Filter scale configuration"] - #[inline(always)] - pub fn fsc8(&self) -> FSC8_R { - FSC8_R::new(((self.bits >> 8) & 0x01) != 0) - } - #[doc = "Bit 9 - Filter scale configuration"] - #[inline(always)] - pub fn fsc9(&self) -> FSC9_R { - FSC9_R::new(((self.bits >> 9) & 0x01) != 0) - } - #[doc = "Bit 10 - Filter scale configuration"] - #[inline(always)] - pub fn fsc10(&self) -> FSC10_R { - FSC10_R::new(((self.bits >> 10) & 0x01) != 0) - } - #[doc = "Bit 11 - Filter scale configuration"] - #[inline(always)] - pub fn fsc11(&self) -> FSC11_R { - FSC11_R::new(((self.bits >> 11) & 0x01) != 0) - } - #[doc = "Bit 12 - Filter scale configuration"] - #[inline(always)] - pub fn fsc12(&self) -> FSC12_R { - FSC12_R::new(((self.bits >> 12) & 0x01) != 0) - } - #[doc = "Bit 13 - Filter scale configuration"] - #[inline(always)] - pub fn fsc13(&self) -> FSC13_R { - FSC13_R::new(((self.bits >> 13) & 0x01) != 0) - } -} -impl W { - #[doc = "Bit 0 - Filter scale configuration"] - #[inline(always)] - pub fn fsc0(&mut self) -> FSC0_W { - FSC0_W { w: self } - } - #[doc = "Bit 1 - Filter scale configuration"] - #[inline(always)] - pub fn fsc1(&mut self) -> FSC1_W { - FSC1_W { w: self } - } - #[doc = "Bit 2 - Filter scale configuration"] - #[inline(always)] - pub fn fsc2(&mut self) -> FSC2_W { - FSC2_W { w: self } - } - #[doc = "Bit 3 - Filter scale configuration"] - #[inline(always)] - pub fn fsc3(&mut self) -> FSC3_W { - FSC3_W { w: self } - } - #[doc = "Bit 4 - Filter scale configuration"] - #[inline(always)] - pub fn fsc4(&mut self) -> FSC4_W { - FSC4_W { w: self } - } - #[doc = "Bit 5 - Filter scale configuration"] - #[inline(always)] - pub fn fsc5(&mut self) -> FSC5_W { - FSC5_W { w: self } - } - #[doc = "Bit 6 - Filter scale configuration"] - #[inline(always)] - pub fn fsc6(&mut self) -> FSC6_W { - FSC6_W { w: self } - } - #[doc = "Bit 7 - Filter scale configuration"] - #[inline(always)] - pub fn fsc7(&mut self) -> FSC7_W { - FSC7_W { w: self } - } - #[doc = "Bit 8 - Filter scale configuration"] - #[inline(always)] - pub fn fsc8(&mut self) -> FSC8_W { - FSC8_W { w: self } - } - #[doc = "Bit 9 - Filter scale configuration"] - #[inline(always)] - pub fn fsc9(&mut self) -> FSC9_W { - FSC9_W { w: self } - } - #[doc = "Bit 10 - Filter scale configuration"] - #[inline(always)] - pub fn fsc10(&mut self) -> FSC10_W { - FSC10_W { w: self } - } - #[doc = "Bit 11 - Filter scale configuration"] - #[inline(always)] - pub fn fsc11(&mut self) -> FSC11_W { - FSC11_W { w: self } - } - #[doc = "Bit 12 - Filter scale configuration"] - #[inline(always)] - pub fn fsc12(&mut self) -> FSC12_W { - FSC12_W { w: self } - } - #[doc = "Bit 13 - Filter scale configuration"] - #[inline(always)] - pub fn fsc13(&mut self) -> FSC13_W { - FSC13_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/ier.rs b/embassy-stm32/src/can/bx/pac/can/ier.rs deleted file mode 100644 index fa73254b7..000000000 --- a/embassy-stm32/src/can/bx/pac/can/ier.rs +++ /dev/null @@ -1,1218 +0,0 @@ -#[doc = "Reader of register IER"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register IER"] -pub type W = crate::can::bx::W; -#[doc = "Register IER `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::IER { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "SLKIE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum SLKIE_A { - #[doc = "0: No interrupt when SLAKI bit is set"] - DISABLED = 0, - #[doc = "1: Interrupt generated when SLAKI bit is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: SLKIE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `SLKIE`"] -pub type SLKIE_R = crate::can::bx::R; -impl SLKIE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> SLKIE_A { - match self.bits { - false => SLKIE_A::DISABLED, - true => SLKIE_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == SLKIE_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == SLKIE_A::ENABLED - } -} -#[doc = "Write proxy for field `SLKIE`"] -pub struct SLKIE_W<'a> { - w: &'a mut W, -} -impl<'a> SLKIE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: SLKIE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt when SLAKI bit is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(SLKIE_A::DISABLED) - } - #[doc = "Interrupt generated when SLAKI bit is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(SLKIE_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 17)) | (((value as u32) & 0x01) << 17); - self.w - } -} -#[doc = "WKUIE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum WKUIE_A { - #[doc = "0: No interrupt when WKUI is set"] - DISABLED = 0, - #[doc = "1: Interrupt generated when WKUI bit is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: WKUIE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `WKUIE`"] -pub type WKUIE_R = crate::can::bx::R; -impl WKUIE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> WKUIE_A { - match self.bits { - false => WKUIE_A::DISABLED, - true => WKUIE_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == WKUIE_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == WKUIE_A::ENABLED - } -} -#[doc = "Write proxy for field `WKUIE`"] -pub struct WKUIE_W<'a> { - w: &'a mut W, -} -impl<'a> WKUIE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: WKUIE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt when WKUI is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(WKUIE_A::DISABLED) - } - #[doc = "Interrupt generated when WKUI bit is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(WKUIE_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 16)) | (((value as u32) & 0x01) << 16); - self.w - } -} -#[doc = "ERRIE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum ERRIE_A { - #[doc = "0: No interrupt will be generated when an error condition is pending in the CAN_ESR"] - DISABLED = 0, - #[doc = "1: An interrupt will be generation when an error condition is pending in the CAN_ESR"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: ERRIE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `ERRIE`"] -pub type ERRIE_R = crate::can::bx::R; -impl ERRIE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> ERRIE_A { - match self.bits { - false => ERRIE_A::DISABLED, - true => ERRIE_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == ERRIE_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == ERRIE_A::ENABLED - } -} -#[doc = "Write proxy for field `ERRIE`"] -pub struct ERRIE_W<'a> { - w: &'a mut W, -} -impl<'a> ERRIE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: ERRIE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt will be generated when an error condition is pending in the CAN_ESR"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(ERRIE_A::DISABLED) - } - #[doc = "An interrupt will be generation when an error condition is pending in the CAN_ESR"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(ERRIE_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 15)) | (((value as u32) & 0x01) << 15); - self.w - } -} -#[doc = "LECIE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum LECIE_A { - #[doc = "0: ERRI bit will not be set when the error code in LEC\\[2:0\\] -is set by hardware on error detection"] - DISABLED = 0, - #[doc = "1: ERRI bit will be set when the error code in LEC\\[2:0\\] -is set by hardware on error detection"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: LECIE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `LECIE`"] -pub type LECIE_R = crate::can::bx::R; -impl LECIE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> LECIE_A { - match self.bits { - false => LECIE_A::DISABLED, - true => LECIE_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == LECIE_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == LECIE_A::ENABLED - } -} -#[doc = "Write proxy for field `LECIE`"] -pub struct LECIE_W<'a> { - w: &'a mut W, -} -impl<'a> LECIE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: LECIE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "ERRI bit will not be set when the error code in LEC\\[2:0\\] -is set by hardware on error detection"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(LECIE_A::DISABLED) - } - #[doc = "ERRI bit will be set when the error code in LEC\\[2:0\\] -is set by hardware on error detection"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(LECIE_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); - self.w - } -} -#[doc = "BOFIE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum BOFIE_A { - #[doc = "0: ERRI bit will not be set when BOFF is set"] - DISABLED = 0, - #[doc = "1: ERRI bit will be set when BOFF is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: BOFIE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `BOFIE`"] -pub type BOFIE_R = crate::can::bx::R; -impl BOFIE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> BOFIE_A { - match self.bits { - false => BOFIE_A::DISABLED, - true => BOFIE_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == BOFIE_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == BOFIE_A::ENABLED - } -} -#[doc = "Write proxy for field `BOFIE`"] -pub struct BOFIE_W<'a> { - w: &'a mut W, -} -impl<'a> BOFIE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: BOFIE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "ERRI bit will not be set when BOFF is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(BOFIE_A::DISABLED) - } - #[doc = "ERRI bit will be set when BOFF is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(BOFIE_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); - self.w - } -} -#[doc = "EPVIE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum EPVIE_A { - #[doc = "0: ERRI bit will not be set when EPVF is set"] - DISABLED = 0, - #[doc = "1: ERRI bit will be set when EPVF is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: EPVIE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `EPVIE`"] -pub type EPVIE_R = crate::can::bx::R; -impl EPVIE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> EPVIE_A { - match self.bits { - false => EPVIE_A::DISABLED, - true => EPVIE_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == EPVIE_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == EPVIE_A::ENABLED - } -} -#[doc = "Write proxy for field `EPVIE`"] -pub struct EPVIE_W<'a> { - w: &'a mut W, -} -impl<'a> EPVIE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: EPVIE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "ERRI bit will not be set when EPVF is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(EPVIE_A::DISABLED) - } - #[doc = "ERRI bit will be set when EPVF is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(EPVIE_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); - self.w - } -} -#[doc = "EWGIE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum EWGIE_A { - #[doc = "0: ERRI bit will not be set when EWGF is set"] - DISABLED = 0, - #[doc = "1: ERRI bit will be set when EWGF is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: EWGIE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `EWGIE`"] -pub type EWGIE_R = crate::can::bx::R; -impl EWGIE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> EWGIE_A { - match self.bits { - false => EWGIE_A::DISABLED, - true => EWGIE_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == EWGIE_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == EWGIE_A::ENABLED - } -} -#[doc = "Write proxy for field `EWGIE`"] -pub struct EWGIE_W<'a> { - w: &'a mut W, -} -impl<'a> EWGIE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: EWGIE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "ERRI bit will not be set when EWGF is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(EWGIE_A::DISABLED) - } - #[doc = "ERRI bit will be set when EWGF is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(EWGIE_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); - self.w - } -} -#[doc = "FOVIE1\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FOVIE1_A { - #[doc = "0: No interrupt when FOVR is set"] - DISABLED = 0, - #[doc = "1: Interrupt generation when FOVR is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FOVIE1_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `FOVIE1`"] -pub type FOVIE1_R = crate::can::bx::R; -impl FOVIE1_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> FOVIE1_A { - match self.bits { - false => FOVIE1_A::DISABLED, - true => FOVIE1_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == FOVIE1_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == FOVIE1_A::ENABLED - } -} -#[doc = "Write proxy for field `FOVIE1`"] -pub struct FOVIE1_W<'a> { - w: &'a mut W, -} -impl<'a> FOVIE1_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: FOVIE1_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt when FOVR is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(FOVIE1_A::DISABLED) - } - #[doc = "Interrupt generation when FOVR is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(FOVIE1_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); - self.w - } -} -#[doc = "FFIE1\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FFIE1_A { - #[doc = "0: No interrupt when FULL bit is set"] - DISABLED = 0, - #[doc = "1: Interrupt generated when FULL bit is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FFIE1_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `FFIE1`"] -pub type FFIE1_R = crate::can::bx::R; -impl FFIE1_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> FFIE1_A { - match self.bits { - false => FFIE1_A::DISABLED, - true => FFIE1_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == FFIE1_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == FFIE1_A::ENABLED - } -} -#[doc = "Write proxy for field `FFIE1`"] -pub struct FFIE1_W<'a> { - w: &'a mut W, -} -impl<'a> FFIE1_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: FFIE1_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt when FULL bit is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(FFIE1_A::DISABLED) - } - #[doc = "Interrupt generated when FULL bit is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(FFIE1_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); - self.w - } -} -#[doc = "FMPIE1\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FMPIE1_A { - #[doc = "0: No interrupt generated when state of FMP\\[1:0\\] -bits are not 00b"] - DISABLED = 0, - #[doc = "1: Interrupt generated when state of FMP\\[1:0\\] -bits are not 00b"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FMPIE1_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `FMPIE1`"] -pub type FMPIE1_R = crate::can::bx::R; -impl FMPIE1_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> FMPIE1_A { - match self.bits { - false => FMPIE1_A::DISABLED, - true => FMPIE1_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == FMPIE1_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == FMPIE1_A::ENABLED - } -} -#[doc = "Write proxy for field `FMPIE1`"] -pub struct FMPIE1_W<'a> { - w: &'a mut W, -} -impl<'a> FMPIE1_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: FMPIE1_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt generated when state of FMP\\[1:0\\] -bits are not 00b"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(FMPIE1_A::DISABLED) - } - #[doc = "Interrupt generated when state of FMP\\[1:0\\] -bits are not 00b"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(FMPIE1_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); - self.w - } -} -#[doc = "FOVIE0\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FOVIE0_A { - #[doc = "0: No interrupt when FOVR bit is set"] - DISABLED = 0, - #[doc = "1: Interrupt generated when FOVR bit is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FOVIE0_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `FOVIE0`"] -pub type FOVIE0_R = crate::can::bx::R; -impl FOVIE0_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> FOVIE0_A { - match self.bits { - false => FOVIE0_A::DISABLED, - true => FOVIE0_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == FOVIE0_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == FOVIE0_A::ENABLED - } -} -#[doc = "Write proxy for field `FOVIE0`"] -pub struct FOVIE0_W<'a> { - w: &'a mut W, -} -impl<'a> FOVIE0_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: FOVIE0_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt when FOVR bit is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(FOVIE0_A::DISABLED) - } - #[doc = "Interrupt generated when FOVR bit is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(FOVIE0_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "FFIE0\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FFIE0_A { - #[doc = "0: No interrupt when FULL bit is set"] - DISABLED = 0, - #[doc = "1: Interrupt generated when FULL bit is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FFIE0_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `FFIE0`"] -pub type FFIE0_R = crate::can::bx::R; -impl FFIE0_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> FFIE0_A { - match self.bits { - false => FFIE0_A::DISABLED, - true => FFIE0_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == FFIE0_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == FFIE0_A::ENABLED - } -} -#[doc = "Write proxy for field `FFIE0`"] -pub struct FFIE0_W<'a> { - w: &'a mut W, -} -impl<'a> FFIE0_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: FFIE0_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt when FULL bit is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(FFIE0_A::DISABLED) - } - #[doc = "Interrupt generated when FULL bit is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(FFIE0_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "FMPIE0\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FMPIE0_A { - #[doc = "0: No interrupt generated when state of FMP\\[1:0\\] -bits are not 00"] - DISABLED = 0, - #[doc = "1: Interrupt generated when state of FMP\\[1:0\\] -bits are not 00b"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FMPIE0_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `FMPIE0`"] -pub type FMPIE0_R = crate::can::bx::R; -impl FMPIE0_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> FMPIE0_A { - match self.bits { - false => FMPIE0_A::DISABLED, - true => FMPIE0_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == FMPIE0_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == FMPIE0_A::ENABLED - } -} -#[doc = "Write proxy for field `FMPIE0`"] -pub struct FMPIE0_W<'a> { - w: &'a mut W, -} -impl<'a> FMPIE0_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: FMPIE0_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt generated when state of FMP\\[1:0\\] -bits are not 00"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(FMPIE0_A::DISABLED) - } - #[doc = "Interrupt generated when state of FMP\\[1:0\\] -bits are not 00b"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(FMPIE0_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); - self.w - } -} -#[doc = "TMEIE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum TMEIE_A { - #[doc = "0: No interrupt when RQCPx bit is set"] - DISABLED = 0, - #[doc = "1: Interrupt generated when RQCPx bit is set"] - ENABLED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: TMEIE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `TMEIE`"] -pub type TMEIE_R = crate::can::bx::R; -impl TMEIE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> TMEIE_A { - match self.bits { - false => TMEIE_A::DISABLED, - true => TMEIE_A::ENABLED, - } - } - #[doc = "Checks if the value of the field is `DISABLED`"] - #[inline(always)] - pub fn is_disabled(&self) -> bool { - *self == TMEIE_A::DISABLED - } - #[doc = "Checks if the value of the field is `ENABLED`"] - #[inline(always)] - pub fn is_enabled(&self) -> bool { - *self == TMEIE_A::ENABLED - } -} -#[doc = "Write proxy for field `TMEIE`"] -pub struct TMEIE_W<'a> { - w: &'a mut W, -} -impl<'a> TMEIE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: TMEIE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "No interrupt when RQCPx bit is set"] - #[inline(always)] - pub fn disabled(self) -> &'a mut W { - self.variant(TMEIE_A::DISABLED) - } - #[doc = "Interrupt generated when RQCPx bit is set"] - #[inline(always)] - pub fn enabled(self) -> &'a mut W { - self.variant(TMEIE_A::ENABLED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -impl R { - #[doc = "Bit 17 - SLKIE"] - #[inline(always)] - pub fn slkie(&self) -> SLKIE_R { - SLKIE_R::new(((self.bits >> 17) & 0x01) != 0) - } - #[doc = "Bit 16 - WKUIE"] - #[inline(always)] - pub fn wkuie(&self) -> WKUIE_R { - WKUIE_R::new(((self.bits >> 16) & 0x01) != 0) - } - #[doc = "Bit 15 - ERRIE"] - #[inline(always)] - pub fn errie(&self) -> ERRIE_R { - ERRIE_R::new(((self.bits >> 15) & 0x01) != 0) - } - #[doc = "Bit 11 - LECIE"] - #[inline(always)] - pub fn lecie(&self) -> LECIE_R { - LECIE_R::new(((self.bits >> 11) & 0x01) != 0) - } - #[doc = "Bit 10 - BOFIE"] - #[inline(always)] - pub fn bofie(&self) -> BOFIE_R { - BOFIE_R::new(((self.bits >> 10) & 0x01) != 0) - } - #[doc = "Bit 9 - EPVIE"] - #[inline(always)] - pub fn epvie(&self) -> EPVIE_R { - EPVIE_R::new(((self.bits >> 9) & 0x01) != 0) - } - #[doc = "Bit 8 - EWGIE"] - #[inline(always)] - pub fn ewgie(&self) -> EWGIE_R { - EWGIE_R::new(((self.bits >> 8) & 0x01) != 0) - } - #[doc = "Bit 6 - FOVIE1"] - #[inline(always)] - pub fn fovie1(&self) -> FOVIE1_R { - FOVIE1_R::new(((self.bits >> 6) & 0x01) != 0) - } - #[doc = "Bit 5 - FFIE1"] - #[inline(always)] - pub fn ffie1(&self) -> FFIE1_R { - FFIE1_R::new(((self.bits >> 5) & 0x01) != 0) - } - #[doc = "Bit 4 - FMPIE1"] - #[inline(always)] - pub fn fmpie1(&self) -> FMPIE1_R { - FMPIE1_R::new(((self.bits >> 4) & 0x01) != 0) - } - #[doc = "Bit 3 - FOVIE0"] - #[inline(always)] - pub fn fovie0(&self) -> FOVIE0_R { - FOVIE0_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bit 2 - FFIE0"] - #[inline(always)] - pub fn ffie0(&self) -> FFIE0_R { - FFIE0_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 1 - FMPIE0"] - #[inline(always)] - pub fn fmpie0(&self) -> FMPIE0_R { - FMPIE0_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 0 - TMEIE"] - #[inline(always)] - pub fn tmeie(&self) -> TMEIE_R { - TMEIE_R::new((self.bits & 0x01) != 0) - } -} -impl W { - #[doc = "Bit 17 - SLKIE"] - #[inline(always)] - pub fn slkie(&mut self) -> SLKIE_W { - SLKIE_W { w: self } - } - #[doc = "Bit 16 - WKUIE"] - #[inline(always)] - pub fn wkuie(&mut self) -> WKUIE_W { - WKUIE_W { w: self } - } - #[doc = "Bit 15 - ERRIE"] - #[inline(always)] - pub fn errie(&mut self) -> ERRIE_W { - ERRIE_W { w: self } - } - #[doc = "Bit 11 - LECIE"] - #[inline(always)] - pub fn lecie(&mut self) -> LECIE_W { - LECIE_W { w: self } - } - #[doc = "Bit 10 - BOFIE"] - #[inline(always)] - pub fn bofie(&mut self) -> BOFIE_W { - BOFIE_W { w: self } - } - #[doc = "Bit 9 - EPVIE"] - #[inline(always)] - pub fn epvie(&mut self) -> EPVIE_W { - EPVIE_W { w: self } - } - #[doc = "Bit 8 - EWGIE"] - #[inline(always)] - pub fn ewgie(&mut self) -> EWGIE_W { - EWGIE_W { w: self } - } - #[doc = "Bit 6 - FOVIE1"] - #[inline(always)] - pub fn fovie1(&mut self) -> FOVIE1_W { - FOVIE1_W { w: self } - } - #[doc = "Bit 5 - FFIE1"] - #[inline(always)] - pub fn ffie1(&mut self) -> FFIE1_W { - FFIE1_W { w: self } - } - #[doc = "Bit 4 - FMPIE1"] - #[inline(always)] - pub fn fmpie1(&mut self) -> FMPIE1_W { - FMPIE1_W { w: self } - } - #[doc = "Bit 3 - FOVIE0"] - #[inline(always)] - pub fn fovie0(&mut self) -> FOVIE0_W { - FOVIE0_W { w: self } - } - #[doc = "Bit 2 - FFIE0"] - #[inline(always)] - pub fn ffie0(&mut self) -> FFIE0_W { - FFIE0_W { w: self } - } - #[doc = "Bit 1 - FMPIE0"] - #[inline(always)] - pub fn fmpie0(&mut self) -> FMPIE0_W { - FMPIE0_W { w: self } - } - #[doc = "Bit 0 - TMEIE"] - #[inline(always)] - pub fn tmeie(&mut self) -> TMEIE_W { - TMEIE_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/mcr.rs b/embassy-stm32/src/can/bx/pac/can/mcr.rs deleted file mode 100644 index bce9561d9..000000000 --- a/embassy-stm32/src/can/bx/pac/can/mcr.rs +++ /dev/null @@ -1,356 +0,0 @@ -#[doc = "Reader of register MCR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register MCR"] -pub type W = crate::can::bx::W; -#[doc = "Register MCR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::MCR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `DBF`"] -pub type DBF_R = crate::can::bx::R; -#[doc = "Write proxy for field `DBF`"] -pub struct DBF_W<'a> { - w: &'a mut W, -} -impl<'a> DBF_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 16)) | (((value as u32) & 0x01) << 16); - self.w - } -} -#[doc = "Reader of field `RESET`"] -pub type RESET_R = crate::can::bx::R; -#[doc = "Write proxy for field `RESET`"] -pub struct RESET_W<'a> { - w: &'a mut W, -} -impl<'a> RESET_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 15)) | (((value as u32) & 0x01) << 15); - self.w - } -} -#[doc = "Reader of field `TTCM`"] -pub type TTCM_R = crate::can::bx::R; -#[doc = "Write proxy for field `TTCM`"] -pub struct TTCM_W<'a> { - w: &'a mut W, -} -impl<'a> TTCM_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); - self.w - } -} -#[doc = "Reader of field `ABOM`"] -pub type ABOM_R = crate::can::bx::R; -#[doc = "Write proxy for field `ABOM`"] -pub struct ABOM_W<'a> { - w: &'a mut W, -} -impl<'a> ABOM_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 6)) | (((value as u32) & 0x01) << 6); - self.w - } -} -#[doc = "Reader of field `AWUM`"] -pub type AWUM_R = crate::can::bx::R; -#[doc = "Write proxy for field `AWUM`"] -pub struct AWUM_W<'a> { - w: &'a mut W, -} -impl<'a> AWUM_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); - self.w - } -} -#[doc = "Reader of field `NART`"] -pub type NART_R = crate::can::bx::R; -#[doc = "Write proxy for field `NART`"] -pub struct NART_W<'a> { - w: &'a mut W, -} -impl<'a> NART_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); - self.w - } -} -#[doc = "Reader of field `RFLM`"] -pub type RFLM_R = crate::can::bx::R; -#[doc = "Write proxy for field `RFLM`"] -pub struct RFLM_W<'a> { - w: &'a mut W, -} -impl<'a> RFLM_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "Reader of field `TXFP`"] -pub type TXFP_R = crate::can::bx::R; -#[doc = "Write proxy for field `TXFP`"] -pub struct TXFP_W<'a> { - w: &'a mut W, -} -impl<'a> TXFP_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "Reader of field `SLEEP`"] -pub type SLEEP_R = crate::can::bx::R; -#[doc = "Write proxy for field `SLEEP`"] -pub struct SLEEP_W<'a> { - w: &'a mut W, -} -impl<'a> SLEEP_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); - self.w - } -} -#[doc = "Reader of field `INRQ`"] -pub type INRQ_R = crate::can::bx::R; -#[doc = "Write proxy for field `INRQ`"] -pub struct INRQ_W<'a> { - w: &'a mut W, -} -impl<'a> INRQ_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -impl R { - #[doc = "Bit 16 - DBF"] - #[inline(always)] - pub fn dbf(&self) -> DBF_R { - DBF_R::new(((self.bits >> 16) & 0x01) != 0) - } - #[doc = "Bit 15 - RESET"] - #[inline(always)] - pub fn reset(&self) -> RESET_R { - RESET_R::new(((self.bits >> 15) & 0x01) != 0) - } - #[doc = "Bit 7 - TTCM"] - #[inline(always)] - pub fn ttcm(&self) -> TTCM_R { - TTCM_R::new(((self.bits >> 7) & 0x01) != 0) - } - #[doc = "Bit 6 - ABOM"] - #[inline(always)] - pub fn abom(&self) -> ABOM_R { - ABOM_R::new(((self.bits >> 6) & 0x01) != 0) - } - #[doc = "Bit 5 - AWUM"] - #[inline(always)] - pub fn awum(&self) -> AWUM_R { - AWUM_R::new(((self.bits >> 5) & 0x01) != 0) - } - #[doc = "Bit 4 - NART"] - #[inline(always)] - pub fn nart(&self) -> NART_R { - NART_R::new(((self.bits >> 4) & 0x01) != 0) - } - #[doc = "Bit 3 - RFLM"] - #[inline(always)] - pub fn rflm(&self) -> RFLM_R { - RFLM_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bit 2 - TXFP"] - #[inline(always)] - pub fn txfp(&self) -> TXFP_R { - TXFP_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 1 - SLEEP"] - #[inline(always)] - pub fn sleep(&self) -> SLEEP_R { - SLEEP_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 0 - INRQ"] - #[inline(always)] - pub fn inrq(&self) -> INRQ_R { - INRQ_R::new((self.bits & 0x01) != 0) - } -} -impl W { - #[doc = "Bit 16 - DBF"] - #[inline(always)] - pub fn dbf(&mut self) -> DBF_W { - DBF_W { w: self } - } - #[doc = "Bit 15 - RESET"] - #[inline(always)] - pub fn reset(&mut self) -> RESET_W { - RESET_W { w: self } - } - #[doc = "Bit 7 - TTCM"] - #[inline(always)] - pub fn ttcm(&mut self) -> TTCM_W { - TTCM_W { w: self } - } - #[doc = "Bit 6 - ABOM"] - #[inline(always)] - pub fn abom(&mut self) -> ABOM_W { - ABOM_W { w: self } - } - #[doc = "Bit 5 - AWUM"] - #[inline(always)] - pub fn awum(&mut self) -> AWUM_W { - AWUM_W { w: self } - } - #[doc = "Bit 4 - NART"] - #[inline(always)] - pub fn nart(&mut self) -> NART_W { - NART_W { w: self } - } - #[doc = "Bit 3 - RFLM"] - #[inline(always)] - pub fn rflm(&mut self) -> RFLM_W { - RFLM_W { w: self } - } - #[doc = "Bit 2 - TXFP"] - #[inline(always)] - pub fn txfp(&mut self) -> TXFP_W { - TXFP_W { w: self } - } - #[doc = "Bit 1 - SLEEP"] - #[inline(always)] - pub fn sleep(&mut self) -> SLEEP_W { - SLEEP_W { w: self } - } - #[doc = "Bit 0 - INRQ"] - #[inline(always)] - pub fn inrq(&mut self) -> INRQ_W { - INRQ_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/msr.rs b/embassy-stm32/src/can/bx/pac/can/msr.rs deleted file mode 100644 index 2e076b14e..000000000 --- a/embassy-stm32/src/can/bx/pac/can/msr.rs +++ /dev/null @@ -1,160 +0,0 @@ -#[doc = "Reader of register MSR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register MSR"] -pub type W = crate::can::bx::W; -#[doc = "Register MSR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::MSR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `RX`"] -pub type RX_R = crate::can::bx::R; -#[doc = "Reader of field `SAMP`"] -pub type SAMP_R = crate::can::bx::R; -#[doc = "Reader of field `RXM`"] -pub type RXM_R = crate::can::bx::R; -#[doc = "Reader of field `TXM`"] -pub type TXM_R = crate::can::bx::R; -#[doc = "Reader of field `SLAKI`"] -pub type SLAKI_R = crate::can::bx::R; -#[doc = "Write proxy for field `SLAKI`"] -pub struct SLAKI_W<'a> { - w: &'a mut W, -} -impl<'a> SLAKI_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); - self.w - } -} -#[doc = "Reader of field `WKUI`"] -pub type WKUI_R = crate::can::bx::R; -#[doc = "Write proxy for field `WKUI`"] -pub struct WKUI_W<'a> { - w: &'a mut W, -} -impl<'a> WKUI_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "Reader of field `ERRI`"] -pub type ERRI_R = crate::can::bx::R; -#[doc = "Write proxy for field `ERRI`"] -pub struct ERRI_W<'a> { - w: &'a mut W, -} -impl<'a> ERRI_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "Reader of field `SLAK`"] -pub type SLAK_R = crate::can::bx::R; -#[doc = "Reader of field `INAK`"] -pub type INAK_R = crate::can::bx::R; -impl R { - #[doc = "Bit 11 - RX"] - #[inline(always)] - pub fn rx(&self) -> RX_R { - RX_R::new(((self.bits >> 11) & 0x01) != 0) - } - #[doc = "Bit 10 - SAMP"] - #[inline(always)] - pub fn samp(&self) -> SAMP_R { - SAMP_R::new(((self.bits >> 10) & 0x01) != 0) - } - #[doc = "Bit 9 - RXM"] - #[inline(always)] - pub fn rxm(&self) -> RXM_R { - RXM_R::new(((self.bits >> 9) & 0x01) != 0) - } - #[doc = "Bit 8 - TXM"] - #[inline(always)] - pub fn txm(&self) -> TXM_R { - TXM_R::new(((self.bits >> 8) & 0x01) != 0) - } - #[doc = "Bit 4 - SLAKI"] - #[inline(always)] - pub fn slaki(&self) -> SLAKI_R { - SLAKI_R::new(((self.bits >> 4) & 0x01) != 0) - } - #[doc = "Bit 3 - WKUI"] - #[inline(always)] - pub fn wkui(&self) -> WKUI_R { - WKUI_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bit 2 - ERRI"] - #[inline(always)] - pub fn erri(&self) -> ERRI_R { - ERRI_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 1 - SLAK"] - #[inline(always)] - pub fn slak(&self) -> SLAK_R { - SLAK_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 0 - INAK"] - #[inline(always)] - pub fn inak(&self) -> INAK_R { - INAK_R::new((self.bits & 0x01) != 0) - } -} -impl W { - #[doc = "Bit 4 - SLAKI"] - #[inline(always)] - pub fn slaki(&mut self) -> SLAKI_W { - SLAKI_W { w: self } - } - #[doc = "Bit 3 - WKUI"] - #[inline(always)] - pub fn wkui(&mut self) -> WKUI_W { - WKUI_W { w: self } - } - #[doc = "Bit 2 - ERRI"] - #[inline(always)] - pub fn erri(&mut self) -> ERRI_W { - ERRI_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/rfr.rs b/embassy-stm32/src/can/bx/pac/can/rfr.rs deleted file mode 100644 index 1a4047cb4..000000000 --- a/embassy-stm32/src/can/bx/pac/can/rfr.rs +++ /dev/null @@ -1,281 +0,0 @@ -#[doc = "Reader of register RF%sR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register RF%sR"] -pub type W = crate::can::bx::W; -#[doc = "Register RF%sR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::RFR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "RFOM0\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum RFOM_A { - #[doc = "1: Set by software to release the output mailbox of the FIFO"] - RELEASE = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: RFOM_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `RFOM`"] -pub type RFOM_R = crate::can::bx::R; -impl RFOM_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> crate::can::bx::Variant { - use crate::can::bx::Variant::*; - match self.bits { - true => Val(RFOM_A::RELEASE), - i => Res(i), - } - } - #[doc = "Checks if the value of the field is `RELEASE`"] - #[inline(always)] - pub fn is_release(&self) -> bool { - *self == RFOM_A::RELEASE - } -} -#[doc = "Write proxy for field `RFOM`"] -pub struct RFOM_W<'a> { - w: &'a mut W, -} -impl<'a> RFOM_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: RFOM_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "Set by software to release the output mailbox of the FIFO"] - #[inline(always)] - pub fn release(self) -> &'a mut W { - self.variant(RFOM_A::RELEASE) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 5)) | (((value as u32) & 0x01) << 5); - self.w - } -} -#[doc = "FOVR0\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FOVR_A { - #[doc = "0: No FIFO x overrun"] - NOOVERRUN = 0, - #[doc = "1: FIFO x overrun"] - OVERRUN = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FOVR_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `FOVR`"] -pub type FOVR_R = crate::can::bx::R; -impl FOVR_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> FOVR_A { - match self.bits { - false => FOVR_A::NOOVERRUN, - true => FOVR_A::OVERRUN, - } - } - #[doc = "Checks if the value of the field is `NOOVERRUN`"] - #[inline(always)] - pub fn is_no_overrun(&self) -> bool { - *self == FOVR_A::NOOVERRUN - } - #[doc = "Checks if the value of the field is `OVERRUN`"] - #[inline(always)] - pub fn is_overrun(&self) -> bool { - *self == FOVR_A::OVERRUN - } -} -#[doc = "FOVR0\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FOVR_AW { - #[doc = "1: Clear flag"] - CLEAR = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FOVR_AW) -> Self { - variant as u8 != 0 - } -} -#[doc = "Write proxy for field `FOVR`"] -pub struct FOVR_W<'a> { - w: &'a mut W, -} -impl<'a> FOVR_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: FOVR_AW) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "Clear flag"] - #[inline(always)] - pub fn clear(self) -> &'a mut W { - self.variant(FOVR_AW::CLEAR) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 4)) | (((value as u32) & 0x01) << 4); - self.w - } -} -#[doc = "FULL0\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FULL_A { - #[doc = "0: FIFO x is not full"] - NOTFULL = 0, - #[doc = "1: FIFO x is full"] - FULL = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FULL_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `FULL`"] -pub type FULL_R = crate::can::bx::R; -impl FULL_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> FULL_A { - match self.bits { - false => FULL_A::NOTFULL, - true => FULL_A::FULL, - } - } - #[doc = "Checks if the value of the field is `NOTFULL`"] - #[inline(always)] - pub fn is_not_full(&self) -> bool { - *self == FULL_A::NOTFULL - } - #[doc = "Checks if the value of the field is `FULL`"] - #[inline(always)] - pub fn is_full(&self) -> bool { - *self == FULL_A::FULL - } -} -#[doc = "FULL0\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FULL_AW { - #[doc = "1: Clear flag"] - CLEAR = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: FULL_AW) -> Self { - variant as u8 != 0 - } -} -#[doc = "Write proxy for field `FULL`"] -pub struct FULL_W<'a> { - w: &'a mut W, -} -impl<'a> FULL_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: FULL_AW) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "Clear flag"] - #[inline(always)] - pub fn clear(self) -> &'a mut W { - self.variant(FULL_AW::CLEAR) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "Reader of field `FMP`"] -pub type FMP_R = crate::can::bx::R; -impl R { - #[doc = "Bit 5 - RFOM0"] - #[inline(always)] - pub fn rfom(&self) -> RFOM_R { - RFOM_R::new(((self.bits >> 5) & 0x01) != 0) - } - #[doc = "Bit 4 - FOVR0"] - #[inline(always)] - pub fn fovr(&self) -> FOVR_R { - FOVR_R::new(((self.bits >> 4) & 0x01) != 0) - } - #[doc = "Bit 3 - FULL0"] - #[inline(always)] - pub fn full(&self) -> FULL_R { - FULL_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bits 0:1 - FMP0"] - #[inline(always)] - pub fn fmp(&self) -> FMP_R { - FMP_R::new((self.bits & 0x03) as u8) - } -} -impl W { - #[doc = "Bit 5 - RFOM0"] - #[inline(always)] - pub fn rfom(&mut self) -> RFOM_W { - RFOM_W { w: self } - } - #[doc = "Bit 4 - FOVR0"] - #[inline(always)] - pub fn fovr(&mut self) -> FOVR_W { - FOVR_W { w: self } - } - #[doc = "Bit 3 - FULL0"] - #[inline(always)] - pub fn full(&mut self) -> FULL_W { - FULL_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/rx.rs b/embassy-stm32/src/can/bx/pac/can/rx.rs deleted file mode 100644 index 58ce7be4a..000000000 --- a/embassy-stm32/src/can/bx/pac/can/rx.rs +++ /dev/null @@ -1,36 +0,0 @@ -#[doc = "CAN_RI0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rir](rir) module"] -pub type RIR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _RIR; -#[doc = "`read()` method returns [rir::R](rir::R) reader structure"] -impl crate::can::bx::Readable for RIR {} -#[doc = "CAN_RI0R"] -pub mod rir; -#[doc = "CAN_RDT0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdtr](rdtr) module"] -pub type RDTR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _RDTR; -#[doc = "`read()` method returns [rdtr::R](rdtr::R) reader structure"] -impl crate::can::bx::Readable for RDTR {} -#[doc = "CAN_RDT0R"] -pub mod rdtr; -#[doc = "CAN_RDL0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdlr](rdlr) module"] -pub type RDLR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _RDLR; -#[doc = "`read()` method returns [rdlr::R](rdlr::R) reader structure"] -impl crate::can::bx::Readable for RDLR {} -#[doc = "CAN_RDL0R"] -pub mod rdlr; -#[doc = "CAN_RDH0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [rdhr](rdhr) module"] -pub type RDHR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _RDHR; -#[doc = "`read()` method returns [rdhr::R](rdhr::R) reader structure"] -impl crate::can::bx::Readable for RDHR {} -#[doc = "CAN_RDH0R"] -pub mod rdhr; diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs deleted file mode 100644 index 0f3ccc307..000000000 --- a/embassy-stm32/src/can/bx/pac/can/rx/rdhr.rs +++ /dev/null @@ -1,32 +0,0 @@ -#[doc = "Reader of register RDHR"] -pub type R = crate::can::bx::R; -#[doc = "Reader of field `DATA7`"] -pub type DATA7_R = crate::can::bx::R; -#[doc = "Reader of field `DATA6`"] -pub type DATA6_R = crate::can::bx::R; -#[doc = "Reader of field `DATA5`"] -pub type DATA5_R = crate::can::bx::R; -#[doc = "Reader of field `DATA4`"] -pub type DATA4_R = crate::can::bx::R; -impl R { - #[doc = "Bits 24:31 - DATA7"] - #[inline(always)] - pub fn data7(&self) -> DATA7_R { - DATA7_R::new(((self.bits >> 24) & 0xff) as u8) - } - #[doc = "Bits 16:23 - DATA6"] - #[inline(always)] - pub fn data6(&self) -> DATA6_R { - DATA6_R::new(((self.bits >> 16) & 0xff) as u8) - } - #[doc = "Bits 8:15 - DATA5"] - #[inline(always)] - pub fn data5(&self) -> DATA5_R { - DATA5_R::new(((self.bits >> 8) & 0xff) as u8) - } - #[doc = "Bits 0:7 - DATA4"] - #[inline(always)] - pub fn data4(&self) -> DATA4_R { - DATA4_R::new((self.bits & 0xff) as u8) - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs deleted file mode 100644 index 16d739540..000000000 --- a/embassy-stm32/src/can/bx/pac/can/rx/rdlr.rs +++ /dev/null @@ -1,32 +0,0 @@ -#[doc = "Reader of register RDLR"] -pub type R = crate::can::bx::R; -#[doc = "Reader of field `DATA3`"] -pub type DATA3_R = crate::can::bx::R; -#[doc = "Reader of field `DATA2`"] -pub type DATA2_R = crate::can::bx::R; -#[doc = "Reader of field `DATA1`"] -pub type DATA1_R = crate::can::bx::R; -#[doc = "Reader of field `DATA0`"] -pub type DATA0_R = crate::can::bx::R; -impl R { - #[doc = "Bits 24:31 - DATA3"] - #[inline(always)] - pub fn data3(&self) -> DATA3_R { - DATA3_R::new(((self.bits >> 24) & 0xff) as u8) - } - #[doc = "Bits 16:23 - DATA2"] - #[inline(always)] - pub fn data2(&self) -> DATA2_R { - DATA2_R::new(((self.bits >> 16) & 0xff) as u8) - } - #[doc = "Bits 8:15 - DATA1"] - #[inline(always)] - pub fn data1(&self) -> DATA1_R { - DATA1_R::new(((self.bits >> 8) & 0xff) as u8) - } - #[doc = "Bits 0:7 - DATA0"] - #[inline(always)] - pub fn data0(&self) -> DATA0_R { - DATA0_R::new((self.bits & 0xff) as u8) - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs b/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs deleted file mode 100644 index 4a48e1f2e..000000000 --- a/embassy-stm32/src/can/bx/pac/can/rx/rdtr.rs +++ /dev/null @@ -1,25 +0,0 @@ -#[doc = "Reader of register RDTR"] -pub type R = crate::can::bx::R; -#[doc = "Reader of field `TIME`"] -pub type TIME_R = crate::can::bx::R; -#[doc = "Reader of field `FMI`"] -pub type FMI_R = crate::can::bx::R; -#[doc = "Reader of field `DLC`"] -pub type DLC_R = crate::can::bx::R; -impl R { - #[doc = "Bits 16:31 - TIME"] - #[inline(always)] - pub fn time(&self) -> TIME_R { - TIME_R::new(((self.bits >> 16) & 0xffff) as u16) - } - #[doc = "Bits 8:15 - FMI"] - #[inline(always)] - pub fn fmi(&self) -> FMI_R { - FMI_R::new(((self.bits >> 8) & 0xff) as u8) - } - #[doc = "Bits 0:3 - DLC"] - #[inline(always)] - pub fn dlc(&self) -> DLC_R { - DLC_R::new((self.bits & 0x0f) as u8) - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/rx/rir.rs b/embassy-stm32/src/can/bx/pac/can/rx/rir.rs deleted file mode 100644 index 22e37b1cd..000000000 --- a/embassy-stm32/src/can/bx/pac/can/rx/rir.rs +++ /dev/null @@ -1,100 +0,0 @@ -#[doc = "Reader of register RIR"] -pub type R = crate::can::bx::R; -#[doc = "Reader of field `STID`"] -pub type STID_R = crate::can::bx::R; -#[doc = "Reader of field `EXID`"] -pub type EXID_R = crate::can::bx::R; -#[doc = "IDE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum IDE_A { - #[doc = "0: Standard identifier"] - STANDARD = 0, - #[doc = "1: Extended identifier"] - EXTENDED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: IDE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `IDE`"] -pub type IDE_R = crate::can::bx::R; -impl IDE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> IDE_A { - match self.bits { - false => IDE_A::STANDARD, - true => IDE_A::EXTENDED, - } - } - #[doc = "Checks if the value of the field is `STANDARD`"] - #[inline(always)] - pub fn is_standard(&self) -> bool { - *self == IDE_A::STANDARD - } - #[doc = "Checks if the value of the field is `EXTENDED`"] - #[inline(always)] - pub fn is_extended(&self) -> bool { - *self == IDE_A::EXTENDED - } -} -#[doc = "RTR\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum RTR_A { - #[doc = "0: Data frame"] - DATA = 0, - #[doc = "1: Remote frame"] - REMOTE = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: RTR_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `RTR`"] -pub type RTR_R = crate::can::bx::R; -impl RTR_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> RTR_A { - match self.bits { - false => RTR_A::DATA, - true => RTR_A::REMOTE, - } - } - #[doc = "Checks if the value of the field is `DATA`"] - #[inline(always)] - pub fn is_data(&self) -> bool { - *self == RTR_A::DATA - } - #[doc = "Checks if the value of the field is `REMOTE`"] - #[inline(always)] - pub fn is_remote(&self) -> bool { - *self == RTR_A::REMOTE - } -} -impl R { - #[doc = "Bits 21:31 - STID"] - #[inline(always)] - pub fn stid(&self) -> STID_R { - STID_R::new(((self.bits >> 21) & 0x07ff) as u16) - } - #[doc = "Bits 3:20 - EXID"] - #[inline(always)] - pub fn exid(&self) -> EXID_R { - EXID_R::new(((self.bits >> 3) & 0x0003_ffff) as u32) - } - #[doc = "Bit 2 - IDE"] - #[inline(always)] - pub fn ide(&self) -> IDE_R { - IDE_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 1 - RTR"] - #[inline(always)] - pub fn rtr(&self) -> RTR_R { - RTR_R::new(((self.bits >> 1) & 0x01) != 0) - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/tsr.rs b/embassy-stm32/src/can/bx/pac/can/tsr.rs deleted file mode 100644 index 3317b7bd5..000000000 --- a/embassy-stm32/src/can/bx/pac/can/tsr.rs +++ /dev/null @@ -1,575 +0,0 @@ -#[doc = "Reader of register TSR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register TSR"] -pub type W = crate::can::bx::W; -#[doc = "Register TSR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::TSR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `LOW2`"] -pub type LOW2_R = crate::can::bx::R; -#[doc = "Reader of field `LOW1`"] -pub type LOW1_R = crate::can::bx::R; -#[doc = "Reader of field `LOW0`"] -pub type LOW0_R = crate::can::bx::R; -#[doc = "Reader of field `TME2`"] -pub type TME2_R = crate::can::bx::R; -#[doc = "Reader of field `TME1`"] -pub type TME1_R = crate::can::bx::R; -#[doc = "Reader of field `TME0`"] -pub type TME0_R = crate::can::bx::R; -#[doc = "Reader of field `CODE`"] -pub type CODE_R = crate::can::bx::R; -#[doc = "Reader of field `ABRQ2`"] -pub type ABRQ2_R = crate::can::bx::R; -#[doc = "Write proxy for field `ABRQ2`"] -pub struct ABRQ2_W<'a> { - w: &'a mut W, -} -impl<'a> ABRQ2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 23)) | (((value as u32) & 0x01) << 23); - self.w - } -} -#[doc = "Reader of field `TERR2`"] -pub type TERR2_R = crate::can::bx::R; -#[doc = "Write proxy for field `TERR2`"] -pub struct TERR2_W<'a> { - w: &'a mut W, -} -impl<'a> TERR2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 19)) | (((value as u32) & 0x01) << 19); - self.w - } -} -#[doc = "Reader of field `ALST2`"] -pub type ALST2_R = crate::can::bx::R; -#[doc = "Write proxy for field `ALST2`"] -pub struct ALST2_W<'a> { - w: &'a mut W, -} -impl<'a> ALST2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 18)) | (((value as u32) & 0x01) << 18); - self.w - } -} -#[doc = "Reader of field `TXOK2`"] -pub type TXOK2_R = crate::can::bx::R; -#[doc = "Write proxy for field `TXOK2`"] -pub struct TXOK2_W<'a> { - w: &'a mut W, -} -impl<'a> TXOK2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 17)) | (((value as u32) & 0x01) << 17); - self.w - } -} -#[doc = "Reader of field `RQCP2`"] -pub type RQCP2_R = crate::can::bx::R; -#[doc = "Write proxy for field `RQCP2`"] -pub struct RQCP2_W<'a> { - w: &'a mut W, -} -impl<'a> RQCP2_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 16)) | (((value as u32) & 0x01) << 16); - self.w - } -} -#[doc = "Reader of field `ABRQ1`"] -pub type ABRQ1_R = crate::can::bx::R; -#[doc = "Write proxy for field `ABRQ1`"] -pub struct ABRQ1_W<'a> { - w: &'a mut W, -} -impl<'a> ABRQ1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 15)) | (((value as u32) & 0x01) << 15); - self.w - } -} -#[doc = "Reader of field `TERR1`"] -pub type TERR1_R = crate::can::bx::R; -#[doc = "Write proxy for field `TERR1`"] -pub struct TERR1_W<'a> { - w: &'a mut W, -} -impl<'a> TERR1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 11)) | (((value as u32) & 0x01) << 11); - self.w - } -} -#[doc = "Reader of field `ALST1`"] -pub type ALST1_R = crate::can::bx::R; -#[doc = "Write proxy for field `ALST1`"] -pub struct ALST1_W<'a> { - w: &'a mut W, -} -impl<'a> ALST1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 10)) | (((value as u32) & 0x01) << 10); - self.w - } -} -#[doc = "Reader of field `TXOK1`"] -pub type TXOK1_R = crate::can::bx::R; -#[doc = "Write proxy for field `TXOK1`"] -pub struct TXOK1_W<'a> { - w: &'a mut W, -} -impl<'a> TXOK1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 9)) | (((value as u32) & 0x01) << 9); - self.w - } -} -#[doc = "Reader of field `RQCP1`"] -pub type RQCP1_R = crate::can::bx::R; -#[doc = "Write proxy for field `RQCP1`"] -pub struct RQCP1_W<'a> { - w: &'a mut W, -} -impl<'a> RQCP1_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); - self.w - } -} -#[doc = "Reader of field `ABRQ0`"] -pub type ABRQ0_R = crate::can::bx::R; -#[doc = "Write proxy for field `ABRQ0`"] -pub struct ABRQ0_W<'a> { - w: &'a mut W, -} -impl<'a> ABRQ0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 7)) | (((value as u32) & 0x01) << 7); - self.w - } -} -#[doc = "Reader of field `TERR0`"] -pub type TERR0_R = crate::can::bx::R; -#[doc = "Write proxy for field `TERR0`"] -pub struct TERR0_W<'a> { - w: &'a mut W, -} -impl<'a> TERR0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 3)) | (((value as u32) & 0x01) << 3); - self.w - } -} -#[doc = "Reader of field `ALST0`"] -pub type ALST0_R = crate::can::bx::R; -#[doc = "Write proxy for field `ALST0`"] -pub struct ALST0_W<'a> { - w: &'a mut W, -} -impl<'a> ALST0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "Reader of field `TXOK0`"] -pub type TXOK0_R = crate::can::bx::R; -#[doc = "Write proxy for field `TXOK0`"] -pub struct TXOK0_W<'a> { - w: &'a mut W, -} -impl<'a> TXOK0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); - self.w - } -} -#[doc = "Reader of field `RQCP0`"] -pub type RQCP0_R = crate::can::bx::R; -#[doc = "Write proxy for field `RQCP0`"] -pub struct RQCP0_W<'a> { - w: &'a mut W, -} -impl<'a> RQCP0_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -impl R { - #[doc = "Bit 31 - Lowest priority flag for mailbox 2"] - #[inline(always)] - pub fn low2(&self) -> LOW2_R { - LOW2_R::new(((self.bits >> 31) & 0x01) != 0) - } - #[doc = "Bit 30 - Lowest priority flag for mailbox 1"] - #[inline(always)] - pub fn low1(&self) -> LOW1_R { - LOW1_R::new(((self.bits >> 30) & 0x01) != 0) - } - #[doc = "Bit 29 - Lowest priority flag for mailbox 0"] - #[inline(always)] - pub fn low0(&self) -> LOW0_R { - LOW0_R::new(((self.bits >> 29) & 0x01) != 0) - } - #[doc = "Bit 28 - Lowest priority flag for mailbox 2"] - #[inline(always)] - pub fn tme2(&self) -> TME2_R { - TME2_R::new(((self.bits >> 28) & 0x01) != 0) - } - #[doc = "Bit 27 - Lowest priority flag for mailbox 1"] - #[inline(always)] - pub fn tme1(&self) -> TME1_R { - TME1_R::new(((self.bits >> 27) & 0x01) != 0) - } - #[doc = "Bit 26 - Lowest priority flag for mailbox 0"] - #[inline(always)] - pub fn tme0(&self) -> TME0_R { - TME0_R::new(((self.bits >> 26) & 0x01) != 0) - } - #[doc = "Bits 24:25 - CODE"] - #[inline(always)] - pub fn code(&self) -> CODE_R { - CODE_R::new(((self.bits >> 24) & 0x03) as u8) - } - #[doc = "Bit 23 - ABRQ2"] - #[inline(always)] - pub fn abrq2(&self) -> ABRQ2_R { - ABRQ2_R::new(((self.bits >> 23) & 0x01) != 0) - } - #[doc = "Bit 19 - TERR2"] - #[inline(always)] - pub fn terr2(&self) -> TERR2_R { - TERR2_R::new(((self.bits >> 19) & 0x01) != 0) - } - #[doc = "Bit 18 - ALST2"] - #[inline(always)] - pub fn alst2(&self) -> ALST2_R { - ALST2_R::new(((self.bits >> 18) & 0x01) != 0) - } - #[doc = "Bit 17 - TXOK2"] - #[inline(always)] - pub fn txok2(&self) -> TXOK2_R { - TXOK2_R::new(((self.bits >> 17) & 0x01) != 0) - } - #[doc = "Bit 16 - RQCP2"] - #[inline(always)] - pub fn rqcp2(&self) -> RQCP2_R { - RQCP2_R::new(((self.bits >> 16) & 0x01) != 0) - } - #[doc = "Bit 15 - ABRQ1"] - #[inline(always)] - pub fn abrq1(&self) -> ABRQ1_R { - ABRQ1_R::new(((self.bits >> 15) & 0x01) != 0) - } - #[doc = "Bit 11 - TERR1"] - #[inline(always)] - pub fn terr1(&self) -> TERR1_R { - TERR1_R::new(((self.bits >> 11) & 0x01) != 0) - } - #[doc = "Bit 10 - ALST1"] - #[inline(always)] - pub fn alst1(&self) -> ALST1_R { - ALST1_R::new(((self.bits >> 10) & 0x01) != 0) - } - #[doc = "Bit 9 - TXOK1"] - #[inline(always)] - pub fn txok1(&self) -> TXOK1_R { - TXOK1_R::new(((self.bits >> 9) & 0x01) != 0) - } - #[doc = "Bit 8 - RQCP1"] - #[inline(always)] - pub fn rqcp1(&self) -> RQCP1_R { - RQCP1_R::new(((self.bits >> 8) & 0x01) != 0) - } - #[doc = "Bit 7 - ABRQ0"] - #[inline(always)] - pub fn abrq0(&self) -> ABRQ0_R { - ABRQ0_R::new(((self.bits >> 7) & 0x01) != 0) - } - #[doc = "Bit 3 - TERR0"] - #[inline(always)] - pub fn terr0(&self) -> TERR0_R { - TERR0_R::new(((self.bits >> 3) & 0x01) != 0) - } - #[doc = "Bit 2 - ALST0"] - #[inline(always)] - pub fn alst0(&self) -> ALST0_R { - ALST0_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 1 - TXOK0"] - #[inline(always)] - pub fn txok0(&self) -> TXOK0_R { - TXOK0_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 0 - RQCP0"] - #[inline(always)] - pub fn rqcp0(&self) -> RQCP0_R { - RQCP0_R::new((self.bits & 0x01) != 0) - } -} -impl W { - #[doc = "Bit 23 - ABRQ2"] - #[inline(always)] - pub fn abrq2(&mut self) -> ABRQ2_W { - ABRQ2_W { w: self } - } - #[doc = "Bit 19 - TERR2"] - #[inline(always)] - pub fn terr2(&mut self) -> TERR2_W { - TERR2_W { w: self } - } - #[doc = "Bit 18 - ALST2"] - #[inline(always)] - pub fn alst2(&mut self) -> ALST2_W { - ALST2_W { w: self } - } - #[doc = "Bit 17 - TXOK2"] - #[inline(always)] - pub fn txok2(&mut self) -> TXOK2_W { - TXOK2_W { w: self } - } - #[doc = "Bit 16 - RQCP2"] - #[inline(always)] - pub fn rqcp2(&mut self) -> RQCP2_W { - RQCP2_W { w: self } - } - #[doc = "Bit 15 - ABRQ1"] - #[inline(always)] - pub fn abrq1(&mut self) -> ABRQ1_W { - ABRQ1_W { w: self } - } - #[doc = "Bit 11 - TERR1"] - #[inline(always)] - pub fn terr1(&mut self) -> TERR1_W { - TERR1_W { w: self } - } - #[doc = "Bit 10 - ALST1"] - #[inline(always)] - pub fn alst1(&mut self) -> ALST1_W { - ALST1_W { w: self } - } - #[doc = "Bit 9 - TXOK1"] - #[inline(always)] - pub fn txok1(&mut self) -> TXOK1_W { - TXOK1_W { w: self } - } - #[doc = "Bit 8 - RQCP1"] - #[inline(always)] - pub fn rqcp1(&mut self) -> RQCP1_W { - RQCP1_W { w: self } - } - #[doc = "Bit 7 - ABRQ0"] - #[inline(always)] - pub fn abrq0(&mut self) -> ABRQ0_W { - ABRQ0_W { w: self } - } - #[doc = "Bit 3 - TERR0"] - #[inline(always)] - pub fn terr0(&mut self) -> TERR0_W { - TERR0_W { w: self } - } - #[doc = "Bit 2 - ALST0"] - #[inline(always)] - pub fn alst0(&mut self) -> ALST0_W { - ALST0_W { w: self } - } - #[doc = "Bit 1 - TXOK0"] - #[inline(always)] - pub fn txok0(&mut self) -> TXOK0_W { - TXOK0_W { w: self } - } - #[doc = "Bit 0 - RQCP0"] - #[inline(always)] - pub fn rqcp0(&mut self) -> RQCP0_W { - RQCP0_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/tx.rs b/embassy-stm32/src/can/bx/pac/can/tx.rs deleted file mode 100644 index f45eb47cc..000000000 --- a/embassy-stm32/src/can/bx/pac/can/tx.rs +++ /dev/null @@ -1,44 +0,0 @@ -#[doc = "CAN_TI0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tir](tir) module"] -pub type TIR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _TIR; -#[doc = "`read()` method returns [tir::R](tir::R) reader structure"] -impl crate::can::bx::Readable for TIR {} -#[doc = "`write(|w| ..)` method takes [tir::W](tir::W) writer structure"] -impl crate::can::bx::Writable for TIR {} -#[doc = "CAN_TI0R"] -pub mod tir; -#[doc = "CAN_TDT0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdtr](tdtr) module"] -pub type TDTR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _TDTR; -#[doc = "`read()` method returns [tdtr::R](tdtr::R) reader structure"] -impl crate::can::bx::Readable for TDTR {} -#[doc = "`write(|w| ..)` method takes [tdtr::W](tdtr::W) writer structure"] -impl crate::can::bx::Writable for TDTR {} -#[doc = "CAN_TDT0R"] -pub mod tdtr; -#[doc = "CAN_TDL0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdlr](tdlr) module"] -pub type TDLR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _TDLR; -#[doc = "`read()` method returns [tdlr::R](tdlr::R) reader structure"] -impl crate::can::bx::Readable for TDLR {} -#[doc = "`write(|w| ..)` method takes [tdlr::W](tdlr::W) writer structure"] -impl crate::can::bx::Writable for TDLR {} -#[doc = "CAN_TDL0R"] -pub mod tdlr; -#[doc = "CAN_TDH0R\n\nThis register you can [`read`](crate::can::bx::generic::Reg::read), [`reset`](crate::can::bx::generic::Reg::reset), [`write`](crate::can::bx::generic::Reg::write), [`write_with_zero`](crate::can::bx::generic::Reg::write_with_zero), [`modify`](crate::can::bx::generic::Reg::modify). See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [tdhr](tdhr) module"] -pub type TDHR = crate::can::bx::Reg; -#[allow(missing_docs)] -#[doc(hidden)] -pub struct _TDHR; -#[doc = "`read()` method returns [tdhr::R](tdhr::R) reader structure"] -impl crate::can::bx::Readable for TDHR {} -#[doc = "`write(|w| ..)` method takes [tdhr::W](tdhr::W) writer structure"] -impl crate::can::bx::Writable for TDHR {} -#[doc = "CAN_TDH0R"] -pub mod tdhr; diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs deleted file mode 100644 index 9c2209b99..000000000 --- a/embassy-stm32/src/can/bx/pac/can/tx/tdhr.rs +++ /dev/null @@ -1,112 +0,0 @@ -#[doc = "Reader of register TDHR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register TDHR"] -pub type W = crate::can::bx::W; -#[doc = "Register TDHR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::TDHR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `DATA7`"] -pub type DATA7_R = crate::can::bx::R; -#[doc = "Write proxy for field `DATA7`"] -pub struct DATA7_W<'a> { - w: &'a mut W, -} -impl<'a> DATA7_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0xff << 24)) | (((value as u32) & 0xff) << 24); - self.w - } -} -#[doc = "Reader of field `DATA6`"] -pub type DATA6_R = crate::can::bx::R; -#[doc = "Write proxy for field `DATA6`"] -pub struct DATA6_W<'a> { - w: &'a mut W, -} -impl<'a> DATA6_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0xff << 16)) | (((value as u32) & 0xff) << 16); - self.w - } -} -#[doc = "Reader of field `DATA5`"] -pub type DATA5_R = crate::can::bx::R; -#[doc = "Write proxy for field `DATA5`"] -pub struct DATA5_W<'a> { - w: &'a mut W, -} -impl<'a> DATA5_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0xff << 8)) | (((value as u32) & 0xff) << 8); - self.w - } -} -#[doc = "Reader of field `DATA4`"] -pub type DATA4_R = crate::can::bx::R; -#[doc = "Write proxy for field `DATA4`"] -pub struct DATA4_W<'a> { - w: &'a mut W, -} -impl<'a> DATA4_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !0xff) | ((value as u32) & 0xff); - self.w - } -} -impl R { - #[doc = "Bits 24:31 - DATA7"] - #[inline(always)] - pub fn data7(&self) -> DATA7_R { - DATA7_R::new(((self.bits >> 24) & 0xff) as u8) - } - #[doc = "Bits 16:23 - DATA6"] - #[inline(always)] - pub fn data6(&self) -> DATA6_R { - DATA6_R::new(((self.bits >> 16) & 0xff) as u8) - } - #[doc = "Bits 8:15 - DATA5"] - #[inline(always)] - pub fn data5(&self) -> DATA5_R { - DATA5_R::new(((self.bits >> 8) & 0xff) as u8) - } - #[doc = "Bits 0:7 - DATA4"] - #[inline(always)] - pub fn data4(&self) -> DATA4_R { - DATA4_R::new((self.bits & 0xff) as u8) - } -} -impl W { - #[doc = "Bits 24:31 - DATA7"] - #[inline(always)] - pub fn data7(&mut self) -> DATA7_W { - DATA7_W { w: self } - } - #[doc = "Bits 16:23 - DATA6"] - #[inline(always)] - pub fn data6(&mut self) -> DATA6_W { - DATA6_W { w: self } - } - #[doc = "Bits 8:15 - DATA5"] - #[inline(always)] - pub fn data5(&mut self) -> DATA5_W { - DATA5_W { w: self } - } - #[doc = "Bits 0:7 - DATA4"] - #[inline(always)] - pub fn data4(&mut self) -> DATA4_W { - DATA4_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs deleted file mode 100644 index d67589f99..000000000 --- a/embassy-stm32/src/can/bx/pac/can/tx/tdlr.rs +++ /dev/null @@ -1,112 +0,0 @@ -#[doc = "Reader of register TDLR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register TDLR"] -pub type W = crate::can::bx::W; -#[doc = "Register TDLR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::TDLR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `DATA3`"] -pub type DATA3_R = crate::can::bx::R; -#[doc = "Write proxy for field `DATA3`"] -pub struct DATA3_W<'a> { - w: &'a mut W, -} -impl<'a> DATA3_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0xff << 24)) | (((value as u32) & 0xff) << 24); - self.w - } -} -#[doc = "Reader of field `DATA2`"] -pub type DATA2_R = crate::can::bx::R; -#[doc = "Write proxy for field `DATA2`"] -pub struct DATA2_W<'a> { - w: &'a mut W, -} -impl<'a> DATA2_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0xff << 16)) | (((value as u32) & 0xff) << 16); - self.w - } -} -#[doc = "Reader of field `DATA1`"] -pub type DATA1_R = crate::can::bx::R; -#[doc = "Write proxy for field `DATA1`"] -pub struct DATA1_W<'a> { - w: &'a mut W, -} -impl<'a> DATA1_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !(0xff << 8)) | (((value as u32) & 0xff) << 8); - self.w - } -} -#[doc = "Reader of field `DATA0`"] -pub type DATA0_R = crate::can::bx::R; -#[doc = "Write proxy for field `DATA0`"] -pub struct DATA0_W<'a> { - w: &'a mut W, -} -impl<'a> DATA0_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !0xff) | ((value as u32) & 0xff); - self.w - } -} -impl R { - #[doc = "Bits 24:31 - DATA3"] - #[inline(always)] - pub fn data3(&self) -> DATA3_R { - DATA3_R::new(((self.bits >> 24) & 0xff) as u8) - } - #[doc = "Bits 16:23 - DATA2"] - #[inline(always)] - pub fn data2(&self) -> DATA2_R { - DATA2_R::new(((self.bits >> 16) & 0xff) as u8) - } - #[doc = "Bits 8:15 - DATA1"] - #[inline(always)] - pub fn data1(&self) -> DATA1_R { - DATA1_R::new(((self.bits >> 8) & 0xff) as u8) - } - #[doc = "Bits 0:7 - DATA0"] - #[inline(always)] - pub fn data0(&self) -> DATA0_R { - DATA0_R::new((self.bits & 0xff) as u8) - } -} -impl W { - #[doc = "Bits 24:31 - DATA3"] - #[inline(always)] - pub fn data3(&mut self) -> DATA3_W { - DATA3_W { w: self } - } - #[doc = "Bits 16:23 - DATA2"] - #[inline(always)] - pub fn data2(&mut self) -> DATA2_W { - DATA2_W { w: self } - } - #[doc = "Bits 8:15 - DATA1"] - #[inline(always)] - pub fn data1(&mut self) -> DATA1_W { - DATA1_W { w: self } - } - #[doc = "Bits 0:7 - DATA0"] - #[inline(always)] - pub fn data0(&mut self) -> DATA0_W { - DATA0_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs b/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs deleted file mode 100644 index cf748ba29..000000000 --- a/embassy-stm32/src/can/bx/pac/can/tx/tdtr.rs +++ /dev/null @@ -1,98 +0,0 @@ -#[doc = "Reader of register TDTR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register TDTR"] -pub type W = crate::can::bx::W; -#[doc = "Register TDTR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::TDTR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `TIME`"] -pub type TIME_R = crate::can::bx::R; -#[doc = "Write proxy for field `TIME`"] -pub struct TIME_W<'a> { - w: &'a mut W, -} -impl<'a> TIME_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u16) -> &'a mut W { - self.w.bits = (self.w.bits & !(0xffff << 16)) | (((value as u32) & 0xffff) << 16); - self.w - } -} -#[doc = "Reader of field `TGT`"] -pub type TGT_R = crate::can::bx::R; -#[doc = "Write proxy for field `TGT`"] -pub struct TGT_W<'a> { - w: &'a mut W, -} -impl<'a> TGT_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 8)) | (((value as u32) & 0x01) << 8); - self.w - } -} -#[doc = "Reader of field `DLC`"] -pub type DLC_R = crate::can::bx::R; -#[doc = "Write proxy for field `DLC`"] -pub struct DLC_W<'a> { - w: &'a mut W, -} -impl<'a> DLC_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits = (self.w.bits & !0x0f) | ((value as u32) & 0x0f); - self.w - } -} -impl R { - #[doc = "Bits 16:31 - TIME"] - #[inline(always)] - pub fn time(&self) -> TIME_R { - TIME_R::new(((self.bits >> 16) & 0xffff) as u16) - } - #[doc = "Bit 8 - TGT"] - #[inline(always)] - pub fn tgt(&self) -> TGT_R { - TGT_R::new(((self.bits >> 8) & 0x01) != 0) - } - #[doc = "Bits 0:3 - DLC"] - #[inline(always)] - pub fn dlc(&self) -> DLC_R { - DLC_R::new((self.bits & 0x0f) as u8) - } -} -impl W { - #[doc = "Bits 16:31 - TIME"] - #[inline(always)] - pub fn time(&mut self) -> TIME_W { - TIME_W { w: self } - } - #[doc = "Bit 8 - TGT"] - #[inline(always)] - pub fn tgt(&mut self) -> TGT_W { - TGT_W { w: self } - } - #[doc = "Bits 0:3 - DLC"] - #[inline(always)] - pub fn dlc(&mut self) -> DLC_W { - DLC_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/can/tx/tir.rs b/embassy-stm32/src/can/bx/pac/can/tx/tir.rs deleted file mode 100644 index 2d2dd0ca7..000000000 --- a/embassy-stm32/src/can/bx/pac/can/tx/tir.rs +++ /dev/null @@ -1,268 +0,0 @@ -#[doc = "Reader of register TIR"] -pub type R = crate::can::bx::R; -#[doc = "Writer for register TIR"] -pub type W = crate::can::bx::W; -#[doc = "Register TIR `reset()`'s with value 0"] -impl crate::can::bx::ResetValue for super::TIR { - type Type = u32; - #[inline(always)] - fn reset_value() -> Self::Type { - 0 - } -} -#[doc = "Reader of field `STID`"] -pub type STID_R = crate::can::bx::R; -#[doc = "Write proxy for field `STID`"] -pub struct STID_W<'a> { - w: &'a mut W, -} -impl<'a> STID_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u16) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x07ff << 21)) | (((value as u32) & 0x07ff) << 21); - self.w - } -} -#[doc = "Reader of field `EXID`"] -pub type EXID_R = crate::can::bx::R; -#[doc = "Write proxy for field `EXID`"] -pub struct EXID_W<'a> { - w: &'a mut W, -} -impl<'a> EXID_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u32) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x0003_ffff << 3)) | (((value as u32) & 0x0003_ffff) << 3); - self.w - } -} -#[doc = "IDE\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum IDE_A { - #[doc = "0: Standard identifier"] - STANDARD = 0, - #[doc = "1: Extended identifier"] - EXTENDED = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: IDE_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `IDE`"] -pub type IDE_R = crate::can::bx::R; -impl IDE_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> IDE_A { - match self.bits { - false => IDE_A::STANDARD, - true => IDE_A::EXTENDED, - } - } - #[doc = "Checks if the value of the field is `STANDARD`"] - #[inline(always)] - pub fn is_standard(&self) -> bool { - *self == IDE_A::STANDARD - } - #[doc = "Checks if the value of the field is `EXTENDED`"] - #[inline(always)] - pub fn is_extended(&self) -> bool { - *self == IDE_A::EXTENDED - } -} -#[doc = "Write proxy for field `IDE`"] -pub struct IDE_W<'a> { - w: &'a mut W, -} -impl<'a> IDE_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: IDE_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "Standard identifier"] - #[inline(always)] - pub fn standard(self) -> &'a mut W { - self.variant(IDE_A::STANDARD) - } - #[doc = "Extended identifier"] - #[inline(always)] - pub fn extended(self) -> &'a mut W { - self.variant(IDE_A::EXTENDED) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 2)) | (((value as u32) & 0x01) << 2); - self.w - } -} -#[doc = "RTR\n\nValue on reset: 0"] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum RTR_A { - #[doc = "0: Data frame"] - DATA = 0, - #[doc = "1: Remote frame"] - REMOTE = 1, -} -impl From for bool { - #[inline(always)] - fn from(variant: RTR_A) -> Self { - variant as u8 != 0 - } -} -#[doc = "Reader of field `RTR`"] -pub type RTR_R = crate::can::bx::R; -impl RTR_R { - #[doc = r"Get enumerated values variant"] - #[inline(always)] - pub fn variant(&self) -> RTR_A { - match self.bits { - false => RTR_A::DATA, - true => RTR_A::REMOTE, - } - } - #[doc = "Checks if the value of the field is `DATA`"] - #[inline(always)] - pub fn is_data(&self) -> bool { - *self == RTR_A::DATA - } - #[doc = "Checks if the value of the field is `REMOTE`"] - #[inline(always)] - pub fn is_remote(&self) -> bool { - *self == RTR_A::REMOTE - } -} -#[doc = "Write proxy for field `RTR`"] -pub struct RTR_W<'a> { - w: &'a mut W, -} -impl<'a> RTR_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - pub fn variant(self, variant: RTR_A) -> &'a mut W { - { - self.bit(variant.into()) - } - } - #[doc = "Data frame"] - #[inline(always)] - pub fn data(self) -> &'a mut W { - self.variant(RTR_A::DATA) - } - #[doc = "Remote frame"] - #[inline(always)] - pub fn remote(self) -> &'a mut W { - self.variant(RTR_A::REMOTE) - } - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !(0x01 << 1)) | (((value as u32) & 0x01) << 1); - self.w - } -} -#[doc = "Reader of field `TXRQ`"] -pub type TXRQ_R = crate::can::bx::R; -#[doc = "Write proxy for field `TXRQ`"] -pub struct TXRQ_W<'a> { - w: &'a mut W, -} -impl<'a> TXRQ_W<'a> { - #[doc = r"Sets the field bit"] - #[inline(always)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits = (self.w.bits & !0x01) | ((value as u32) & 0x01); - self.w - } -} -impl R { - #[doc = "Bits 21:31 - STID"] - #[inline(always)] - pub fn stid(&self) -> STID_R { - STID_R::new(((self.bits >> 21) & 0x07ff) as u16) - } - #[doc = "Bits 3:20 - EXID"] - #[inline(always)] - pub fn exid(&self) -> EXID_R { - EXID_R::new(((self.bits >> 3) & 0x0003_ffff) as u32) - } - #[doc = "Bit 2 - IDE"] - #[inline(always)] - pub fn ide(&self) -> IDE_R { - IDE_R::new(((self.bits >> 2) & 0x01) != 0) - } - #[doc = "Bit 1 - RTR"] - #[inline(always)] - pub fn rtr(&self) -> RTR_R { - RTR_R::new(((self.bits >> 1) & 0x01) != 0) - } - #[doc = "Bit 0 - TXRQ"] - #[inline(always)] - pub fn txrq(&self) -> TXRQ_R { - TXRQ_R::new((self.bits & 0x01) != 0) - } -} -impl W { - #[doc = "Bits 21:31 - STID"] - #[inline(always)] - pub fn stid(&mut self) -> STID_W { - STID_W { w: self } - } - #[doc = "Bits 3:20 - EXID"] - #[inline(always)] - pub fn exid(&mut self) -> EXID_W { - EXID_W { w: self } - } - #[doc = "Bit 2 - IDE"] - #[inline(always)] - pub fn ide(&mut self) -> IDE_W { - IDE_W { w: self } - } - #[doc = "Bit 1 - RTR"] - #[inline(always)] - pub fn rtr(&mut self) -> RTR_W { - RTR_W { w: self } - } - #[doc = "Bit 0 - TXRQ"] - #[inline(always)] - pub fn txrq(&mut self) -> TXRQ_W { - TXRQ_W { w: self } - } -} diff --git a/embassy-stm32/src/can/bx/pac/generic.rs b/embassy-stm32/src/can/bx/pac/generic.rs deleted file mode 100644 index 749e7e204..000000000 --- a/embassy-stm32/src/can/bx/pac/generic.rs +++ /dev/null @@ -1,256 +0,0 @@ -use core::marker; - -///This trait shows that register has `read` method -/// -///Registers marked with `Writable` can be also `modify`'ed -pub trait Readable {} - -///This trait shows that register has `write`, `write_with_zero` and `reset` method -/// -///Registers marked with `Readable` can be also `modify`'ed -pub trait Writable {} - -///Reset value of the register -/// -///This value is initial value for `write` method. -///It can be also directly writed to register by `reset` method. -pub trait ResetValue { - ///Register size - type Type; - ///Reset value of the register - fn reset_value() -> Self::Type; -} - -///This structure provides volatile access to register -pub struct Reg { - register: vcell::VolatileCell, - _marker: marker::PhantomData, -} - -unsafe impl Send for Reg {} - -impl Reg -where - Self: Readable, - U: Copy, -{ - ///Reads the contents of `Readable` register - /// - ///You can read the contents of a register in such way: - ///```ignore - ///let bits = periph.reg.read().bits(); - ///``` - ///or get the content of a particular field of a register. - ///```ignore - ///let reader = periph.reg.read(); - ///let bits = reader.field1().bits(); - ///let flag = reader.field2().bit_is_set(); - ///``` - #[inline(always)] - pub fn read(&self) -> R { - R { - bits: self.register.get(), - _reg: marker::PhantomData, - } - } -} - -impl Reg -where - Self: ResetValue + Writable, - U: Copy, -{ - ///Writes the reset value to `Writable` register - /// - ///Resets the register to its initial state - #[inline(always)] - pub fn reset(&self) { - self.register.set(Self::reset_value()) - } -} - -impl Reg -where - Self: ResetValue + Writable, - U: Copy, -{ - ///Writes bits to `Writable` register - /// - ///You can write raw bits into a register: - ///```ignore - ///periph.reg.write(|w| unsafe { w.bits(rawbits) }); - ///``` - ///or write only the fields you need: - ///```ignore - ///periph.reg.write(|w| w - /// .field1().bits(newfield1bits) - /// .field2().set_bit() - /// .field3().variant(VARIANT) - ///); - ///``` - ///Other fields will have reset value. - #[inline(always)] - pub fn write(&self, f: F) - where - F: FnOnce(&mut W) -> &mut W, - { - self.register.set( - f(&mut W { - bits: Self::reset_value(), - _reg: marker::PhantomData, - }) - .bits, - ); - } -} - -impl Reg -where - Self: Writable, - U: Copy + Default, -{ - ///Writes Zero to `Writable` register - /// - ///Similar to `write`, but unused bits will contain 0. - #[inline(always)] - pub fn write_with_zero(&self, f: F) - where - F: FnOnce(&mut W) -> &mut W, - { - self.register.set( - f(&mut W { - bits: U::default(), - _reg: marker::PhantomData, - }) - .bits, - ); - } -} - -impl Reg -where - Self: Readable + Writable, - U: Copy, -{ - ///Modifies the contents of the register - /// - ///E.g. to do a read-modify-write sequence to change parts of a register: - ///```ignore - ///periph.reg.modify(|r, w| unsafe { w.bits( - /// r.bits() | 3 - ///) }); - ///``` - ///or - ///```ignore - ///periph.reg.modify(|_, w| w - /// .field1().bits(newfield1bits) - /// .field2().set_bit() - /// .field3().variant(VARIANT) - ///); - ///``` - ///Other fields will have value they had before call `modify`. - #[inline(always)] - pub fn modify(&self, f: F) - where - for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, - { - let bits = self.register.get(); - self.register.set( - f( - &R { - bits, - _reg: marker::PhantomData, - }, - &mut W { - bits, - _reg: marker::PhantomData, - }, - ) - .bits, - ); - } -} - -///Register/field reader -/// -///Result of the [`read`](Reg::read) method of a register. -///Also it can be used in the [`modify`](Reg::read) method -pub struct R { - pub(crate) bits: U, - _reg: marker::PhantomData, -} - -impl R -where - U: Copy, -{ - ///Create new instance of reader - #[inline(always)] - pub(crate) fn new(bits: U) -> Self { - Self { - bits, - _reg: marker::PhantomData, - } - } - ///Read raw bits from register/field - #[inline(always)] - pub fn bits(&self) -> U { - self.bits - } -} - -impl PartialEq for R -where - U: PartialEq, - FI: Copy + Into, -{ - #[inline(always)] - fn eq(&self, other: &FI) -> bool { - self.bits.eq(&(*other).into()) - } -} - -impl R { - ///Value of the field as raw bits - #[inline(always)] - pub fn bit(&self) -> bool { - self.bits - } - ///Returns `true` if the bit is clear (0) - #[inline(always)] - pub fn bit_is_clear(&self) -> bool { - !self.bit() - } - ///Returns `true` if the bit is set (1) - #[inline(always)] - pub fn bit_is_set(&self) -> bool { - self.bit() - } -} - -///Register writer -/// -///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register -pub struct W { - ///Writable bits - pub(crate) bits: U, - _reg: marker::PhantomData, -} - -impl W { - ///Writes raw bits to the register - #[inline(always)] - pub unsafe fn bits(&mut self, bits: U) -> &mut Self { - self.bits = bits; - self - } -} - -///Used if enumerated values cover not the whole range -#[derive(Clone, Copy, PartialEq)] -pub enum Variant { - ///Expected variant - Val(T), - ///Raw bits - Res(U), -} diff --git a/embassy-stm32/src/can/bx/pac/mod.rs b/embassy-stm32/src/can/bx/pac/mod.rs deleted file mode 100644 index 4360c2c73..000000000 --- a/embassy-stm32/src/can/bx/pac/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(unused)] -use core::marker::PhantomData; -use core::ops::Deref; - -#[doc = "Controller area network"] -pub mod can; -pub mod generic; From 84d21e959d98326ff4c92c7c2278fe356ff4e5c0 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 7 Mar 2024 08:27:45 +1000 Subject: [PATCH 652/760] Dummy --- embassy-stm32/src/can/bx/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 2bfa827a8..f639260a1 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -71,8 +71,7 @@ pub unsafe trait Instance {} pub unsafe trait FilterOwner: Instance { /// The total number of filter banks available to the instance. /// - /// This is usually either 14 or 28, and should be specified in the chip's reference manual or - /// datasheet. + /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet. const NUM_FILTER_BANKS: u8; } From bbc06458a31946a2faf96d418d51d09d880fb1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 7 Mar 2024 15:03:40 +0100 Subject: [PATCH 653/760] stm32: Implement `Channel` trait for `AnyChannel` --- embassy-stm32/src/dma/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 6b1ac6207..960483f34 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -96,6 +96,13 @@ impl AnyChannel { } } +impl sealed::Channel for AnyChannel { + fn id(&self) -> u8 { + self.id + } +} +impl Channel for AnyChannel {} + const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len(); static STATE: [ChannelState; CHANNEL_COUNT] = [ChannelState::NEW; CHANNEL_COUNT]; From bb3711bbf9fc1c63148c41587b5d0d0e0890c7cc Mon Sep 17 00:00:00 2001 From: Tomas Barton <87450069+tomasbarton-stemcell@users.noreply.github.com> Date: Thu, 7 Mar 2024 06:51:32 -0800 Subject: [PATCH 654/760] update stm32c0 HSI frequency --- embassy-stm32/src/rcc/c0.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 7ca737bf0..349f978c5 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -6,7 +6,7 @@ use crate::pac::{FLASH, RCC}; use crate::time::Hertz; /// HSI speed -pub const HSI_FREQ: Hertz = Hertz(16_000_000); +pub const HSI_FREQ: Hertz = Hertz(48_000_000); /// HSE Mode #[derive(Clone, Copy, Eq, PartialEq)] From b7bb4b23f8e59e90cff4773cc1e93e493d72ae56 Mon Sep 17 00:00:00 2001 From: Ralf Date: Fri, 1 Mar 2024 13:50:14 +0100 Subject: [PATCH 655/760] STM32 SimplePwm: Fix regression and re-enable output pin PR #2499 implemented timer hierarchy, but removed enable_outputs() from trait CaptureCompare16bitInstance and from SimplePwm. This functions is required for advanced timers to set bit BDTR.MOE and to enable the output signal. --- embassy-stm32/src/timer/mod.rs | 37 ++++++++++++++++++++++----- embassy-stm32/src/timer/simple_pwm.rs | 1 + 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 8530c5229..ef893c7f5 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -439,9 +439,9 @@ pub(crate) mod sealed { Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); } - /// Enable timer outputs. - fn enable_outputs(&self) { - Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); + /// Set state of MOE-bit in BDTR register to en-/disable output + fn set_moe(&self, enable: bool) { + Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); } } @@ -685,6 +685,13 @@ pub trait CaptureCompare16bitInstance: + sealed::GeneralPurpose16bitInstance + 'static { + // SimplePwm<'d, T> is implemented for T: CaptureCompare16bitInstance + // Advanced timers implement this trait, but the output needs to be + // enabled explicitly. + // To support general-purpose and advanced timers, this function is added + // here defaulting to noop and overwritten for advanced timers. + /// Enable timer outputs. + fn enable_outputs(&self) {} } #[cfg(not(stm32l0))] @@ -911,7 +918,13 @@ foreach_interrupt! { impl_1ch_cmp_timer!($inst); impl_2ch_cmp_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst { + /// Enable timer outputs. + fn enable_outputs(&self) { + use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; + self.set_moe(true); + } + } impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => { @@ -929,7 +942,13 @@ foreach_interrupt! { impl_1ch_cmp_timer!($inst); impl_2ch_cmp_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst { + /// Enable timer outputs. + fn enable_outputs(&self) { + use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; + self.set_moe(true); + } + } impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => { @@ -947,7 +966,13 @@ foreach_interrupt! { impl_1ch_cmp_timer!($inst); impl_2ch_cmp_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst { + /// Enable timer outputs. + fn enable_outputs(&self) { + use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; + self.set_moe(true); + } + } impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => { diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1acba504e..6df2f66ec 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -82,6 +82,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { this.inner.set_counting_mode(counting_mode); this.set_frequency(freq); + this.inner.enable_outputs(); // Required for advanced timers, see CaptureCompare16bitInstance for details this.inner.start(); [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] From fadffc5061f4eb26886a14a2ecc7e9d11bbb7b0c Mon Sep 17 00:00:00 2001 From: Dominic Date: Fri, 2 Feb 2024 13:47:26 +0100 Subject: [PATCH 656/760] Fix incorrect D1CPRE max for STM32H7 RM0468 --- embassy-stm32/src/rcc/h.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index bab8bb19e..9251df162 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -455,7 +455,7 @@ pub(crate) unsafe fn init(config: Config) { }; #[cfg(pwr_h7rm0468)] let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { - VoltageScale::Scale0 => (Hertz(520_000_000), Hertz(275_000_000), Hertz(137_500_000)), + VoltageScale::Scale0 => (Hertz(550_000_000), Hertz(275_000_000), Hertz(137_500_000)), VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)), From 71179fa818f5ef8578f3b0f73791831821119893 Mon Sep 17 00:00:00 2001 From: Dominic Date: Sat, 9 Mar 2024 11:49:23 +0100 Subject: [PATCH 657/760] Check for CPU_FREQ_BOOST --- embassy-stm32/src/rcc/h.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 9251df162..1949fc891 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -455,7 +455,14 @@ pub(crate) unsafe fn init(config: Config) { }; #[cfg(pwr_h7rm0468)] let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { - VoltageScale::Scale0 => (Hertz(550_000_000), Hertz(275_000_000), Hertz(137_500_000)), + VoltageScale::Scale0 => { + let d1cpre_clk_max = if pac::SYSCFG.ur18().read().cpu_freq_boost() { + 550_000_000 + } else { + 520_000_000 + }; + (Hertz(d1cpre_clk_max), Hertz(275_000_000), Hertz(137_500_000)) + } VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)), From 842f90e3248889ecf340352fbedd7fbcb66812e4 Mon Sep 17 00:00:00 2001 From: Dominic Date: Sat, 9 Mar 2024 11:59:46 +0100 Subject: [PATCH 658/760] No personal preferences in public repository --- .vscode/settings.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 46d26562c..0c195a13b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,4 @@ { - "editor.formatOnSave": true, "[toml]": { "editor.formatOnSave": false }, From 2d7ec281e8843575b56982e8e2bc2159c6386111 Mon Sep 17 00:00:00 2001 From: Harry Brooke Date: Sat, 9 Mar 2024 18:24:31 +0000 Subject: [PATCH 659/760] stm32/rcc: wait for peripheral clock to be active. also, hold the peripheral reset while enabling the clock. --- embassy-stm32/build.rs | 46 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 84e8be25d..ce8283540 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -509,25 +509,20 @@ fn main() { if let Some(rcc) = &p.rcc { let en = rcc.enable.as_ref().unwrap(); - let rst = match &rcc.reset { + let (start_rst, end_rst) = match &rcc.reset { Some(rst) => { let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); - quote! { - crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); - crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); - } + ( + quote! { + crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); + }, + quote! { + crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); + }, + ) } - None => TokenStream::new(), - }; - - let after_enable = if chip_name.starts_with("stm32f2") { - // Errata: ES0005 - 2.1.11 Delay after an RCC peripheral clock enabling - quote! { - cortex_m::asm::dsb(); - } - } else { - TokenStream::new() + None => (TokenStream::new(), TokenStream::new()), }; let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; @@ -596,9 +591,26 @@ fn main() { fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { #before_enable #incr_stop_refcount + + #start_rst + crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); - #after_enable - #rst + // dummy read to ensure write is completed + let _ = crate::pac::RCC.#en_reg().read(); + + // wait two peripheral clock cycles before the clock is active + // accomplish this with two dummy reads from the peripheral. this shouldn't + // cause any side effects since the peripheral is in reset + unsafe { + //apparently volatile accesses to ZST like () can be optimized out. lol + let ptr = crate::pac::#pname.as_ptr() as *const usize; + let _ = ::core::ptr::read_volatile(ptr); + let _ = ::core::ptr::read_volatile(ptr); + // wait for memory accesses to finish + ::core::arch::asm!("dmb"); + } + + #end_rst } fn disable_with_cs(_cs: critical_section::CriticalSection) { #before_disable From b456addb2ba6790f6c738a4e80fcebedafba3ee7 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Sat, 9 Mar 2024 20:13:20 +0000 Subject: [PATCH 660/760] stm32: bump metapac version --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index b326c26fd..ba22ba0b6 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-e7f91751fbbf856e0cb30e50ae6db79f0409b085" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c8b32ecae7d70cea2705095c4fc6bd5f59d238d5" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-e7f91751fbbf856e0cb30e50ae6db79f0409b085", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c8b32ecae7d70cea2705095c4fc6bd5f59d238d5", default-features = false, features = ["metadata"]} [features] From e92094986d1f7845539250ad2833069c49999ae9 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:53:37 -0400 Subject: [PATCH 661/760] Add DMA request priority as transfer option. --- embassy-stm32/src/dma/dma_bdma.rs | 63 ++++++++++++++++++++++++++++--- embassy-stm32/src/dma/mod.rs | 8 ++-- embassy-stm32/src/sdmmc/mod.rs | 1 + 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 08aba2795..5b3243de7 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -10,7 +10,7 @@ use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDm use super::word::{Word, WordSize}; use super::{AnyChannel, Channel, Dir, Request, STATE}; use crate::interrupt::typelevel::Interrupt; -use crate::interrupt::Priority; +use crate::interrupt; use crate::pac; pub(crate) struct ChannelInfo { @@ -45,6 +45,8 @@ pub struct TransferOptions { /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. #[cfg(dma)] pub fifo_threshold: Option, + /// Request priority level + pub priority: Priority, /// Enable circular DMA /// /// Note: @@ -68,6 +70,7 @@ impl Default for TransferOptions { flow_ctrl: FlowControl::Dma, #[cfg(dma)] fifo_threshold: None, + priority: Priority::VeryHigh, circular: false, half_transfer_ir: false, complete_transfer_ir: true, @@ -170,6 +173,31 @@ mod dma_only { } } } + + /// DMA request priority + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum Priority { + /// Low Priority + Low, + /// Medium Priority + Medium, + /// High Priority + High, + /// Very High Priority + VeryHigh, + } + + impl From for vals::Pl { + fn from(value: Priority) -> Self { + match value { + Priority::Low => vals::Pl::LOW, + Priority::Medium => vals::Pl::MEDIUM, + Priority::High => vals::Pl::HIGH, + Priority::VeryHigh => vals::Pl::VERYHIGH, + } + } + } } #[cfg(bdma)] @@ -196,6 +224,31 @@ mod bdma_only { } } } + + /// DMA request priority + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum Priority { + /// Low Priority + Low, + /// Medium Priority + Medium, + /// High Priority + High, + /// Very High Priority + VeryHigh, + } + + impl From for vals::Pl { + fn from(value: Priority) -> Self { + match value { + Priority::Low => vals::Pl::LOW, + Priority::Medium => vals::Pl::MEDIUM, + Priority::High => vals::Pl::HIGH, + Priority::VeryHigh => vals::Pl::VERYHIGH, + } + } + } } pub(crate) struct ChannelState { @@ -213,8 +266,8 @@ impl ChannelState { /// safety: must be called only once pub(crate) unsafe fn init( cs: critical_section::CriticalSection, - #[cfg(dma)] dma_priority: Priority, - #[cfg(bdma)] bdma_priority: Priority, + #[cfg(dma)] dma_priority: interrupt::Priority, + #[cfg(bdma)] bdma_priority: interrupt::Priority, ) { foreach_interrupt! { ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { @@ -334,7 +387,7 @@ impl AnyChannel { w.set_dir(dir.into()); w.set_msize(data_size.into()); w.set_psize(data_size.into()); - w.set_pl(pac::dma::vals::Pl::VERYHIGH); + w.set_pl(options.priority.into()); w.set_minc(incr_mem); w.set_pinc(false); w.set_teie(true); @@ -374,7 +427,7 @@ impl AnyChannel { w.set_tcie(options.complete_transfer_ir); w.set_htie(options.half_transfer_ir); w.set_circ(options.circular); - w.set_pl(pac::bdma::vals::Pl::VERYHIGH); + w.set_pl(options.priority.into()); w.set_en(false); // don't start yet }); } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 960483f34..d5e88a20a 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -23,7 +23,7 @@ use core::mem; use embassy_hal_internal::{impl_peripheral, Peripheral}; -use crate::interrupt::Priority; +use crate::interrupt; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -131,9 +131,9 @@ pub(crate) fn slice_ptr_parts_mut(slice: *mut [T]) -> (usize, usize) { // safety: must be called only once at startup pub(crate) unsafe fn init( cs: critical_section::CriticalSection, - #[cfg(bdma)] bdma_priority: Priority, - #[cfg(dma)] dma_priority: Priority, - #[cfg(gpdma)] gpdma_priority: Priority, + #[cfg(bdma)] bdma_priority: interrupt::Priority, + #[cfg(dma)] dma_priority: interrupt::Priority, + #[cfg(gpdma)] gpdma_priority: interrupt::Priority, ) { #[cfg(any(dma, bdma))] dma_bdma::init( diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index bf1d2ca9b..4d054aa7b 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -240,6 +240,7 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp mburst: crate::dma::Burst::Incr4, flow_ctrl: crate::dma::FlowControl::Peripheral, fifo_threshold: Some(crate::dma::FifoThreshold::Full), + priority: crate::dma::Priority::VeryHigh, circular: false, half_transfer_ir: false, complete_transfer_ir: true, From 50a7ada0bbc4ee8b93d1ec364a5fbf5e4e5eccf7 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 10 Mar 2024 17:28:53 -0400 Subject: [PATCH 662/760] Fixed DMA CI build issues. --- embassy-stm32/src/dma/dma_bdma.rs | 91 +++++++++++++------------------ 1 file changed, 39 insertions(+), 52 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 5b3243de7..7b5b3cf58 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -10,8 +10,7 @@ use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDm use super::word::{Word, WordSize}; use super::{AnyChannel, Channel, Dir, Request, STATE}; use crate::interrupt::typelevel::Interrupt; -use crate::interrupt; -use crate::pac; +use crate::{interrupt, pac}; pub(crate) struct ChannelInfo { pub(crate) dma: DmaInfo, @@ -78,6 +77,44 @@ impl Default for TransferOptions { } } +/// DMA request priority +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Priority { + /// Low Priority + Low, + /// Medium Priority + Medium, + /// High Priority + High, + /// Very High Priority + VeryHigh, +} + +#[cfg(dma)] +impl From for pac::dma::vals::Pl { + fn from(value: Priority) -> Self { + match value { + Priority::Low => pac::dma::vals::Pl::LOW, + Priority::Medium => pac::dma::vals::Pl::MEDIUM, + Priority::High => pac::dma::vals::Pl::HIGH, + Priority::VeryHigh => pac::dma::vals::Pl::VERYHIGH, + } + } +} + +#[cfg(bdma)] +impl From for pac::bdma::vals::Pl { + fn from(value: Priority) -> Self { + match value { + Priority::Low => pac::bdma::vals::Pl::LOW, + Priority::Medium => pac::bdma::vals::Pl::MEDIUM, + Priority::High => pac::bdma::vals::Pl::HIGH, + Priority::VeryHigh => pac::bdma::vals::Pl::VERYHIGH, + } + } +} + #[cfg(dma)] pub use dma_only::*; #[cfg(dma)] @@ -173,31 +210,6 @@ mod dma_only { } } } - - /// DMA request priority - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum Priority { - /// Low Priority - Low, - /// Medium Priority - Medium, - /// High Priority - High, - /// Very High Priority - VeryHigh, - } - - impl From for vals::Pl { - fn from(value: Priority) -> Self { - match value { - Priority::Low => vals::Pl::LOW, - Priority::Medium => vals::Pl::MEDIUM, - Priority::High => vals::Pl::HIGH, - Priority::VeryHigh => vals::Pl::VERYHIGH, - } - } - } } #[cfg(bdma)] @@ -224,31 +236,6 @@ mod bdma_only { } } } - - /// DMA request priority - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum Priority { - /// Low Priority - Low, - /// Medium Priority - Medium, - /// High Priority - High, - /// Very High Priority - VeryHigh, - } - - impl From for vals::Pl { - fn from(value: Priority) -> Self { - match value { - Priority::Low => vals::Pl::LOW, - Priority::Medium => vals::Pl::MEDIUM, - Priority::High => vals::Pl::HIGH, - Priority::VeryHigh => vals::Pl::VERYHIGH, - } - } - } } pub(crate) struct ChannelState { From 4a5b6e05fb806d70747e2abb2da7c90eeba0dc41 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Sun, 10 Mar 2024 17:33:40 -0400 Subject: [PATCH 663/760] Correct more CI build issues. --- embassy-stm32/src/sdmmc/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 4d054aa7b..fa1f710d8 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -247,6 +247,7 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp }; #[cfg(all(sdmmc_v1, not(dma)))] const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { + priority: crate::dma::Priority::VeryHigh, circular: false, half_transfer_ir: false, complete_transfer_ir: true, From f761f721bc42decc5ee7f2669381de16b2f89ab7 Mon Sep 17 00:00:00 2001 From: Harry Brooke Date: Sun, 10 Mar 2024 22:51:42 +0000 Subject: [PATCH 664/760] fix ci --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ce8283540..cee2d7e92 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -607,7 +607,7 @@ fn main() { let _ = ::core::ptr::read_volatile(ptr); let _ = ::core::ptr::read_volatile(ptr); // wait for memory accesses to finish - ::core::arch::asm!("dmb"); + cortex_m::asm::dsb(); } #end_rst From 096d147dce104cfb78480a8e9a6df2b067ccacf5 Mon Sep 17 00:00:00 2001 From: Harry Brooke Date: Mon, 11 Mar 2024 11:04:01 +0000 Subject: [PATCH 665/760] stm32: add disable_ucpdx_dead_battery --- embassy-stm32/src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index ff77399b2..948cde677 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -189,6 +189,18 @@ pub struct Config { /// Defaults to P0 (highest). #[cfg(gpdma)] pub gpdma_interrupt_priority: Priority, + + /// Disables UCPD1 dead battery functionality. + /// + /// Defaults to true (disabled). + #[cfg(ucpd)] + pub disable_ucpd1_dead_battery: bool, + + /// Disables UCPD2 dead battery functionality. + /// + /// Defaults to true (disabled). + #[cfg(all(ucpd, stm32g0x1))] + pub disable_ucpd2_dead_battery: bool, } impl Default for Config { @@ -203,6 +215,10 @@ impl Default for Config { dma_interrupt_priority: Priority::P0, #[cfg(gpdma)] gpdma_interrupt_priority: Priority::P0, + #[cfg(ucpd)] + disable_ucpd1_dead_battery: true, + #[cfg(all(ucpd, stm32g0x1))] + uisable_ucpd2_dead_battery: true, } } } @@ -254,6 +270,36 @@ pub fn init(config: Config) -> Peripherals { #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] peripherals::FLASH::enable_and_reset_with_cs(cs); + // dead battery IOs are still present on g0x0 despite not having UCPD + #[cfg(any(stm32g070, stm32g0b0))] + let (disable_ucpd1_dead_battery, disable_ucpd2_dead_battery) = (true, true); + #[cfg(ucpd)] + let disable_ucpd1_dead_battery = config.disable_ucpd1_dead_battery; + #[cfg(all(ucpd, stm32g0x1))] + let disable_ucpd2_dead_battery = config.disable_ucpd2_dead_battery; + + #[cfg(any(stm32g070, stm32g0b0, all(ucpd, stm32g0x1)))] + { + crate::pac::SYSCFG.cfgr1().modify(|w| { + w.set_ucpd1_strobe(disable_ucpd1_dead_battery); + w.set_ucpd2_strobe(disable_ucpd2_dead_battery); + }); + } + + #[cfg(all(ucpd, any(stm32g4, stm32l5)))] + { + crate::pac::PWR + .cr3() + .modify(|w| w.set_ucpd1_dbdis(disable_ucpd1_dead_battery)) + } + + #[cfg(all(ucpd, any(stm32h5, stm32u5)))] + { + crate::pac::PWR + .ucpdr() + .modify(|w| w.set_ucpd1_dbdis(disable_ucpd1_dead_battery)) + } + unsafe { #[cfg(feature = "_split-pins-enabled")] crate::pac::SYSCFG.pmcr().modify(|pmcr| { From 6e9e8eeb5f6458833b28a08e7480b2630107d79c Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 5 Mar 2024 11:25:56 -0500 Subject: [PATCH 666/760] Refactored cryp din/dout into functions. --- embassy-stm32/src/cryp/mod.rs | 276 +++++++++++++++---------------- examples/stm32f7/src/bin/cryp.rs | 14 +- 2 files changed, 144 insertions(+), 146 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 8f259520a..12353baa0 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -4,12 +4,35 @@ use core::cmp::min; use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; -use crate::{interrupt, pac, peripherals, Peripheral}; +use crate::interrupt::typelevel::Interrupt; +use crate::{dma::NoDma, interrupt, pac, peripherals, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits +static CRYP_WAKER: AtomicWaker = AtomicWaker::new(); + +/// CRYP interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let bits = T::regs().misr().read(); + if bits.inmis() { + T::regs().imscr().modify(|w| w.set_inim(false)); + CRYP_WAKER.wake(); + } + if bits.outmis() { + T::regs().imscr().modify(|w| w.set_outim(false)); + CRYP_WAKER.wake(); + } + } +} + /// This trait encapsulates all cipher-specific behavior/ pub trait Cipher<'c> { /// Processing block size. Determined by the processor and the algorithm. @@ -32,7 +55,7 @@ pub trait Cipher<'c> { fn prepare_key(&self, _p: &pac::cryp::Cryp) {} /// Performs any cipher-specific initialization. - fn init_phase(&self, _p: &pac::cryp::Cryp) {} + fn init_phase(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp) {} /// Called prior to processing the last data block for cipher-specific operations. fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { @@ -40,9 +63,10 @@ pub trait Cipher<'c> { } /// Called after processing the last data block for cipher-specific operations. - fn post_final_block( + fn post_final_block( &self, _p: &pac::cryp::Cryp, + _cryp: &Cryp, _dir: Direction, _int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -425,7 +449,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase(&self, p: &pac::cryp::Cryp) { + fn init_phase(&self, p: &pac::cryp::Cryp, _cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -453,9 +477,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - fn post_final_block( + fn post_final_block( &self, p: &pac::cryp::Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -471,17 +496,9 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_gcm_ccmph(3)); - let mut index = 0; - let end_index = Self::BLOCK_SIZE; - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&int_data[index..index + 4]); - p.din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } - for _ in 0..4 { - p.dout().read(); - } + + cryp.write_bytes_blocking(Self::BLOCK_SIZE, int_data); + cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data); } } } @@ -532,7 +549,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase(&self, p: &pac::cryp::Cryp) { + fn init_phase(&self, p: &pac::cryp::Cryp, _cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -560,9 +577,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - fn post_final_block( + fn post_final_block( &self, p: &pac::cryp::Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -578,17 +596,9 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_gcm_ccmph(3)); - let mut index = 0; - let end_index = Self::BLOCK_SIZE; - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&int_data[index..index + 4]); - p.din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } - for _ in 0..4 { - p.dout().read(); - } + + cryp.write_bytes_blocking(Self::BLOCK_SIZE, int_data); + cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data); } } } @@ -697,18 +707,11 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase(&self, p: &pac::cryp::Cryp) { + fn init_phase(&self, p: &pac::cryp::Cryp, cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); - let mut index = 0; - let end_index = index + Self::BLOCK_SIZE; - // Write block in - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&self.block0[index..index + 4]); - p.din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } + cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0); + p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} } @@ -744,9 +747,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } #[cfg(cryp_v2)] - fn post_final_block( + fn post_final_block( &self, p: &pac::cryp::Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], temp1: [u32; 4], @@ -774,8 +778,8 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip let int_word = u32::from_le_bytes(int_bytes); in_data[i] = int_word; in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; - p.din().write_value(in_data[i]); } + cryp.write_words_blocking(Self::BLOCK_SIZE, &in_data); } } } @@ -845,16 +849,31 @@ pub enum Direction { } /// Crypto Accelerator Driver -pub struct Cryp<'d, T: Instance> { +pub struct Cryp<'d, T: Instance, D = NoDma> { _peripheral: PeripheralRef<'d, T>, + indma: PeripheralRef<'d, D>, + outdma: PeripheralRef<'d, D>, } -impl<'d, T: Instance> Cryp<'d, T> { +impl<'d, T: Instance, D> Cryp<'d, T, D> { /// Create a new CRYP driver. - pub fn new(peri: impl Peripheral

+ 'd) -> Self { + pub fn new( + peri: impl Peripheral

+ 'd, + indma: impl Peripheral

+ 'd, + outdma: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { T::enable_and_reset(); - into_ref!(peri); - let instance = Self { _peripheral: peri }; + into_ref!(peri, indma, outdma); + let instance = Self { + _peripheral: peri, + indma: indma, + outdma: outdma, + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + instance } @@ -929,7 +948,7 @@ impl<'d, T: Instance> Cryp<'d, T> { // Flush in/out FIFOs T::regs().cr().modify(|w| w.fflush()); - ctx.cipher.init_phase(&T::regs()); + ctx.cipher.init_phase(&T::regs(), self); self.store_context(&mut ctx); @@ -985,15 +1004,7 @@ impl<'d, T: Instance> Cryp<'d, T> { if ctx.aad_buffer_len < C::BLOCK_SIZE { // The buffer isn't full and this is the last buffer, so process it as is (already padded). if last_aad_block { - let mut index = 0; - let end_index = C::BLOCK_SIZE; - // Write block in - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); - T::regs().din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } + self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer); // Block until input FIFO is empty. while !T::regs().sr().read().ifem() {} @@ -1008,15 +1019,7 @@ impl<'d, T: Instance> Cryp<'d, T> { } } else { // Load the full block from the buffer. - let mut index = 0; - let end_index = C::BLOCK_SIZE; - // Write block in - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); - T::regs().din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } + self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer); // Block until input FIFO is empty. while !T::regs().sr().read().ifem() {} } @@ -1032,33 +1035,13 @@ impl<'d, T: Instance> Cryp<'d, T> { // Load full data blocks into core. let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; - for block in 0..num_full_blocks { - let mut index = len_to_copy + (block * C::BLOCK_SIZE); - let end_index = index + C::BLOCK_SIZE; - // Write block in - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&aad[index..index + 4]); - T::regs().din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } - // Block until input FIFO is empty. - while !T::regs().sr().read().ifem() {} - } + let start_index = len_to_copy; + let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks); + self.write_bytes_blocking(C::BLOCK_SIZE, &aad[start_index..end_index]); if last_aad_block { if leftovers > 0 { - let mut index = 0; - let end_index = C::BLOCK_SIZE; - // Write block in - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); - T::regs().din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } - // Block until input FIFO is empty. - while !T::regs().sr().read().ifem() {} + self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer); } // Switch to payload phase. ctx.aad_complete = true; @@ -1125,25 +1108,11 @@ impl<'d, T: Instance> Cryp<'d, T> { // Load data into core, block by block. let num_full_blocks = input.len() / C::BLOCK_SIZE; for block in 0..num_full_blocks { - let mut index = block * C::BLOCK_SIZE; - let end_index = index + C::BLOCK_SIZE; + let index = block * C::BLOCK_SIZE; // Write block in - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&input[index..index + 4]); - T::regs().din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } - let mut index = block * C::BLOCK_SIZE; - let end_index = index + C::BLOCK_SIZE; - // Block until there is output to read. - while !T::regs().sr().read().ofne() {} + self.write_bytes_blocking(C::BLOCK_SIZE, &input[index..index + 4]); // Read block out - while index < end_index { - let out_word: u32 = T::regs().dout().read(); - output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); - index += 4; - } + self.read_bytes_blocking(C::BLOCK_SIZE, &mut output[index..index + 4]); } // Handle the final block, which is incomplete. @@ -1154,25 +1123,8 @@ impl<'d, T: Instance> Cryp<'d, T> { let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); - let mut index = 0; - let end_index = C::BLOCK_SIZE; - // Write block in - while index < end_index { - let mut in_word: [u8; 4] = [0; 4]; - in_word.copy_from_slice(&last_block[index..index + 4]); - T::regs().din().write_value(u32::from_ne_bytes(in_word)); - index += 4; - } - let mut index = 0; - let end_index = C::BLOCK_SIZE; - // Block until there is output to read. - while !T::regs().sr().read().ofne() {} - // Read block out - while index < end_index { - let out_word: u32 = T::regs().dout().read(); - intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); - index += 4; - } + self.write_bytes_blocking(C::BLOCK_SIZE, &last_block); + self.read_bytes_blocking(C::BLOCK_SIZE, &mut intermediate_data); // Handle the last block depending on mode. let output_len = output.len(); @@ -1182,7 +1134,7 @@ impl<'d, T: Instance> Cryp<'d, T> { let mut mask: [u8; 16] = [0; 16]; mask[..last_block_remainder].fill(0xFF); ctx.cipher - .post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask); + .post_final_block(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask); } ctx.payload_len += input.len() as u64; @@ -1213,28 +1165,21 @@ impl<'d, T: Instance> Cryp<'d, T> { let payloadlen2: u32 = (ctx.payload_len * 8) as u32; #[cfg(cryp_v2)] - { - T::regs().din().write_value(headerlen1.swap_bytes()); - T::regs().din().write_value(headerlen2.swap_bytes()); - T::regs().din().write_value(payloadlen1.swap_bytes()); - T::regs().din().write_value(payloadlen2.swap_bytes()); - } - + let footer: [u32; 4] = [ + headerlen1.swap_bytes(), + headerlen2.swap_bytes(), + payloadlen1.swap_bytes(), + payloadlen2.swap_bytes(), + ]; #[cfg(cryp_v3)] - { - T::regs().din().write_value(headerlen1); - T::regs().din().write_value(headerlen2); - T::regs().din().write_value(payloadlen1); - T::regs().din().write_value(payloadlen2); - } + let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; + + self.write_words_blocking(C::BLOCK_SIZE, &footer); while !T::regs().sr().read().ofne() {} let mut full_tag: [u8; 16] = [0; 16]; - full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); - full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); - full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); - full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + self.read_bytes_blocking(C::BLOCK_SIZE, &mut full_tag); let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; tag.copy_from_slice(&full_tag[0..TAG_SIZE]); @@ -1325,6 +1270,51 @@ impl<'d, T: Instance> Cryp<'d, T> { // Enable crypto processor. T::regs().cr().modify(|w| w.set_crypen(true)); } + + fn write_bytes_blocking(&self, block_size: usize, blocks: &[u8]) { + // Ensure input is a multiple of block size. + assert_eq!(blocks.len() % block_size, 0); + let mut index = 0; + let end_index = blocks.len(); + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&blocks[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + if index % block_size == 0 { + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + } + } + } + + fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) { + assert_eq!((blocks.len() * 4) % block_size, 0); + let mut byte_counter: usize = 0; + for word in blocks { + T::regs().din().write_value(*word); + byte_counter += 4; + if byte_counter % block_size == 0 { + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + } + } + } + + fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) { + // Block until there is output to read. + while !T::regs().sr().read().ofne() {} + // Ensure input is a multiple of block size. + assert_eq!(blocks.len() % block_size, 0); + // Read block out + let mut index = 0; + let end_index = blocks.len(); + while index < end_index { + let out_word: u32 = T::regs().dout().read(); + blocks[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); + index += 4; + } + } } pub(crate) mod sealed { diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index 04927841a..79b74e569 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -6,11 +6,19 @@ use aes_gcm::aead::{AeadInPlace, KeyInit}; use aes_gcm::Aes128Gcm; use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::cryp::*; -use embassy_stm32::Config; +use embassy_stm32::dma::NoDma; +use embassy_stm32::{ + bind_interrupts, + cryp::{self, *}, +}; +use embassy_stm32::{peripherals, Config}; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + CRYP => cryp::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let config = Config::default(); @@ -19,7 +27,7 @@ async fn main(_spawner: Spawner) -> ! { let payload: &[u8] = b"hello world"; let aad: &[u8] = b"additional data"; - let hw_cryp = Cryp::new(p.CRYP); + let hw_cryp = Cryp::new(p.CRYP, NoDma, NoDma, Irqs); let key: [u8; 16] = [0; 16]; let mut ciphertext: [u8; 11] = [0; 11]; let mut plaintext: [u8; 11] = [0; 11]; From b6a383811a775d1cb98b4fb2070c55e95c66a648 Mon Sep 17 00:00:00 2001 From: Dominic Date: Mon, 11 Mar 2024 17:51:53 +0100 Subject: [PATCH 667/760] Improve panic message when requesting frequency higher than clock Previously it would panic with message "unreachable", which isn't particularly clear about what the problem is and how to fix it. --- embassy-stm32/src/spi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 172bc8112..b517f640a 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -700,7 +700,7 @@ use vals::Mbr as Br; fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { let val = match clocks.0 / freq.0 { - 0 => unreachable!(), + 0 => panic!("You are trying to reach a frequency higher than the clock"), 1..=2 => 0b000, 3..=5 => 0b001, 6..=11 => 0b010, From d4869b83fcc160dc9a5338e7e47c18197b9cb7f5 Mon Sep 17 00:00:00 2001 From: Harry Brooke Date: Mon, 11 Mar 2024 21:45:41 +0000 Subject: [PATCH 668/760] disable -> enable. also extracted to function for easy refactoring later --- embassy-stm32/src/lib.rs | 100 +++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 36 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 948cde677..b548a0343 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -190,17 +190,17 @@ pub struct Config { #[cfg(gpdma)] pub gpdma_interrupt_priority: Priority, - /// Disables UCPD1 dead battery functionality. + /// Enables UCPD1 dead battery functionality. /// - /// Defaults to true (disabled). - #[cfg(ucpd)] - pub disable_ucpd1_dead_battery: bool, + /// Defaults to false (disabled). + #[cfg(peri_ucpd1)] + pub enable_ucpd1_dead_battery: bool, - /// Disables UCPD2 dead battery functionality. + /// Enables UCPD2 dead battery functionality. /// - /// Defaults to true (disabled). - #[cfg(all(ucpd, stm32g0x1))] - pub disable_ucpd2_dead_battery: bool, + /// Defaults to false (disabled). + #[cfg(peri_ucpd2)] + pub enable_ucpd2_dead_battery: bool, } impl Default for Config { @@ -215,10 +215,10 @@ impl Default for Config { dma_interrupt_priority: Priority::P0, #[cfg(gpdma)] gpdma_interrupt_priority: Priority::P0, - #[cfg(ucpd)] - disable_ucpd1_dead_battery: true, - #[cfg(all(ucpd, stm32g0x1))] - uisable_ucpd2_dead_battery: true, + #[cfg(peri_ucpd1)] + enable_ucpd1_dead_battery: false, + #[cfg(peri_ucpd2)] + enable_ucpd2_dead_battery: false, } } } @@ -270,37 +270,27 @@ pub fn init(config: Config) -> Peripherals { #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] peripherals::FLASH::enable_and_reset_with_cs(cs); - // dead battery IOs are still present on g0x0 despite not having UCPD + // dead battery functionality is still present on these + // chips despite them not having UCPD- disable it #[cfg(any(stm32g070, stm32g0b0))] - let (disable_ucpd1_dead_battery, disable_ucpd2_dead_battery) = (true, true); - #[cfg(ucpd)] - let disable_ucpd1_dead_battery = config.disable_ucpd1_dead_battery; - #[cfg(all(ucpd, stm32g0x1))] - let disable_ucpd2_dead_battery = config.disable_ucpd2_dead_battery; - - #[cfg(any(stm32g070, stm32g0b0, all(ucpd, stm32g0x1)))] { crate::pac::SYSCFG.cfgr1().modify(|w| { - w.set_ucpd1_strobe(disable_ucpd1_dead_battery); - w.set_ucpd2_strobe(disable_ucpd2_dead_battery); + w.set_ucpd1_strobe(true); + w.set_ucpd2_strobe(true); }); } - #[cfg(all(ucpd, any(stm32g4, stm32l5)))] - { - crate::pac::PWR - .cr3() - .modify(|w| w.set_ucpd1_dbdis(disable_ucpd1_dead_battery)) - } - - #[cfg(all(ucpd, any(stm32h5, stm32u5)))] - { - crate::pac::PWR - .ucpdr() - .modify(|w| w.set_ucpd1_dbdis(disable_ucpd1_dead_battery)) - } - unsafe { + // TODO: refactor into mod ucpd + #[cfg(ucpd)] + ucpd_init( + cs, + #[cfg(peri_ucpd1)] + config.enable_ucpd1_dead_battery, + #[cfg(peri_ucpd2)] + config.enable_ucpd2_dead_battery, + ); + #[cfg(feature = "_split-pins-enabled")] crate::pac::SYSCFG.pmcr().modify(|pmcr| { #[cfg(feature = "split-pa0")] @@ -342,3 +332,41 @@ pub fn init(config: Config) -> Peripherals { p }) } + +#[cfg(ucpd)] +/// Safety: must only be called when all UCPDs are disabled (e.g. at startup) +unsafe fn ucpd_init( + _cs: critical_section::CriticalSection, + #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, + #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, +) { + #[cfg(stm32g0x1)] + { + // according to RM0444 (STM32G0x1) section 8.1.1: + // when UCPD is disabled setting the strobe will disable dead battery + // (which is enabled after reset) but if UCPD is enabled, setting the + // strobe will apply the CC pin configuration from the control register + // (which is why we need to be careful about when we call this) + crate::pac::SYSCFG.cfgr1().modify(|w| { + w.set_ucpd1_strobe(ucpd1_db_enable); + w.set_ucpd2_strobe(ucpd2_db_enable); + }); + } + + #[cfg(any(stm32g4, stm32l5))] + { + crate::pac::PWR.cr3().modify(|w| { + #[cfg(stm32g4)] + w.set_ucpd1_dbdis(!ucpd1_db_enable); + #[cfg(stm32l5)] + w.set_ucpd_dbdis(!ucpd1_db_enable); + }) + } + + #[cfg(any(stm32h5, stm32u5))] + { + crate::pac::PWR.ucpdr().modify(|w| { + w.set_ucpd_dbdis(!ucpd1_db_enable); + }) + } +} From 8a255b375b7598c2825535cb0d0729311a7b882d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Fri, 1 Mar 2024 14:59:21 +0100 Subject: [PATCH 669/760] [UCPD] Instance and Pin Traits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skip FRSTX pin for now. Its available twice in the device JSON as FRSTX1 and FRSTX2 both with the same pins as targets. I don’t know enough about the FRS (fast role switch) feature to understand if that is correct and how to handle the pins. --- embassy-stm32/build.rs | 4 ++++ embassy-stm32/src/lib.rs | 2 ++ embassy-stm32/src/ucpd.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 embassy-stm32/src/ucpd.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 84e8be25d..680216034 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -764,6 +764,8 @@ fn main() { #[rustfmt::skip] let signals: HashMap<_, _> = [ // (kind, signal) => trait + (("ucpd", "CC1"), quote!(crate::ucpd::Cc1Pin)), + (("ucpd", "CC2"), quote!(crate::ucpd::Cc2Pin)), (("usart", "TX"), quote!(crate::usart::TxPin)), (("usart", "RX"), quote!(crate::usart::RxPin)), (("usart", "CTS"), quote!(crate::usart::CtsPin)), @@ -1102,6 +1104,8 @@ fn main() { let signals: HashMap<_, _> = [ // (kind, signal) => trait + (("ucpd", "RX"), quote!(crate::ucpd::RxDma)), + (("ucpd", "TX"), quote!(crate::ucpd::TxDma)), (("usart", "RX"), quote!(crate::usart::RxDma)), (("usart", "TX"), quote!(crate::usart::TxDma)), (("lpuart", "RX"), quote!(crate::usart::RxDma)), diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index b548a0343..361dc6f53 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -73,6 +73,8 @@ pub mod sai; pub mod sdmmc; #[cfg(spi)] pub mod spi; +#[cfg(ucpd)] +pub mod ucpd; #[cfg(uid)] pub mod uid; #[cfg(usart)] diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs new file mode 100644 index 000000000..a2bac7611 --- /dev/null +++ b/embassy-stm32/src/ucpd.rs @@ -0,0 +1,28 @@ +//! USB Type-C/USB Power Delivery Interface (UCPD) + +use crate::rcc::RccPeripheral; + +/// UCPD instance trait. +pub trait Instance: sealed::Instance + RccPeripheral {} + +pub(crate) mod sealed { + pub trait Instance { + const REGS: crate::pac::ucpd::Ucpd; + } +} + +foreach_peripheral!( + (ucpd, $inst:ident) => { + impl sealed::Instance for crate::peripherals::$inst { + const REGS: crate::pac::ucpd::Ucpd = crate::pac::$inst; + } + + impl Instance for crate::peripherals::$inst {} + }; +); + +pin_trait!(Cc1Pin, Instance); +pin_trait!(Cc2Pin, Instance); + +dma_trait!(TxDma, Instance); +dma_trait!(RxDma, Instance); From aa1411e2c772fd332417ca258b58c75b35d5b7ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Sun, 3 Mar 2024 15:02:00 +0100 Subject: [PATCH 670/760] [UCPD] Prepare interrupt handle --- embassy-stm32/src/ucpd.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index a2bac7611..a3f01c629 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -1,20 +1,49 @@ //! USB Type-C/USB Power Delivery Interface (UCPD) +use core::marker::PhantomData; + +use crate::interrupt; use crate::rcc::RccPeripheral; +use embassy_sync::waitqueue::AtomicWaker; + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let sr = T::REGS.sr().read(); + + // TODO: Disable interrupt which have fired. + + // Wake the task to handle and re-enabled interrupts. + T::waker().wake(); + } +} /// UCPD instance trait. pub trait Instance: sealed::Instance + RccPeripheral {} pub(crate) mod sealed { pub trait Instance { + type Interrupt: crate::interrupt::typelevel::Interrupt; const REGS: crate::pac::ucpd::Ucpd; + fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker; } } -foreach_peripheral!( - (ucpd, $inst:ident) => { +foreach_interrupt!( + ($inst:ident, ucpd, UCPD, GLOBAL, $irq:ident) => { impl sealed::Instance for crate::peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + const REGS: crate::pac::ucpd::Ucpd = crate::pac::$inst; + + fn waker() -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } } impl Instance for crate::peripherals::$inst {} From d99fcfd0c285be220c8f0004974567d7d4e2607b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Sun, 3 Mar 2024 15:09:53 +0100 Subject: [PATCH 671/760] [UCPD] Configuration Channel (CC) handling --- embassy-stm32/src/ucpd.rs | 171 ++++++++++++++++++++++++++- examples/stm32g4/src/bin/usb_c_pd.rs | 62 ++++++++++ 2 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 examples/stm32g4/src/bin/usb_c_pd.rs diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index a3f01c629..98b82bacc 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -1,10 +1,165 @@ //! USB Type-C/USB Power Delivery Interface (UCPD) -use core::marker::PhantomData; +// Implementation Notes +// +// As of Feb. 2024 the UCPD peripheral is availalbe on: G0, G4, H5, L5, U5 +// +// Cube HAL LL Driver (g0): +// https://github.com/STMicroelectronics/stm32g0xx_hal_driver/blob/v1.4.6/Inc/stm32g0xx_ll_ucpd.h +// https://github.com/STMicroelectronics/stm32g0xx_hal_driver/blob/v1.4.6/Src/stm32g0xx_ll_ucpd.c +// Except for a the `LL_UCPD_RxAnalogFilterEnable/Disable()` functions the Cube HAL implementation of +// all families is the same. +// +// Dead battery pull-down resistors functionality is enabled by default on startup and must +// be disabled by setting a bit in PWR/SYSCFG registers. The exact name and location for that +// bit is different for each familily. + +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; -use crate::interrupt; use crate::rcc::RccPeripheral; +use crate::{interrupt, pac}; +use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +use pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk}; + +pub use pac::ucpd::vals::TypecVstateCc as CcVState; + +/// Pull-up or Pull-down resistor state of both CC lines. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum CcPull { + /// Analog PHY for CC pin disabled. + Disabled, + + /// Rd=5.1k pull-down resistor enabled when the corresponding DBCC pin is high. + SinkDeadBattery, + + /// Rd=5.1k pull-down resistor. + Sink, + + /// Rp=56k pull-up resistor to indicate default USB power. + SourceDefaultUsb, + + /// Rp=22k pull-up resistor to indicate support for up to 1.5A. + Source1_5A, + + /// Rp=10k pull-up resistor to indicate support for up to 3.0A. + Source3_0A, +} + +/// UCPD driver. +pub struct Ucpd<'d, T: Instance> { + _peri: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Ucpd<'d, T> { + /// Creates a new UCPD driver instance. + pub fn new( + peri: impl Peripheral

+ 'd, + _cc1: impl Peripheral

> + 'd, + _cc2: impl Peripheral

> + 'd, + cc_pull: CcPull, + ) -> Self { + T::enable_and_reset(); + + let r = T::REGS; + r.cfgr1().write(|w| { + // "The receiver is designed to work in the clock frequency range from 6 to 18 MHz. + // However, the optimum performance is ensured in the range from 6 to 12 MHz" + // UCPD is driven by HSI16 (16MHz internal oscillator), which we need to divide by 2. + w.set_psc_usbpdclk(PscUsbpdclk::DIV2); + + // Prescaler to produce a target half-bit frequency of 600kHz which is required + // to produce transmit with a nominal nominal bit rate of 300Kbps+-10% using + // biphase mark coding (BMC, aka differential manchester coding). + // A divider of 13 gives the target frequency closest to spec (~615kHz, 1.625us) + // but we go with the (hopefully well tested) default value used by the Cube HAL + // which is 14 divides the clock down to ~571kHz, 1.75us. + w.set_hbitclkdiv(14 - 1); + + // Time window for detecting non-idle (12-20us). + // 1.75us * 8 = 14us. + w.set_transwin(8 - 1); + + // Time from the end of last bit of a Frame until the start of the first bit of the + // next Preamble (min 25us). + // 1.75us * 17 = ~30us + w.set_ifrgap(17 - 1); + + // TODO: Only receive SOP messages + w.set_rxordseten(0x1); + + // Enable DMA and the peripheral + w.set_txdmaen(true); + w.set_rxdmaen(true); + w.set_ucpden(true); + }); + + r.cr().write(|w| { + w.set_anamode(if cc_pull == CcPull::Sink { + Anamode::SINK + } else { + Anamode::SOURCE + }); + w.set_anasubmode(match cc_pull { + CcPull::SourceDefaultUsb => 1, + CcPull::Source1_5A => 2, + CcPull::Source3_0A => 3, + _ => 0, + }); + w.set_ccenable(if cc_pull != CcPull::SinkDeadBattery { + Ccenable::BOTH + } else { + Ccenable::DISABLED + }); + }); + + // Disable dead-battery pull-down resistors which are enabled by default on boot. + critical_section::with(|_| { + // TODO: other families + #[cfg(stm32g4)] + pac::PWR + .cr3() + .modify(|w| w.set_ucpd1_dbdis(cc_pull != CcPull::SinkDeadBattery)); + }); + + into_ref!(peri); + Self { _peri: peri } + } + + /// Returns the current voltage level of CC1 and CC2 pin as tuple. + /// + /// Interpretation of the voltage levels depends on the configured CC line + /// pull-up/pull-down resistance. + pub fn cc_vstate(&self) -> (CcVState, CcVState) { + let sr = T::REGS.sr().read(); + (sr.typec_vstate_cc1(), sr.typec_vstate_cc2()) + } + + /// Waits for a change in voltage state on either CC line. + pub async fn wait_for_cc_change(&mut self) { + let r = T::REGS; + poll_fn(|cx| { + let sr = r.sr().read(); + if sr.typecevt1() || sr.typecevt2() { + r.icr().write(|w| { + w.set_typecevt1cf(true); + w.set_typecevt2cf(true); + }); + Poll::Ready(()) + } else { + T::waker().register(cx.waker()); + r.imr().modify(|w| { + w.set_typecevt1ie(true); + w.set_typecevt2ie(true); + }); + Poll::Pending + } + }) + .await; + } +} /// Interrupt handler. pub struct InterruptHandler { @@ -13,11 +168,17 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let sr = T::REGS.sr().read(); + let r = T::REGS; + let sr = r.sr().read(); - // TODO: Disable interrupt which have fired. + if sr.typecevt1() || sr.typecevt2() { + r.imr().modify(|w| { + w.set_typecevt1ie(true); + w.set_typecevt2ie(true); + }); + } - // Wake the task to handle and re-enabled interrupts. + // Wake the task to clear and re-enabled interrupts. T::waker().wake(); } } diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs new file mode 100644 index 000000000..c442ab0a7 --- /dev/null +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -0,0 +1,62 @@ +#![no_std] +#![no_main] + +use defmt::{info, Format}; +use embassy_executor::Spawner; +use embassy_stm32::{ + ucpd::{self, CcPull, CcVState, Ucpd}, + Config, +}; +use embassy_time::{with_timeout, Duration}; +use {defmt_rtt as _, panic_probe as _}; + +#[derive(Debug, Format)] +enum CableOrientation { + Normal, + Flipped, + DebugAccessoryMode, +} + +// Returns true when the cable +async fn wait_attached<'d, T: ucpd::Instance>(ucpd: &mut Ucpd<'d, T>) -> CableOrientation { + loop { + let (cc1, cc2) = ucpd.cc_vstate(); + if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST { + // Detached, wait until attached by monitoring the CC lines. + ucpd.wait_for_cc_change().await; + continue; + } + + // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms). + if with_timeout(Duration::from_millis(100), ucpd.wait_for_cc_change()) + .await + .is_ok() + { + // State has changed, restart detection procedure. + continue; + }; + + // State was stable for the complete debounce period, check orientation. + return match (cc1, cc2) { + (_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected + (CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected + _ => CableOrientation::DebugAccessoryMode, // Both connected (special cable) + }; + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // TODO: Disable DBCC pin functionality by default but have flag in the config to keep it enabled when required. + let p = embassy_stm32::init(Config::default()); + + info!("Hello World!"); + + let mut ucpd = Ucpd::new(p.UCPD1, p.PB6, p.PB4, CcPull::Sink); + + info!("Waiting for USB connection..."); + let cable_orientation = wait_attached(&mut ucpd).await; + info!("USB cable connected, orientation: {}", cable_orientation); + + loop {} +} From a3b12226170d6b1a9ded47cc043cc09489cee278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 7 Mar 2024 09:17:05 +0100 Subject: [PATCH 672/760] [UCPD] Improve Type-C CC handling * Improved interrupt handling: Clear flags in ISR, check state change in future * Disable pull-up/pull-down resistors and voltage monitor on drop * nightly rustfmt --- embassy-stm32/src/ucpd.rs | 62 ++++++++++++++++++---------- examples/stm32g4/src/bin/usb_c_pd.rs | 12 +++--- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 98b82bacc..a366fadda 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -18,13 +18,14 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use crate::rcc::RccPeripheral; -use crate::{interrupt, pac}; +use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk}; -pub use pac::ucpd::vals::TypecVstateCc as CcVState; +use crate::interrupt; +pub use crate::pac::ucpd::vals::TypecVstateCc as CcVState; +use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk}; +use crate::rcc::RccPeripheral; /// Pull-up or Pull-down resistor state of both CC lines. #[derive(Debug, Clone, Copy, PartialEq)] @@ -53,6 +54,16 @@ pub struct Ucpd<'d, T: Instance> { _peri: PeripheralRef<'d, T>, } +impl<'d, T: Instance> Drop for Ucpd<'d, T> { + fn drop(&mut self) { + T::REGS.cr().modify(|w| { + w.set_ccenable(Ccenable::DISABLED); + w.set_cc1tcdis(true); + w.set_cc2tcdis(true); + }); + } +} + impl<'d, T: Instance> Ucpd<'d, T> { /// Creates a new UCPD driver instance. pub fn new( @@ -113,13 +124,17 @@ impl<'d, T: Instance> Ucpd<'d, T> { } else { Ccenable::DISABLED }); + + // Make sure detector is enabled on both pins. + w.set_cc1tcdis(false); + w.set_cc2tcdis(false); }); // Disable dead-battery pull-down resistors which are enabled by default on boot. critical_section::with(|_| { // TODO: other families #[cfg(stm32g4)] - pac::PWR + crate::pac::PWR .cr3() .modify(|w| w.set_ucpd1_dbdis(cc_pull != CcPull::SinkDeadBattery)); }); @@ -138,26 +153,29 @@ impl<'d, T: Instance> Ucpd<'d, T> { } /// Waits for a change in voltage state on either CC line. - pub async fn wait_for_cc_change(&mut self) { - let r = T::REGS; + pub async fn wait_for_cc_vstate_change(&self) -> (CcVState, CcVState) { + let _on_drop = OnDrop::new(|| critical_section::with(|_| self.enable_cc_interrupts(false))); + let prev_vstate = self.cc_vstate(); poll_fn(|cx| { - let sr = r.sr().read(); - if sr.typecevt1() || sr.typecevt2() { - r.icr().write(|w| { - w.set_typecevt1cf(true); - w.set_typecevt2cf(true); - }); - Poll::Ready(()) + let vstate = self.cc_vstate(); + if vstate != prev_vstate { + Poll::Ready(vstate) } else { T::waker().register(cx.waker()); - r.imr().modify(|w| { - w.set_typecevt1ie(true); - w.set_typecevt2ie(true); - }); + self.enable_cc_interrupts(true); Poll::Pending } }) - .await; + .await + } + + fn enable_cc_interrupts(&self, enable: bool) { + critical_section::with(|_| { + T::REGS.imr().modify(|w| { + w.set_typecevt1ie(enable); + w.set_typecevt2ie(enable); + }) + }); } } @@ -172,9 +190,9 @@ impl interrupt::typelevel::Handler for InterruptHandl let sr = r.sr().read(); if sr.typecevt1() || sr.typecevt2() { - r.imr().modify(|w| { - w.set_typecevt1ie(true); - w.set_typecevt2ie(true); + r.icr().write(|w| { + w.set_typecevt1cf(true); + w.set_typecevt2cf(true); }); } diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index c442ab0a7..7a0065087 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -3,10 +3,8 @@ use defmt::{info, Format}; use embassy_executor::Spawner; -use embassy_stm32::{ - ucpd::{self, CcPull, CcVState, Ucpd}, - Config, -}; +use embassy_stm32::ucpd::{self, CcPull, CcVState, Ucpd}; +use embassy_stm32::Config; use embassy_time::{with_timeout, Duration}; use {defmt_rtt as _, panic_probe as _}; @@ -18,17 +16,17 @@ enum CableOrientation { } // Returns true when the cable -async fn wait_attached<'d, T: ucpd::Instance>(ucpd: &mut Ucpd<'d, T>) -> CableOrientation { +async fn wait_attached(ucpd: &mut Ucpd<'_, T>) -> CableOrientation { loop { let (cc1, cc2) = ucpd.cc_vstate(); if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST { // Detached, wait until attached by monitoring the CC lines. - ucpd.wait_for_cc_change().await; + ucpd.wait_for_cc_vstate_change().await; continue; } // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms). - if with_timeout(Duration::from_millis(100), ucpd.wait_for_cc_change()) + if with_timeout(Duration::from_millis(100), ucpd.wait_for_cc_vstate_change()) .await .is_ok() { From 4d0e3838168a7447b3580135ef78d65baa578933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 7 Mar 2024 11:17:39 +0100 Subject: [PATCH 673/760] [UCPD] Prepare for PD communication implementation --- embassy-stm32/src/ucpd.rs | 47 +++++++++++++++++++++++++++- examples/stm32g4/src/bin/usb_c_pd.rs | 15 ++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index a366fadda..96cd92764 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -22,9 +22,10 @@ use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +use crate::dma::AnyChannel; use crate::interrupt; -pub use crate::pac::ucpd::vals::TypecVstateCc as CcVState; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk}; +pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; use crate::rcc::RccPeripheral; /// Pull-up or Pull-down resistor state of both CC lines. @@ -177,6 +178,50 @@ impl<'d, T: Instance> Ucpd<'d, T> { }) }); } + + /// Returns PD receiver and transmitter. + pub fn pd( + &mut self, + rx_dma: impl Peripheral

> + 'd, + tx_dma: impl Peripheral

> + 'd, + cc_sel: CcSel, + ) -> (PdRx<'_, T>, PdTx<'_, T>) { + into_ref!(rx_dma, tx_dma); + let rx_dma_req = rx_dma.request(); + let tx_dma_req = tx_dma.request(); + ( + PdRx { + _ucpd: self, + dma_ch: rx_dma.map_into(), + dma_req: rx_dma_req, + }, + PdTx { + _ucpd: self, + dma_ch: tx_dma.map_into(), + dma_req: tx_dma_req, + }, + ) + } +} + +/// Power Delivery (PD) Receiver. +pub struct PdRx<'d, T: Instance> { + _ucpd: &'d Ucpd<'d, T>, + dma_ch: PeripheralRef<'d, AnyChannel>, + dma_req: Request, +} + +impl<'d, T: Instance> Drop for PdRx<'d, T> { + fn drop(&mut self) { + T::REGS.cr().modify(|w| w.set_phyrxen(false)); + } +} + +/// Power Delivery (PD) Transmitter. +pub struct PdTx<'d, T: Instance> { + _ucpd: &'d Ucpd<'d, T>, + dma_ch: PeripheralRef<'d, AnyChannel>, + dma_req: Request, } /// Interrupt handler. diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 7a0065087..1443cb773 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -3,7 +3,7 @@ use defmt::{info, Format}; use embassy_executor::Spawner; -use embassy_stm32::ucpd::{self, CcPull, CcVState, Ucpd}; +use embassy_stm32::ucpd::{self, CcPull, CcSel, CcVState, Ucpd}; use embassy_stm32::Config; use embassy_time::{with_timeout, Duration}; use {defmt_rtt as _, panic_probe as _}; @@ -56,5 +56,18 @@ async fn main(_spawner: Spawner) { let cable_orientation = wait_attached(&mut ucpd).await; info!("USB cable connected, orientation: {}", cable_orientation); + let cc_sel = match cable_orientation { + CableOrientation::Normal => { + info!("Starting PD communication on CC1 pin"); + CcSel::CC1 + } + CableOrientation::Flipped => { + info!("Starting PD communication on CC2 pin"); + CcSel::CC2 + } + CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"), + }; + let (mut _rx, mut _tx) = ucpd.pd(p.DMA1_CH1, p.DMA1_CH2, cc_sel); + loop {} } From 984d5bbc720dfe9acf22400d2462c0ffce52a7cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 7 Mar 2024 16:36:47 +0100 Subject: [PATCH 674/760] [UCPD] Implement PD receiver --- embassy-stm32/src/ucpd.rs | 99 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 96cd92764..f3f225d0c 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -22,7 +22,7 @@ use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use crate::dma::AnyChannel; +use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; use crate::interrupt; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk}; pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; @@ -99,7 +99,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { // 1.75us * 17 = ~30us w.set_ifrgap(17 - 1); - // TODO: Only receive SOP messages + // TODO: Currently only SOP messages are supported. w.set_rxordseten(0x1); // Enable DMA and the peripheral @@ -186,6 +186,14 @@ impl<'d, T: Instance> Ucpd<'d, T> { tx_dma: impl Peripheral

> + 'd, cc_sel: CcSel, ) -> (PdRx<'_, T>, PdTx<'_, T>) { + let r = T::REGS; + + // Enable the receiver on one of the two CC lines. + r.cr().modify(|w| { + w.set_phyccsel(cc_sel); + w.set_phyrxen(true); + }); + into_ref!(rx_dma, tx_dma); let rx_dma_req = rx_dma.request(); let tx_dma_req = tx_dma.request(); @@ -204,6 +212,16 @@ impl<'d, T: Instance> Ucpd<'d, T> { } } +/// Receive Error. +#[derive(Debug, Clone, Copy)] +pub enum RxError { + /// Incorrect CRC or truncated message (a line becoming static before EOP is met). + Crc, + + /// Provided buffer was too small for the received message. + Overrun, +} + /// Power Delivery (PD) Receiver. pub struct PdRx<'d, T: Instance> { _ucpd: &'d Ucpd<'d, T>, @@ -217,6 +235,79 @@ impl<'d, T: Instance> Drop for PdRx<'d, T> { } } +impl<'d, T: Instance> PdRx<'d, T> { + /// Receives a PD message into the provided buffer. + /// + /// Returns the number of received bytes or an error. + pub async fn receive(&mut self, buf: &mut [u8]) -> Result { + let r = T::REGS; + + // Check if a message is already being received. If yes, wait until its + // done, ignore errors and try to receive the next message. + if r.sr().read().rxorddet() { + let _ = self.wait_rx_done().await; + r.rxdr().read(); // Clear the RX buffer. + } + + // Keep the DMA transfer alive so its drop code does not stop it right away. + let dma = unsafe { + // Disable the DMA complete interrupt because the end of packet is + // signaled by the UCPD receiver. When the DMA buffer is too short + // DMA stops by itself and the overrun RXOVR flag of UCPD is set. + let mut transfer_options = TransferOptions::default(); + transfer_options.complete_transfer_ir = false; + + Transfer::new_read( + &self.dma_ch, + self.dma_req, + r.rxdr().as_ptr() as *mut u8, + buf, + transfer_options, + ) + }; + + self.wait_rx_done().await?; + + // Make sure the the last byte to byte was fetched by DMA. + while r.sr().read().rxne() { + if dma.get_remaining_transfers() == 0 { + return Err(RxError::Overrun); + } + } + + Ok(r.rx_payszr().read().rxpaysz().into()) + } + + async fn wait_rx_done(&self) -> Result<(), RxError> { + poll_fn(|cx| { + let r = T::REGS; + let sr = r.sr().read(); + if sr.rxmsgend() { + let ret = if sr.rxovr() { + Err(RxError::Overrun) + } else if sr.rxerr() { + Err(RxError::Crc) + } else { + Ok(()) + }; + // Message received, clear interrupt flags. + r.icr().write(|w| { + w.set_rxorddetcf(true); + w.set_rxovrcf(true); + w.set_rxmsgendcf(true); + }); + Poll::Ready(ret) + } else { + // Enable receiver interrupt. + T::waker().register(cx.waker()); + r.imr().modify(|w| w.set_rxmsgendie(true)); + Poll::Pending + } + }) + .await + } +} + /// Power Delivery (PD) Transmitter. pub struct PdTx<'d, T: Instance> { _ucpd: &'d Ucpd<'d, T>, @@ -241,6 +332,10 @@ impl interrupt::typelevel::Handler for InterruptHandl }); } + if sr.rxmsgend() { + r.imr().modify(|w| w.set_rxmsgendie(false)); + } + // Wake the task to clear and re-enabled interrupts. T::waker().wake(); } From 36a99189210bf15c93198a4bf9a0d2ab732c8bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 7 Mar 2024 18:35:05 +0100 Subject: [PATCH 675/760] [UCPD] Implement PD transmitter --- embassy-stm32/src/ucpd.rs | 81 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index f3f225d0c..0a6f7df71 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -24,7 +24,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; use crate::interrupt; -use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk}; +use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; use crate::rcc::RccPeripheral; @@ -194,6 +194,9 @@ impl<'d, T: Instance> Ucpd<'d, T> { w.set_phyrxen(true); }); + // TODO: Currently only SOP messages are supported. + r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); + into_ref!(rx_dma, tx_dma); let rx_dma_req = rx_dma.request(); let tx_dma_req = tx_dma.request(); @@ -308,6 +311,13 @@ impl<'d, T: Instance> PdRx<'d, T> { } } +/// Transmit Error. +#[derive(Debug, Clone, Copy)] +pub enum TxError { + /// Concurrent receive in progress or excessive noise on the line. + Discarded, +} + /// Power Delivery (PD) Transmitter. pub struct PdTx<'d, T: Instance> { _ucpd: &'d Ucpd<'d, T>, @@ -315,6 +325,68 @@ pub struct PdTx<'d, T: Instance> { dma_req: Request, } +impl<'d, T: Instance> PdTx<'d, T> { + /// Transmits a PD message. + pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), TxError> { + let r = T::REGS; + + // When a previous transmission was dropped before it had finished it + // might still be running because there is no way to abort an ongoing + // message transmission. Wait for it to finish but ignore errors. + if r.cr().read().txsend() { + let _ = self.wait_tx_done().await; + } + + // Clear the TX interrupt flags. + T::REGS.icr().write(|w| { + w.set_txmsgdisccf(true); + w.set_txmsgsentcf(true); + }); + + // Start the DMA and let it do its thing in the background. + let _dma = unsafe { + Transfer::new_write( + &self.dma_ch, + self.dma_req, + buf, + r.txdr().as_ptr() as *mut u8, + TransferOptions::default(), + ) + }; + + // Configure and start the transmission. + r.tx_payszr().write(|w| w.set_txpaysz(buf.len() as _)); + r.cr().modify(|w| { + w.set_txmode(Txmode::PACKET); + w.set_txsend(true); + }); + + self.wait_tx_done().await + } + + async fn wait_tx_done(&self) -> Result<(), TxError> { + poll_fn(|cx| { + let r = T::REGS; + if r.sr().read().txmsgdisc() { + Poll::Ready(Err(TxError::Discarded)) + } else if r.sr().read().txmsgsent() { + Poll::Ready(Ok(())) + } else { + // Enable transmit interrupts. + T::waker().register(cx.waker()); + r.imr().modify(|w| { + w.set_txmsgdiscie(true); + w.set_txmsgsentie(true); + }); + Poll::Pending + } + }) + .await + } + + fn clear_tx_flags(&self) {} +} + /// Interrupt handler. pub struct InterruptHandler { _phantom: PhantomData, @@ -336,6 +408,13 @@ impl interrupt::typelevel::Handler for InterruptHandl r.imr().modify(|w| w.set_rxmsgendie(false)); } + if sr.txmsgdisc() || sr.txmsgsent() { + r.imr().modify(|w| { + w.set_txmsgdiscie(false); + w.set_txmsgsentie(false); + }); + } + // Wake the task to clear and re-enabled interrupts. T::waker().wake(); } From 5e271ff31b55b339d4321af4b2c8a096bf153d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 7 Mar 2024 19:47:13 +0100 Subject: [PATCH 676/760] [UCPD] Combine RX and TX `select(rx.receive(), tx.transmit()` had subtle interrupt enable race conditions. Combine receiver and transmitter into one new `PdPhy` struct to disallow the problematic pattern. Scanning through the USB PD 2.0 specification there is no need to have RX and TX running concurrently (after all the USB PD communication is half-duplex). --- embassy-stm32/src/ucpd.rs | 127 +++++++++++++-------------- examples/stm32g4/src/bin/usb_c_pd.rs | 2 +- 2 files changed, 60 insertions(+), 69 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 0a6f7df71..02c81c2b6 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -57,11 +57,7 @@ pub struct Ucpd<'d, T: Instance> { impl<'d, T: Instance> Drop for Ucpd<'d, T> { fn drop(&mut self) { - T::REGS.cr().modify(|w| { - w.set_ccenable(Ccenable::DISABLED); - w.set_cc1tcdis(true); - w.set_cc2tcdis(true); - }); + T::REGS.cfgr1().write(|w| w.set_ucpden(false)); } } @@ -99,12 +95,6 @@ impl<'d, T: Instance> Ucpd<'d, T> { // 1.75us * 17 = ~30us w.set_ifrgap(17 - 1); - // TODO: Currently only SOP messages are supported. - w.set_rxordseten(0x1); - - // Enable DMA and the peripheral - w.set_txdmaen(true); - w.set_rxdmaen(true); w.set_ucpden(true); }); @@ -155,7 +145,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { /// Waits for a change in voltage state on either CC line. pub async fn wait_for_cc_vstate_change(&self) -> (CcVState, CcVState) { - let _on_drop = OnDrop::new(|| critical_section::with(|_| self.enable_cc_interrupts(false))); + let _on_drop = OnDrop::new(|| self.enable_cc_interrupts(false)); let prev_vstate = self.cc_vstate(); poll_fn(|cx| { let vstate = self.cc_vstate(); @@ -171,47 +161,49 @@ impl<'d, T: Instance> Ucpd<'d, T> { } fn enable_cc_interrupts(&self, enable: bool) { - critical_section::with(|_| { - T::REGS.imr().modify(|w| { - w.set_typecevt1ie(enable); - w.set_typecevt2ie(enable); - }) + T::REGS.imr().modify(|w| { + w.set_typecevt1ie(enable); + w.set_typecevt2ie(enable); }); } /// Returns PD receiver and transmitter. - pub fn pd( + pub fn pd_phy( &mut self, rx_dma: impl Peripheral

> + 'd, tx_dma: impl Peripheral

> + 'd, cc_sel: CcSel, - ) -> (PdRx<'_, T>, PdTx<'_, T>) { + ) -> PdPhy<'_, T> { let r = T::REGS; + // TODO: Currently only SOP messages are supported. + r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); + + r.cfgr1().modify(|w| { + // TODO: Currently only SOP messages are supported. + w.set_rxordseten(0x1); + + // Enable DMA + w.set_txdmaen(true); + w.set_rxdmaen(true); + }); + // Enable the receiver on one of the two CC lines. r.cr().modify(|w| { w.set_phyccsel(cc_sel); w.set_phyrxen(true); }); - // TODO: Currently only SOP messages are supported. - r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); - into_ref!(rx_dma, tx_dma); let rx_dma_req = rx_dma.request(); let tx_dma_req = tx_dma.request(); - ( - PdRx { - _ucpd: self, - dma_ch: rx_dma.map_into(), - dma_req: rx_dma_req, - }, - PdTx { - _ucpd: self, - dma_ch: tx_dma.map_into(), - dma_req: tx_dma_req, - }, - ) + PdPhy { + _ucpd: self, + rx_dma_ch: rx_dma.map_into(), + rx_dma_req, + tx_dma_ch: tx_dma.map_into(), + tx_dma_req, + } } } @@ -225,20 +217,29 @@ pub enum RxError { Overrun, } -/// Power Delivery (PD) Receiver. -pub struct PdRx<'d, T: Instance> { - _ucpd: &'d Ucpd<'d, T>, - dma_ch: PeripheralRef<'d, AnyChannel>, - dma_req: Request, +/// Transmit Error. +#[derive(Debug, Clone, Copy)] +pub enum TxError { + /// Concurrent receive in progress or excessive noise on the line. + Discarded, } -impl<'d, T: Instance> Drop for PdRx<'d, T> { +/// Power Delivery (PD) PHY. +pub struct PdPhy<'d, T: Instance> { + _ucpd: &'d Ucpd<'d, T>, + rx_dma_ch: PeripheralRef<'d, AnyChannel>, + rx_dma_req: Request, + tx_dma_ch: PeripheralRef<'d, AnyChannel>, + tx_dma_req: Request, +} + +impl<'d, T: Instance> Drop for PdPhy<'d, T> { fn drop(&mut self) { T::REGS.cr().modify(|w| w.set_phyrxen(false)); } } -impl<'d, T: Instance> PdRx<'d, T> { +impl<'d, T: Instance> PdPhy<'d, T> { /// Receives a PD message into the provided buffer. /// /// Returns the number of received bytes or an error. @@ -261,8 +262,8 @@ impl<'d, T: Instance> PdRx<'d, T> { transfer_options.complete_transfer_ir = false; Transfer::new_read( - &self.dma_ch, - self.dma_req, + &self.rx_dma_ch, + self.rx_dma_req, r.rxdr().as_ptr() as *mut u8, buf, transfer_options, @@ -282,6 +283,7 @@ impl<'d, T: Instance> PdRx<'d, T> { } async fn wait_rx_done(&self) -> Result<(), RxError> { + let _on_drop = OnDrop::new(|| self.enable_rx_interrupt(false)); poll_fn(|cx| { let r = T::REGS; let sr = r.sr().read(); @@ -301,31 +303,18 @@ impl<'d, T: Instance> PdRx<'d, T> { }); Poll::Ready(ret) } else { - // Enable receiver interrupt. T::waker().register(cx.waker()); - r.imr().modify(|w| w.set_rxmsgendie(true)); + self.enable_rx_interrupt(true); Poll::Pending } }) .await } -} -/// Transmit Error. -#[derive(Debug, Clone, Copy)] -pub enum TxError { - /// Concurrent receive in progress or excessive noise on the line. - Discarded, -} + fn enable_rx_interrupt(&self, enable: bool) { + T::REGS.imr().modify(|w| w.set_rxmsgendie(enable)); + } -/// Power Delivery (PD) Transmitter. -pub struct PdTx<'d, T: Instance> { - _ucpd: &'d Ucpd<'d, T>, - dma_ch: PeripheralRef<'d, AnyChannel>, - dma_req: Request, -} - -impl<'d, T: Instance> PdTx<'d, T> { /// Transmits a PD message. pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), TxError> { let r = T::REGS; @@ -346,8 +335,8 @@ impl<'d, T: Instance> PdTx<'d, T> { // Start the DMA and let it do its thing in the background. let _dma = unsafe { Transfer::new_write( - &self.dma_ch, - self.dma_req, + &self.tx_dma_ch, + self.tx_dma_req, buf, r.txdr().as_ptr() as *mut u8, TransferOptions::default(), @@ -365,6 +354,7 @@ impl<'d, T: Instance> PdTx<'d, T> { } async fn wait_tx_done(&self) -> Result<(), TxError> { + let _on_drop = OnDrop::new(|| self.enable_tx_interrupts(false)); poll_fn(|cx| { let r = T::REGS; if r.sr().read().txmsgdisc() { @@ -372,19 +362,20 @@ impl<'d, T: Instance> PdTx<'d, T> { } else if r.sr().read().txmsgsent() { Poll::Ready(Ok(())) } else { - // Enable transmit interrupts. T::waker().register(cx.waker()); - r.imr().modify(|w| { - w.set_txmsgdiscie(true); - w.set_txmsgsentie(true); - }); + self.enable_tx_interrupts(true); Poll::Pending } }) .await } - fn clear_tx_flags(&self) {} + fn enable_tx_interrupts(&self, enable: bool) { + T::REGS.imr().modify(|w| { + w.set_txmsgdiscie(enable); + w.set_txmsgsentie(enable); + }); + } } /// Interrupt handler. diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 1443cb773..fd2400bd5 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) { } CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"), }; - let (mut _rx, mut _tx) = ucpd.pd(p.DMA1_CH1, p.DMA1_CH2, cc_sel); + let mut pd_phy = ucpd.pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel); loop {} } From b7972048a1642679392b2a1dfc976881205fd23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 7 Mar 2024 19:54:55 +0100 Subject: [PATCH 677/760] [UCPD] Improve example and defmt Format for enums --- embassy-stm32/src/ucpd.rs | 3 +++ examples/stm32g4/src/bin/usb_c_pd.rs | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 02c81c2b6..071bfd1b1 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -30,6 +30,7 @@ use crate::rcc::RccPeripheral; /// Pull-up or Pull-down resistor state of both CC lines. #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CcPull { /// Analog PHY for CC pin disabled. Disabled, @@ -209,6 +210,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { /// Receive Error. #[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RxError { /// Incorrect CRC or truncated message (a line becoming static before EOP is met). Crc, @@ -219,6 +221,7 @@ pub enum RxError { /// Transmit Error. #[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum TxError { /// Concurrent receive in progress or excessive noise on the line. Discarded, diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index fd2400bd5..14abd542f 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use defmt::{info, Format}; +use defmt::{error, info, Format}; use embassy_executor::Spawner; use embassy_stm32::ucpd::{self, CcPull, CcSel, CcVState, Ucpd}; use embassy_stm32::Config; @@ -69,5 +69,12 @@ async fn main(_spawner: Spawner) { }; let mut pd_phy = ucpd.pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel); - loop {} + loop { + // Enough space for the longest non-extended data message. + let mut buf = [0_u8; 30]; + match pd_phy.receive(buf.as_mut()).await { + Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]), + Err(e) => error!("USB PD RX: {}", e), + } + } } From c1efcbba2dc472948b294b474a9a1970f88cd96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Fri, 8 Mar 2024 15:01:55 +0100 Subject: [PATCH 678/760] [UCPD] Receive hard resets --- embassy-stm32/src/ucpd.rs | 42 ++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 071bfd1b1..64969beb8 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -181,8 +181,8 @@ impl<'d, T: Instance> Ucpd<'d, T> { r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); r.cfgr1().modify(|w| { - // TODO: Currently only SOP messages are supported. - w.set_rxordseten(0x1); + // TODO: Currently only hard reset and SOP messages can be received. + w.set_rxordseten(0b1001); // Enable DMA w.set_txdmaen(true); @@ -195,6 +195,9 @@ impl<'d, T: Instance> Ucpd<'d, T> { w.set_phyrxen(true); }); + // Enable hard reset receive interrupt. + r.imr().modify(|w| w.set_rxhrstdetie(true)); + into_ref!(rx_dma, tx_dma); let rx_dma_req = rx_dma.request(); let tx_dma_req = tx_dma.request(); @@ -217,6 +220,9 @@ pub enum RxError { /// Provided buffer was too small for the received message. Overrun, + + /// Hard Reset received before or during reception. + HardReset, } /// Transmit Error. @@ -225,6 +231,9 @@ pub enum RxError { pub enum TxError { /// Concurrent receive in progress or excessive noise on the line. Discarded, + + /// Hard Reset received before or during transmission. + HardReset, } /// Power Delivery (PD) PHY. @@ -252,7 +261,9 @@ impl<'d, T: Instance> PdPhy<'d, T> { // Check if a message is already being received. If yes, wait until its // done, ignore errors and try to receive the next message. if r.sr().read().rxorddet() { - let _ = self.wait_rx_done().await; + if let Err(RxError::HardReset) = self.wait_rx_done().await { + return Err(RxError::HardReset); + } r.rxdr().read(); // Clear the RX buffer. } @@ -290,7 +301,12 @@ impl<'d, T: Instance> PdPhy<'d, T> { poll_fn(|cx| { let r = T::REGS; let sr = r.sr().read(); - if sr.rxmsgend() { + if sr.rxhrstdet() { + // Clean and re-enable hard reset receive interrupt. + r.icr().write(|w| w.set_rxhrstdetcf(true)); + r.imr().modify(|w| w.set_rxhrstdetie(true)); + Poll::Ready(Err(RxError::HardReset)) + } else if sr.rxmsgend() { let ret = if sr.rxovr() { Err(RxError::Overrun) } else if sr.rxerr() { @@ -326,7 +342,9 @@ impl<'d, T: Instance> PdPhy<'d, T> { // might still be running because there is no way to abort an ongoing // message transmission. Wait for it to finish but ignore errors. if r.cr().read().txsend() { - let _ = self.wait_tx_done().await; + if let Err(TxError::HardReset) = self.wait_tx_done().await { + return Err(TxError::HardReset); + } } // Clear the TX interrupt flags. @@ -360,9 +378,15 @@ impl<'d, T: Instance> PdPhy<'d, T> { let _on_drop = OnDrop::new(|| self.enable_tx_interrupts(false)); poll_fn(|cx| { let r = T::REGS; - if r.sr().read().txmsgdisc() { + let sr = r.sr().read(); + if sr.rxhrstdet() { + // Clean and re-enable hard reset receive interrupt. + r.icr().write(|w| w.set_rxhrstdetcf(true)); + r.imr().modify(|w| w.set_rxhrstdetie(true)); + Poll::Ready(Err(TxError::HardReset)) + } else if sr.txmsgdisc() { Poll::Ready(Err(TxError::Discarded)) - } else if r.sr().read().txmsgsent() { + } else if sr.txmsgsent() { Poll::Ready(Ok(())) } else { T::waker().register(cx.waker()); @@ -398,6 +422,10 @@ impl interrupt::typelevel::Handler for InterruptHandl }); } + if sr.rxhrstdet() { + r.imr().modify(|w| w.set_rxhrstdetie(false)); + } + if sr.rxmsgend() { r.imr().modify(|w| w.set_rxmsgendie(false)); } From ff8129a6a6845186bac92c6b6fcfefa03a7a7d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Fri, 8 Mar 2024 15:15:55 +0100 Subject: [PATCH 679/760] [UCPD] Implement hard reset transmission --- embassy-stm32/src/ucpd.rs | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 64969beb8..05a61634a 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -403,6 +403,50 @@ impl<'d, T: Instance> PdPhy<'d, T> { w.set_txmsgsentie(enable); }); } + + /// Transmit a hard reset. + pub async fn transmit_hardreset(&mut self) -> Result<(), TxError> { + let r = T::REGS; + + // Clear the hardreset interrupt flags. + T::REGS.icr().write(|w| { + w.set_txmsgdisccf(true); + w.set_txmsgsentcf(true); + }); + + // Trigger hard reset transmission. + r.cr().modify(|w| { + w.set_txhrst(true); + }); + + let _on_drop = OnDrop::new(|| self.enable_hardreset_interrupts(false)); + poll_fn(|cx| { + let r = T::REGS; + let sr = r.sr().read(); + if sr.rxhrstdet() { + // Clean and re-enable hard reset receive interrupt. + r.icr().write(|w| w.set_rxhrstdetcf(true)); + r.imr().modify(|w| w.set_rxhrstdetie(true)); + Poll::Ready(Err(TxError::HardReset)) + } else if sr.hrstdisc() { + Poll::Ready(Err(TxError::Discarded)) + } else if sr.hrstsent() { + Poll::Ready(Ok(())) + } else { + T::waker().register(cx.waker()); + self.enable_hardreset_interrupts(true); + Poll::Pending + } + }) + .await + } + + fn enable_hardreset_interrupts(&self, enable: bool) { + T::REGS.imr().modify(|w| { + w.set_hrstdiscie(enable); + w.set_hrstsentie(enable); + }); + } } /// Interrupt handler. @@ -437,6 +481,13 @@ impl interrupt::typelevel::Handler for InterruptHandl }); } + if sr.hrstdisc() || sr.hrstsent() { + r.imr().modify(|w| { + w.set_hrstdiscie(false); + w.set_hrstsentie(false); + }); + } + // Wake the task to clear and re-enabled interrupts. T::waker().wake(); } From 99854ff840fdd12d7562923f6a9ef2d39e1c9f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Fri, 8 Mar 2024 19:26:49 +0100 Subject: [PATCH 680/760] [UCPD] Fix build for devices with GPDMA Do not use a flag that is DMA/BDMA only, not required anyway the transfer should run in the background nevertheless --- embassy-stm32/src/ucpd.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 05a61634a..d1b793e26 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -269,18 +269,12 @@ impl<'d, T: Instance> PdPhy<'d, T> { // Keep the DMA transfer alive so its drop code does not stop it right away. let dma = unsafe { - // Disable the DMA complete interrupt because the end of packet is - // signaled by the UCPD receiver. When the DMA buffer is too short - // DMA stops by itself and the overrun RXOVR flag of UCPD is set. - let mut transfer_options = TransferOptions::default(); - transfer_options.complete_transfer_ir = false; - Transfer::new_read( &self.rx_dma_ch, self.rx_dma_req, r.rxdr().as_ptr() as *mut u8, buf, - transfer_options, + TransferOptions::default(), ) }; From 89504f51629d0ab81070db91c3eb5b96b1e41fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Fri, 8 Mar 2024 20:36:37 +0100 Subject: [PATCH 681/760] [UCPD] Split into CC and PD phy PD3.0 spec requires concurrent control of CC resistors for collision avoidance. Needed to introduce some "ref counting" (its just a bool) for drop code. --- embassy-stm32/src/ucpd.rs | 251 +++++++++++++++++---------- examples/stm32g4/src/bin/usb_c_pd.rs | 17 +- 2 files changed, 164 insertions(+), 104 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index d1b793e26..2120716ef 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -16,11 +16,11 @@ use core::future::poll_fn; use core::marker::PhantomData; +use core::sync::atomic::Ordering; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; use crate::interrupt; @@ -53,22 +53,15 @@ pub enum CcPull { /// UCPD driver. pub struct Ucpd<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, -} - -impl<'d, T: Instance> Drop for Ucpd<'d, T> { - fn drop(&mut self) { - T::REGS.cfgr1().write(|w| w.set_ucpden(false)); - } + cc_phy: CcPhy<'d, T>, } impl<'d, T: Instance> Ucpd<'d, T> { /// Creates a new UCPD driver instance. pub fn new( - peri: impl Peripheral

+ 'd, + _peri: impl Peripheral

+ 'd, _cc1: impl Peripheral

> + 'd, _cc2: impl Peripheral

> + 'd, - cc_pull: CcPull, ) -> Self { T::enable_and_reset(); @@ -99,82 +92,24 @@ impl<'d, T: Instance> Ucpd<'d, T> { w.set_ucpden(true); }); - r.cr().write(|w| { - w.set_anamode(if cc_pull == CcPull::Sink { - Anamode::SINK - } else { - Anamode::SOURCE - }); - w.set_anasubmode(match cc_pull { - CcPull::SourceDefaultUsb => 1, - CcPull::Source1_5A => 2, - CcPull::Source3_0A => 3, - _ => 0, - }); - w.set_ccenable(if cc_pull != CcPull::SinkDeadBattery { - Ccenable::BOTH - } else { - Ccenable::DISABLED - }); - - // Make sure detector is enabled on both pins. - w.set_cc1tcdis(false); - w.set_cc2tcdis(false); - }); - - // Disable dead-battery pull-down resistors which are enabled by default on boot. - critical_section::with(|_| { - // TODO: other families - #[cfg(stm32g4)] - crate::pac::PWR - .cr3() - .modify(|w| w.set_ucpd1_dbdis(cc_pull != CcPull::SinkDeadBattery)); - }); - - into_ref!(peri); - Self { _peri: peri } + Self { + cc_phy: CcPhy { _lifetime: PhantomData }, + } } - /// Returns the current voltage level of CC1 and CC2 pin as tuple. - /// - /// Interpretation of the voltage levels depends on the configured CC line - /// pull-up/pull-down resistance. - pub fn cc_vstate(&self) -> (CcVState, CcVState) { - let sr = T::REGS.sr().read(); - (sr.typec_vstate_cc1(), sr.typec_vstate_cc2()) + /// Returns the TypeC CC PHY. + pub fn cc_phy(&mut self) -> &mut CcPhy<'d, T> { + &mut self.cc_phy } - /// Waits for a change in voltage state on either CC line. - pub async fn wait_for_cc_vstate_change(&self) -> (CcVState, CcVState) { - let _on_drop = OnDrop::new(|| self.enable_cc_interrupts(false)); - let prev_vstate = self.cc_vstate(); - poll_fn(|cx| { - let vstate = self.cc_vstate(); - if vstate != prev_vstate { - Poll::Ready(vstate) - } else { - T::waker().register(cx.waker()); - self.enable_cc_interrupts(true); - Poll::Pending - } - }) - .await - } - - fn enable_cc_interrupts(&self, enable: bool) { - T::REGS.imr().modify(|w| { - w.set_typecevt1ie(enable); - w.set_typecevt2ie(enable); - }); - } - - /// Returns PD receiver and transmitter. - pub fn pd_phy( - &mut self, + /// Splits the UCPD driver into a TypeC PHY to control and monitor CC voltage + /// and a Power Delivery (PD) PHY with receiver and transmitter. + pub fn split_pd_phy( + self, rx_dma: impl Peripheral

> + 'd, tx_dma: impl Peripheral

> + 'd, cc_sel: CcSel, - ) -> PdPhy<'_, T> { + ) -> (CcPhy<'d, T>, PdPhy<'d, T>) { let r = T::REGS; // TODO: Currently only SOP messages are supported. @@ -198,19 +133,115 @@ impl<'d, T: Instance> Ucpd<'d, T> { // Enable hard reset receive interrupt. r.imr().modify(|w| w.set_rxhrstdetie(true)); + // Both parts must be dropped before the peripheral can be disabled. + T::state().drop_not_ready.store(true, Ordering::Relaxed); + into_ref!(rx_dma, tx_dma); let rx_dma_req = rx_dma.request(); let tx_dma_req = tx_dma.request(); - PdPhy { - _ucpd: self, - rx_dma_ch: rx_dma.map_into(), - rx_dma_req, - tx_dma_ch: tx_dma.map_into(), - tx_dma_req, + ( + self.cc_phy, + PdPhy { + _lifetime: PhantomData, + rx_dma_ch: rx_dma.map_into(), + rx_dma_req, + tx_dma_ch: tx_dma.map_into(), + tx_dma_req, + }, + ) + } +} + +/// Control and monitoring of TypeC CC pin functionailty. +pub struct CcPhy<'d, T: Instance> { + _lifetime: PhantomData<&'d mut T>, +} + +impl<'d, T: Instance> Drop for CcPhy<'d, T> { + fn drop(&mut self) { + let r = T::REGS; + r.cr().modify(|w| { + w.set_cc1tcdis(true); + w.set_cc2tcdis(true); + w.set_ccenable(Ccenable::DISABLED); + }); + + // Check if the PdPhy part was dropped already. + let drop_not_ready = &T::state().drop_not_ready; + if drop_not_ready.load(Ordering::Relaxed) { + drop_not_ready.store(true, Ordering::Relaxed); + } else { + r.cfgr1().write(|w| w.set_ucpden(false)); } } } +impl<'d, T: Instance> CcPhy<'d, T> { + /// Sets the pull-up/pull-down resistor values exposed on the CC pins. + pub fn set_pull(&mut self, cc_pull: CcPull) { + T::REGS.cr().write(|w| { + w.set_anamode(if cc_pull == CcPull::Sink { + Anamode::SINK + } else { + Anamode::SOURCE + }); + w.set_anasubmode(match cc_pull { + CcPull::SourceDefaultUsb => 1, + CcPull::Source1_5A => 2, + CcPull::Source3_0A => 3, + _ => 0, + }); + w.set_ccenable(if cc_pull != CcPull::SinkDeadBattery { + Ccenable::BOTH + } else { + Ccenable::DISABLED + }); + }); + + // Disable dead-battery pull-down resistors which are enabled by default on boot. + critical_section::with(|_| { + // TODO: other families + #[cfg(stm32g4)] + crate::pac::PWR + .cr3() + .modify(|w| w.set_ucpd1_dbdis(cc_pull != CcPull::SinkDeadBattery)); + }); + } + + /// Returns the current voltage level of CC1 and CC2 pin as tuple. + /// + /// Interpretation of the voltage levels depends on the configured CC line + /// pull-up/pull-down resistance. + pub fn vstate(&self) -> (CcVState, CcVState) { + let sr = T::REGS.sr().read(); + (sr.typec_vstate_cc1(), sr.typec_vstate_cc2()) + } + + /// Waits for a change in voltage state on either CC line. + pub async fn wait_for_vstate_change(&self) -> (CcVState, CcVState) { + let _on_drop = OnDrop::new(|| self.enable_cc_interrupts(false)); + let prev_vstate = self.vstate(); + poll_fn(|cx| { + let vstate = self.vstate(); + if vstate != prev_vstate { + Poll::Ready(vstate) + } else { + T::state().waker.register(cx.waker()); + self.enable_cc_interrupts(true); + Poll::Pending + } + }) + .await + } + + fn enable_cc_interrupts(&self, enable: bool) { + T::REGS.imr().modify(|w| { + w.set_typecevt1ie(enable); + w.set_typecevt2ie(enable); + }); + } +} + /// Receive Error. #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -238,7 +269,7 @@ pub enum TxError { /// Power Delivery (PD) PHY. pub struct PdPhy<'d, T: Instance> { - _ucpd: &'d Ucpd<'d, T>, + _lifetime: PhantomData<&'d mut T>, rx_dma_ch: PeripheralRef<'d, AnyChannel>, rx_dma_req: Request, tx_dma_ch: PeripheralRef<'d, AnyChannel>, @@ -247,7 +278,16 @@ pub struct PdPhy<'d, T: Instance> { impl<'d, T: Instance> Drop for PdPhy<'d, T> { fn drop(&mut self) { - T::REGS.cr().modify(|w| w.set_phyrxen(false)); + let r = T::REGS; + r.cr().modify(|w| w.set_phyrxen(false)); + + // Check if the Type-C part was dropped already. + let drop_not_ready = &T::state().drop_not_ready; + if drop_not_ready.load(Ordering::Relaxed) { + drop_not_ready.store(true, Ordering::Relaxed); + } else { + r.cfgr1().write(|w| w.set_ucpden(false)); + } } } @@ -316,7 +356,7 @@ impl<'d, T: Instance> PdPhy<'d, T> { }); Poll::Ready(ret) } else { - T::waker().register(cx.waker()); + T::state().waker.register(cx.waker()); self.enable_rx_interrupt(true); Poll::Pending } @@ -383,7 +423,7 @@ impl<'d, T: Instance> PdPhy<'d, T> { } else if sr.txmsgsent() { Poll::Ready(Ok(())) } else { - T::waker().register(cx.waker()); + T::state().waker.register(cx.waker()); self.enable_tx_interrupts(true); Poll::Pending } @@ -427,7 +467,7 @@ impl<'d, T: Instance> PdPhy<'d, T> { } else if sr.hrstsent() { Poll::Ready(Ok(())) } else { - T::waker().register(cx.waker()); + T::state().waker.register(cx.waker()); self.enable_hardreset_interrupts(true); Poll::Pending } @@ -483,18 +523,37 @@ impl interrupt::typelevel::Handler for InterruptHandl } // Wake the task to clear and re-enabled interrupts. - T::waker().wake(); + T::state().waker.wake(); } } /// UCPD instance trait. pub trait Instance: sealed::Instance + RccPeripheral {} -pub(crate) mod sealed { +mod sealed { + use core::sync::atomic::AtomicBool; + + use embassy_sync::waitqueue::AtomicWaker; + + pub struct State { + pub waker: AtomicWaker, + // Inverted logic for a default state of 0 so that the data goes into the .bss section. + pub drop_not_ready: AtomicBool, + } + + impl State { + pub const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + drop_not_ready: AtomicBool::new(false), + } + } + } + pub trait Instance { type Interrupt: crate::interrupt::typelevel::Interrupt; const REGS: crate::pac::ucpd::Ucpd; - fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker; + fn state() -> &'static crate::ucpd::sealed::State; } } @@ -505,9 +564,9 @@ foreach_interrupt!( const REGS: crate::pac::ucpd::Ucpd = crate::pac::$inst; - fn waker() -> &'static AtomicWaker { - static WAKER: AtomicWaker = AtomicWaker::new(); - &WAKER + fn state() -> &'static crate::ucpd::sealed::State { + static STATE: crate::ucpd::sealed::State = crate::ucpd::sealed::State::new(); + &STATE } } diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 14abd542f..0e80840df 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -3,7 +3,7 @@ use defmt::{error, info, Format}; use embassy_executor::Spawner; -use embassy_stm32::ucpd::{self, CcPull, CcSel, CcVState, Ucpd}; +use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; use embassy_stm32::Config; use embassy_time::{with_timeout, Duration}; use {defmt_rtt as _, panic_probe as _}; @@ -16,17 +16,17 @@ enum CableOrientation { } // Returns true when the cable -async fn wait_attached(ucpd: &mut Ucpd<'_, T>) -> CableOrientation { +async fn wait_attached(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation { loop { - let (cc1, cc2) = ucpd.cc_vstate(); + let (cc1, cc2) = cc_phy.vstate(); if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST { // Detached, wait until attached by monitoring the CC lines. - ucpd.wait_for_cc_vstate_change().await; + cc_phy.wait_for_vstate_change().await; continue; } // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms). - if with_timeout(Duration::from_millis(100), ucpd.wait_for_cc_vstate_change()) + if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change()) .await .is_ok() { @@ -50,10 +50,11 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let mut ucpd = Ucpd::new(p.UCPD1, p.PB6, p.PB4, CcPull::Sink); + let mut ucpd = Ucpd::new(p.UCPD1, p.PB6, p.PB4); + ucpd.cc_phy().set_pull(CcPull::Sink); info!("Waiting for USB connection..."); - let cable_orientation = wait_attached(&mut ucpd).await; + let cable_orientation = wait_attached(ucpd.cc_phy()).await; info!("USB cable connected, orientation: {}", cable_orientation); let cc_sel = match cable_orientation { @@ -67,7 +68,7 @@ async fn main(_spawner: Spawner) { } CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"), }; - let mut pd_phy = ucpd.pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel); + let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel); loop { // Enough space for the longest non-extended data message. From eeb033caf06cbb3a1bc2d6804524097c61c6c793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Sat, 9 Mar 2024 15:52:20 +0100 Subject: [PATCH 682/760] [UCPD] Disable RCC clock on drop --- embassy-stm32/src/ucpd.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 2120716ef..4b8124554 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -172,6 +172,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> { drop_not_ready.store(true, Ordering::Relaxed); } else { r.cfgr1().write(|w| w.set_ucpden(false)); + T::disable(); } } } @@ -287,6 +288,7 @@ impl<'d, T: Instance> Drop for PdPhy<'d, T> { drop_not_ready.store(true, Ordering::Relaxed); } else { r.cfgr1().write(|w| w.set_ucpden(false)); + T::disable(); } } } From 30cdc6c9c53837e91f92d24e9861b525f54bc65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Tue, 12 Mar 2024 08:47:08 +0100 Subject: [PATCH 683/760] [UCPD] Disable dead-battery resistor for all families Using the code from PR #2683, thank you @ExplodingWaffle Removes the dead-battery as selectable option because its unclear if it can be re-enabled. Also there is no use case for it because the same resistor can be configured with the sink option. --- embassy-stm32/src/lib.rs | 41 +-------------------------- embassy-stm32/src/ucpd.rs | 58 +++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 361dc6f53..b38b5c29d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -283,9 +283,8 @@ pub fn init(config: Config) -> Peripherals { } unsafe { - // TODO: refactor into mod ucpd #[cfg(ucpd)] - ucpd_init( + ucpd::init( cs, #[cfg(peri_ucpd1)] config.enable_ucpd1_dead_battery, @@ -334,41 +333,3 @@ pub fn init(config: Config) -> Peripherals { p }) } - -#[cfg(ucpd)] -/// Safety: must only be called when all UCPDs are disabled (e.g. at startup) -unsafe fn ucpd_init( - _cs: critical_section::CriticalSection, - #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, - #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, -) { - #[cfg(stm32g0x1)] - { - // according to RM0444 (STM32G0x1) section 8.1.1: - // when UCPD is disabled setting the strobe will disable dead battery - // (which is enabled after reset) but if UCPD is enabled, setting the - // strobe will apply the CC pin configuration from the control register - // (which is why we need to be careful about when we call this) - crate::pac::SYSCFG.cfgr1().modify(|w| { - w.set_ucpd1_strobe(ucpd1_db_enable); - w.set_ucpd2_strobe(ucpd2_db_enable); - }); - } - - #[cfg(any(stm32g4, stm32l5))] - { - crate::pac::PWR.cr3().modify(|w| { - #[cfg(stm32g4)] - w.set_ucpd1_dbdis(!ucpd1_db_enable); - #[cfg(stm32l5)] - w.set_ucpd_dbdis(!ucpd1_db_enable); - }) - } - - #[cfg(any(stm32h5, stm32u5))] - { - crate::pac::PWR.ucpdr().modify(|w| { - w.set_ucpd_dbdis(!ucpd1_db_enable); - }) - } -} diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 4b8124554..51cfe4a24 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -28,6 +28,42 @@ use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; use crate::rcc::RccPeripheral; +pub(crate) fn init( + _cs: critical_section::CriticalSection, + #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, + #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, +) { + #[cfg(stm32g0x1)] + { + // according to RM0444 (STM32G0x1) section 8.1.1: + // when UCPD is disabled setting the strobe will disable dead battery + // (which is enabled after reset) but if UCPD is enabled, setting the + // strobe will apply the CC pin configuration from the control register + // (which is why we need to be careful about when we call this) + crate::pac::SYSCFG.cfgr1().modify(|w| { + w.set_ucpd1_strobe(ucpd1_db_enable); + w.set_ucpd2_strobe(ucpd2_db_enable); + }); + } + + #[cfg(any(stm32g4, stm32l5))] + { + crate::pac::PWR.cr3().modify(|w| { + #[cfg(stm32g4)] + w.set_ucpd1_dbdis(!ucpd1_db_enable); + #[cfg(stm32l5)] + w.set_ucpd_dbdis(!ucpd1_db_enable); + }) + } + + #[cfg(any(stm32h5, stm32u5))] + { + crate::pac::PWR.ucpdr().modify(|w| { + w.set_ucpd_dbdis(!ucpd1_db_enable); + }) + } +} + /// Pull-up or Pull-down resistor state of both CC lines. #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -35,9 +71,6 @@ pub enum CcPull { /// Analog PHY for CC pin disabled. Disabled, - /// Rd=5.1k pull-down resistor enabled when the corresponding DBCC pin is high. - SinkDeadBattery, - /// Rd=5.1k pull-down resistor. Sink, @@ -192,20 +225,21 @@ impl<'d, T: Instance> CcPhy<'d, T> { CcPull::Source3_0A => 3, _ => 0, }); - w.set_ccenable(if cc_pull != CcPull::SinkDeadBattery { - Ccenable::BOTH - } else { + w.set_ccenable(if cc_pull == CcPull::Disabled { Ccenable::DISABLED + } else { + Ccenable::BOTH }); }); // Disable dead-battery pull-down resistors which are enabled by default on boot. - critical_section::with(|_| { - // TODO: other families - #[cfg(stm32g4)] - crate::pac::PWR - .cr3() - .modify(|w| w.set_ucpd1_dbdis(cc_pull != CcPull::SinkDeadBattery)); + critical_section::with(|cs| { + init( + cs, + false, + #[cfg(peri_ucpd2)] + false, + ); }); } From 8bb1fe1f653bd4bef6ad0760f33a07bcfe5d91fb Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 12 Mar 2024 15:27:52 +0100 Subject: [PATCH 684/760] Add conversion into dyn variants for channel futures --- embassy-sync/src/channel.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 01db0d09a..79d3e0378 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -263,6 +263,15 @@ impl<'ch, T> Future for DynamicReceiveFuture<'ch, T> { } } +impl<'ch, M: RawMutex, T, const N: usize> From> for DynamicReceiveFuture<'ch, T> +{ + fn from(value: ReceiveFuture<'ch, M, T, N>) -> Self { + Self { + channel: value.channel, + } + } +} + /// Future returned by [`Channel::send`] and [`Sender::send`]. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct SendFuture<'ch, M, T, const N: usize> @@ -321,6 +330,16 @@ impl<'ch, T> Future for DynamicSendFuture<'ch, T> { impl<'ch, T> Unpin for DynamicSendFuture<'ch, T> {} +impl<'ch, M: RawMutex, T, const N: usize> From> for DynamicSendFuture<'ch, T> +{ + fn from(value: SendFuture<'ch, M, T, N>) -> Self { + Self { + channel: value.channel, + message: value.message, + } + } +} + pub(crate) trait DynamicChannel { fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError>; From c0d91600ea7b6847e2295a0fee819291c951132f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 12 Mar 2024 15:37:53 +0100 Subject: [PATCH 685/760] rustfmt --- embassy-sync/src/channel.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 79d3e0378..48f4dafd6 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -263,12 +263,9 @@ impl<'ch, T> Future for DynamicReceiveFuture<'ch, T> { } } -impl<'ch, M: RawMutex, T, const N: usize> From> for DynamicReceiveFuture<'ch, T> -{ +impl<'ch, M: RawMutex, T, const N: usize> From> for DynamicReceiveFuture<'ch, T> { fn from(value: ReceiveFuture<'ch, M, T, N>) -> Self { - Self { - channel: value.channel, - } + Self { channel: value.channel } } } @@ -330,8 +327,7 @@ impl<'ch, T> Future for DynamicSendFuture<'ch, T> { impl<'ch, T> Unpin for DynamicSendFuture<'ch, T> {} -impl<'ch, M: RawMutex, T, const N: usize> From> for DynamicSendFuture<'ch, T> -{ +impl<'ch, M: RawMutex, T, const N: usize> From> for DynamicSendFuture<'ch, T> { fn from(value: SendFuture<'ch, M, T, N>) -> Self { Self { channel: value.channel, From 61050a16d5f02a7db718c6e39c811e6e434b032b Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:01:14 -0400 Subject: [PATCH 686/760] Add CRYP DMA support. Updated example. --- embassy-stm32/build.rs | 2 + embassy-stm32/src/cryp/mod.rs | 613 +++++++++++++++++++++++++++++-- examples/stm32f7/src/bin/cryp.rs | 19 +- 3 files changed, 597 insertions(+), 37 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 84e8be25d..70f4515db 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1121,6 +1121,8 @@ fn main() { (("dac", "CH2"), quote!(crate::dac::DacDma2)), (("timer", "UP"), quote!(crate::timer::UpDma)), (("hash", "IN"), quote!(crate::hash::Dma)), + (("cryp", "IN"), quote!(crate::cryp::DmaIn)), + (("cryp", "OUT"), quote!(crate::cryp::DmaOut)), (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 12353baa0..1a601533d 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -2,12 +2,14 @@ #[cfg(any(cryp_v2, cryp_v3))] use core::cmp::min; use core::marker::PhantomData; +use core::ptr; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +use crate::dma::{NoDma, Priority, Transfer, TransferOptions}; use crate::interrupt::typelevel::Interrupt; -use crate::{dma::NoDma, interrupt, pac, peripherals, Peripheral}; +use crate::{interrupt, pac, peripherals, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits @@ -55,18 +57,25 @@ pub trait Cipher<'c> { fn prepare_key(&self, _p: &pac::cryp::Cryp) {} /// Performs any cipher-specific initialization. - fn init_phase(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp) {} + fn init_phase_blocking(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp) {} + + /// Performs any cipher-specific initialization. + async fn init_phase(&self, _p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + {} /// Called prior to processing the last data block for cipher-specific operations. - fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { + fn pre_final(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { return [0; 4]; } /// Called after processing the last data block for cipher-specific operations. - fn post_final_block( + fn post_final_blocking( &self, _p: &pac::cryp::Cryp, - _cryp: &Cryp, + _cryp: &Cryp, _dir: Direction, _int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -74,6 +83,21 @@ pub trait Cipher<'c> { ) { } + /// Called after processing the last data block for cipher-specific operations. + async fn post_final( + &self, + _p: &pac::cryp::Cryp, + _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + _dir: Direction, + _int_data: &mut [u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + _padding_mask: [u8; 16], + ) + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + {} + /// Called prior to processing the first associated data block for cipher-specific operations. fn get_header_block(&self) -> &[u8] { return [0; 0].as_slice(); @@ -449,14 +473,20 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase(&self, p: &pac::cryp::Cryp, _cryp: &Cryp) { + fn init_phase_blocking(&self, p: &pac::cryp::Cryp, _cryp: &Cryp) { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + + async fn init_phase(&self, p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} } #[cfg(cryp_v2)] - fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { + fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. if dir == Direction::Encrypt { p.cr().modify(|w| w.set_crypen(false)); @@ -477,10 +507,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - fn post_final_block( + fn post_final_blocking( &self, p: &pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -501,6 +531,43 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data); } } + + #[cfg(cryp_v2)] + async fn post_final( + &self, + p: &pac::cryp::Cryp, + cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + dir: Direction, + int_data: &mut [u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + padding_mask: [u8; AES_BLOCK_SIZE], + ) + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + { + + if dir == Direction::Encrypt { + // Handle special GCM partial block process. + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(0)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } + p.cr().modify(|w| w.set_crypen(true)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + + let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + + let read = Cryp::::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); + let write = Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); + + embassy_futures::join::join(read, write).await; + + int_data.copy_from_slice(&out_data); + } + } } #[cfg(any(cryp_v2, cryp_v3))] @@ -549,14 +616,20 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase(&self, p: &pac::cryp::Cryp, _cryp: &Cryp) { + fn init_phase_blocking(&self, p: &pac::cryp::Cryp, _cryp: &Cryp) { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + + async fn init_phase(&self, p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} } #[cfg(cryp_v2)] - fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { + fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. if dir == Direction::Encrypt { p.cr().modify(|w| w.set_crypen(false)); @@ -577,10 +650,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - fn post_final_block( + fn post_final_blocking( &self, p: &pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -601,6 +674,41 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data); } } + + #[cfg(cryp_v2)] + async fn post_final( + &self, + p: &pac::cryp::Cryp, + cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + dir: Direction, + int_data: &mut [u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + padding_mask: [u8; AES_BLOCK_SIZE], + ) + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + { + + if dir == Direction::Encrypt { + // Handle special GCM partial block process. + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(0)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } + p.cr().modify(|w| w.set_crypen(true)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + + let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + + let read = Cryp::::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); + let write = Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); + + embassy_futures::join::join(read, write).await; + } + } } #[cfg(any(cryp_v2, cryp_v3))] @@ -707,7 +815,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase(&self, p: &pac::cryp::Cryp, cryp: &Cryp) { + fn init_phase_blocking(&self, p: &pac::cryp::Cryp, cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0); @@ -716,12 +824,25 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip while p.cr().read().crypen() {} } + async fn init_phase(&self, p: &pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + + Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, &self.block0).await; + + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + fn get_header_block(&self) -> &[u8] { return &self.aad_header[0..self.aad_header_len]; } #[cfg(cryp_v2)] - fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { + fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { //Handle special CCM partial block process. let mut temp1 = [0; 4]; if dir == Direction::Decrypt { @@ -747,10 +868,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } #[cfg(cryp_v2)] - fn post_final_block( + fn post_final_blocking( &self, p: &pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], temp1: [u32; 4], @@ -782,6 +903,47 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip cryp.write_words_blocking(Self::BLOCK_SIZE, &in_data); } } + + #[cfg(cryp_v2)] + async fn post_final( + &self, + p: &pac::cryp::Cryp, + cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + dir: Direction, + int_data: &mut [u8; AES_BLOCK_SIZE], + temp1: [u32; 4], + padding_mask: [u8; 16], + ) + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + { + if dir == Direction::Decrypt { + //Handle special CCM partial block process. + let mut temp2 = [0; 4]; + temp2[0] = p.csgcmccmr(0).read().swap_bytes(); + temp2[1] = p.csgcmccmr(1).read().swap_bytes(); + temp2[2] = p.csgcmccmr(2).read().swap_bytes(); + temp2[3] = p.csgcmccmr(3).read().swap_bytes(); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(1)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + // Header phase + p.cr().modify(|w| w.set_gcm_ccmph(1)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } + let mut in_data: [u32; 4] = [0; 4]; + for i in 0..in_data.len() { + let mut int_bytes: [u8; 4] = [0; 4]; + int_bytes.copy_from_slice(&int_data[(i * 4)..(i * 4) + 4]); + let int_word = u32::from_le_bytes(int_bytes); + in_data[i] = int_word; + in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; + } + Cryp::::write_words(&mut cryp.indma, Self::BLOCK_SIZE, &in_data).await; + } + } } #[cfg(any(cryp_v2, cryp_v3))] @@ -849,18 +1011,18 @@ pub enum Direction { } /// Crypto Accelerator Driver -pub struct Cryp<'d, T: Instance, D = NoDma> { +pub struct Cryp<'d, T: Instance, DmaIn = NoDma, DmaOut = NoDma> { _peripheral: PeripheralRef<'d, T>, - indma: PeripheralRef<'d, D>, - outdma: PeripheralRef<'d, D>, + indma: PeripheralRef<'d, DmaIn>, + outdma: PeripheralRef<'d, DmaOut>, } -impl<'d, T: Instance, D> Cryp<'d, T, D> { +impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { /// Create a new CRYP driver. pub fn new( peri: impl Peripheral

+ 'd, - indma: impl Peripheral

+ 'd, - outdma: impl Peripheral

+ 'd, + indma: impl Peripheral

+ 'd, + outdma: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { T::enable_and_reset(); @@ -881,7 +1043,7 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { /// Key size must be 128, 192, or 256 bits. /// Initialization vector must only be supplied if necessary. /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. - pub fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { + pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { let mut ctx: Context<'c, C> = Context { dir, last_block_processed: false, @@ -948,7 +1110,89 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { // Flush in/out FIFOs T::regs().cr().modify(|w| w.fflush()); - ctx.cipher.init_phase(&T::regs(), self); + ctx.cipher.init_phase_blocking(&T::regs(), self); + + self.store_context(&mut ctx); + + ctx + } + + /// Start a new cipher operation. + /// Key size must be 128, 192, or 256 bits. + /// Initialization vector must only be supplied if necessary. + /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. + pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&mut self, cipher: &'c C, dir: Direction) -> Context<'c, C> + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + { + let mut ctx: Context<'c, C> = Context { + dir, + last_block_processed: false, + cr: 0, + iv: [0; 4], + csgcmccm: [0; 8], + csgcm: [0; 8], + aad_complete: false, + header_len: 0, + payload_len: 0, + cipher: cipher, + phantom_data: PhantomData, + header_processed: false, + aad_buffer: [0; 16], + aad_buffer_len: 0, + }; + + T::regs().cr().modify(|w| w.set_crypen(false)); + + let key = ctx.cipher.key(); + + if key.len() == (128 / 8) { + T::regs().cr().modify(|w| w.set_keysize(0)); + } else if key.len() == (192 / 8) { + T::regs().cr().modify(|w| w.set_keysize(1)); + } else if key.len() == (256 / 8) { + T::regs().cr().modify(|w| w.set_keysize(2)); + } + + self.load_key(key); + + // Set data type to 8-bit. This will match software implementations. + T::regs().cr().modify(|w| w.set_datatype(2)); + + ctx.cipher.prepare_key(&T::regs()); + + ctx.cipher.set_algomode(&T::regs()); + + // Set encrypt/decrypt + if dir == Direction::Encrypt { + T::regs().cr().modify(|w| w.set_algodir(false)); + } else { + T::regs().cr().modify(|w| w.set_algodir(true)); + } + + // Load the IV into the registers. + let iv = ctx.cipher.iv(); + let mut full_iv: [u8; 16] = [0; 16]; + full_iv[0..iv.len()].copy_from_slice(iv); + let mut iv_idx = 0; + let mut iv_word: [u8; 4] = [0; 4]; + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); + + // Flush in/out FIFOs + T::regs().cr().modify(|w| w.fflush()); + + ctx.cipher.init_phase(&T::regs(), self).await; self.store_context(&mut ctx); @@ -1053,6 +1297,107 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { self.store_context(ctx); } + #[cfg(any(cryp_v2, cryp_v3))] + /// Controls the header phase of cipher processing. + /// This function is only valid for GCM, CCM, and GMAC modes. + /// It only needs to be called if using one of these modes and there is associated data. + /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. + /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block. + /// When supplying the last block of AAD, `last_aad_block` must be `true`. + pub async fn aad< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( + &mut self, + ctx: &mut Context<'c, C>, + aad: &[u8], + last_aad_block: bool, + ) + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + { + self.load_context(ctx); + + // Perform checks for correctness. + if ctx.aad_complete { + panic!("Cannot update AAD after starting payload!") + } + + ctx.header_len += aad.len() as u64; + + // Header phase + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); + T::regs().cr().modify(|w| w.set_crypen(true)); + + // First write the header B1 block if not yet written. + if !ctx.header_processed { + ctx.header_processed = true; + let header = ctx.cipher.get_header_block(); + ctx.aad_buffer[0..header.len()].copy_from_slice(header); + ctx.aad_buffer_len += header.len(); + } + + // Fill the header block to make a full block. + let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len); + ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]); + ctx.aad_buffer_len += len_to_copy; + ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); + let mut aad_len_remaining = aad.len() - len_to_copy; + + if ctx.aad_buffer_len < C::BLOCK_SIZE { + // The buffer isn't full and this is the last buffer, so process it as is (already padded). + if last_aad_block { + Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + + // Switch to payload phase. + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + } else { + // Just return because we don't yet have a full block to process. + return; + } + } else { + // Load the full block from the buffer. + Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + } + + // Handle a partial block that is passed in. + ctx.aad_buffer_len = 0; + let leftovers = aad_len_remaining % C::BLOCK_SIZE; + ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]); + ctx.aad_buffer_len += leftovers; + ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); + aad_len_remaining -= leftovers; + assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0); + + // Load full data blocks into core. + let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; + let start_index = len_to_copy; + let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks); + Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &aad[start_index..end_index]).await; + + if last_aad_block { + if leftovers > 0 { + Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + } + // Switch to payload phase. + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + } + + self.store_context(ctx); + } + /// Performs encryption/decryption on the provided context. /// The context determines algorithm, mode, and state of the crypto accelerator. /// When the last piece of data is supplied, `last_block` should be `true`. @@ -1118,7 +1463,7 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { // Handle the final block, which is incomplete. if last_block_remainder > 0 { let padding_len = C::BLOCK_SIZE - last_block_remainder; - let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir, padding_len); + let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len); let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; @@ -1134,7 +1479,102 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { let mut mask: [u8; 16] = [0; 16]; mask[..last_block_remainder].fill(0xFF); ctx.cipher - .post_final_block(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask); + .post_final_blocking(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask); + } + + ctx.payload_len += input.len() as u64; + + self.store_context(ctx); + } + + /// Performs encryption/decryption on the provided context. + /// The context determines algorithm, mode, and state of the crypto accelerator. + /// When the last piece of data is supplied, `last_block` should be `true`. + /// This function panics under various mismatches of parameters. + /// Input and output buffer lengths must match. + /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. + /// Padding or ciphertext stealing must be managed by the application for these modes. + /// Data must also be a multiple of block size unless `last_block` is `true`. + pub async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>( + &mut self, + ctx: &mut Context<'c, C>, + input: &[u8], + output: &mut [u8], + last_block: bool, + ) + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + { + self.load_context(ctx); + + let last_block_remainder = input.len() % C::BLOCK_SIZE; + + // Perform checks for correctness. + if !ctx.aad_complete && ctx.header_len > 0 { + panic!("Additional associated data must be processed first!"); + } else if !ctx.aad_complete { + #[cfg(any(cryp_v2, cryp_v3))] + { + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + T::regs().cr().modify(|w| w.set_crypen(true)); + } + } + if ctx.last_block_processed { + panic!("The last block has already been processed!"); + } + if input.len() > output.len() { + panic!("Output buffer length must match input length."); + } + if !last_block { + if last_block_remainder != 0 { + panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE); + } + } + if C::REQUIRES_PADDING { + if last_block_remainder != 0 { + panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); + } + } + if last_block { + ctx.last_block_processed = true; + } + + // Load data into core, block by block. + let num_full_blocks = input.len() / C::BLOCK_SIZE; + for block in 0..num_full_blocks { + let index = block * C::BLOCK_SIZE; + // Read block out + let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut output[index..index + 4]); + // Write block in + let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + 4]); + embassy_futures::join::join(read, write).await; + } + + // Handle the final block, which is incomplete. + if last_block_remainder > 0 { + let padding_len = C::BLOCK_SIZE - last_block_remainder; + let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len); + + let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); + let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut intermediate_data); + let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &last_block); + embassy_futures::join::join(read, write).await; + + // Handle the last block depending on mode. + let output_len = output.len(); + output[output_len - last_block_remainder..output_len] + .copy_from_slice(&intermediate_data[0..last_block_remainder]); + + let mut mask: [u8; 16] = [0; 16]; + mask[..last_block_remainder].fill(0xFF); + ctx.cipher + .post_final(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask).await; } ctx.payload_len += input.len() as u64; @@ -1188,6 +1628,50 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { tag } + #[cfg(any(cryp_v2, cryp_v3))] + /// This function only needs to be called for GCM, CCM, and GMAC modes to + /// generate an authentication tag. + pub async fn finish<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated>(&mut self, mut ctx: Context<'c, C>) -> [u8; TAG_SIZE] + where + DmaIn: crate::cryp::DmaIn, + DmaOut: crate::cryp::DmaOut, + { + self.load_context(&mut ctx); + + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); + T::regs().cr().modify(|w| w.set_crypen(true)); + + let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32; + let headerlen2: u32 = (ctx.header_len * 8) as u32; + let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32; + let payloadlen2: u32 = (ctx.payload_len * 8) as u32; + + #[cfg(cryp_v2)] + let footer: [u32; 4] = [ + headerlen1.swap_bytes(), + headerlen2.swap_bytes(), + payloadlen1.swap_bytes(), + payloadlen2.swap_bytes(), + ]; + #[cfg(cryp_v3)] + let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; + + let write = Self::write_words(&mut self.indma, C::BLOCK_SIZE, &footer); + + let mut full_tag: [u8; 16] = [0; 16]; + let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut full_tag); + + embassy_futures::join::join(read, write).await; + + let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; + tag.copy_from_slice(&full_tag[0..TAG_SIZE]); + + T::regs().cr().modify(|w| w.set_crypen(false)); + + tag + } + fn load_key(&self, key: &[u8]) { // Load the key into the registers. let mut keyidx = 0; @@ -1288,6 +1772,30 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { } } + async fn write_bytes(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u8]) + where + DmaIn: crate::cryp::DmaIn, + { + if blocks.len() == 0 { + return; + } + // Ensure input is a multiple of block size. + assert_eq!(blocks.len() % block_size, 0); + // Configure DMA to transfer input to crypto core. + let dma_request = dma.request(); + let dst_ptr = T::regs().din().as_ptr(); + let num_words = blocks.len() / 4; + let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); + let options = TransferOptions { + priority: Priority::High, + ..Default::default() + }; + let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; + T::regs().dmacr().modify(|w| w.set_dien(true)); + // Wait for the transfer to complete. + dma_transfer.await; + } + fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) { assert_eq!((blocks.len() * 4) % block_size, 0); let mut byte_counter: usize = 0; @@ -1301,6 +1809,30 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { } } + async fn write_words(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u32]) + where + DmaIn: crate::cryp::DmaIn, + { + if blocks.len() == 0 { + return; + } + // Ensure input is a multiple of block size. + assert_eq!((blocks.len() * 4) % block_size, 0); + // Configure DMA to transfer input to crypto core. + let dma_request = dma.request(); + let dst_ptr = T::regs().din().as_ptr(); + let num_words = blocks.len(); + let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); + let options = TransferOptions { + priority: Priority::High, + ..Default::default() + }; + let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; + T::regs().dmacr().modify(|w| w.set_dien(true)); + // Wait for the transfer to complete. + dma_transfer.await; + } + fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) { // Block until there is output to read. while !T::regs().sr().read().ofne() {} @@ -1315,6 +1847,30 @@ impl<'d, T: Instance, D> Cryp<'d, T, D> { index += 4; } } + + async fn read_bytes(dma: &mut PeripheralRef<'_, DmaOut>, block_size: usize, blocks: &mut [u8]) + where + DmaOut: crate::cryp::DmaOut, + { + if blocks.len() == 0 { + return; + } + // Ensure input is a multiple of block size. + assert_eq!(blocks.len() % block_size, 0); + // Configure DMA to get output from crypto core. + let dma_request = dma.request(); + let src_ptr = T::regs().dout().as_ptr(); + let num_words = blocks.len() / 4; + let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words); + let options = TransferOptions { + priority: Priority::VeryHigh, + ..Default::default() + }; + let dma_transfer = unsafe { Transfer::new_read_raw(dma, dma_request, src_ptr, dst_ptr, options) }; + T::regs().dmacr().modify(|w| w.set_doen(true)); + // Wait for the transfer to complete. + dma_transfer.await; + } } pub(crate) mod sealed { @@ -1344,3 +1900,6 @@ foreach_interrupt!( } }; ); + +dma_trait!(DmaIn, Instance); +dma_trait!(DmaOut, Instance); \ No newline at end of file diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index 79b74e569..a5418765b 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -6,7 +6,6 @@ use aes_gcm::aead::{AeadInPlace, KeyInit}; use aes_gcm::Aes128Gcm; use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::{ bind_interrupts, cryp::{self, *}, @@ -27,7 +26,7 @@ async fn main(_spawner: Spawner) -> ! { let payload: &[u8] = b"hello world"; let aad: &[u8] = b"additional data"; - let hw_cryp = Cryp::new(p.CRYP, NoDma, NoDma, Irqs); + let mut hw_cryp = Cryp::new(p.CRYP, p.DMA2_CH6, p.DMA2_CH5, Irqs); let key: [u8; 16] = [0; 16]; let mut ciphertext: [u8; 11] = [0; 11]; let mut plaintext: [u8; 11] = [0; 11]; @@ -37,16 +36,16 @@ async fn main(_spawner: Spawner) -> ! { // Encrypt in hardware using AES-GCM 128-bit let aes_gcm = AesGcm::new(&key, &iv); - let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); - hw_cryp.aad_blocking(&mut gcm_encrypt, aad, true); - hw_cryp.payload_blocking(&mut gcm_encrypt, payload, &mut ciphertext, true); - let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); + let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt).await; + hw_cryp.aad(&mut gcm_encrypt, aad, true).await; + hw_cryp.payload(&mut gcm_encrypt, payload, &mut ciphertext, true).await; + let encrypt_tag = hw_cryp.finish(gcm_encrypt).await; // Decrypt in hardware using AES-GCM 128-bit - let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); - hw_cryp.aad_blocking(&mut gcm_decrypt, aad, true); - hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); - let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); + let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await; + hw_cryp.aad(&mut gcm_decrypt, aad, true).await; + hw_cryp.payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true).await; + let decrypt_tag = hw_cryp.finish(gcm_decrypt).await; let hw_end_time = Instant::now(); let hw_execution_time = hw_end_time - hw_start_time; From 1ec9fc58f44987c11ac1e093f117679c56dbe2ed Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:52:34 -0400 Subject: [PATCH 687/760] Add async CRYP to test. --- embassy-stm32/src/cryp/mod.rs | 52 +++++++++++++++-------------------- tests/stm32/src/bin/cryp.rs | 31 ++++++++++++++------- tests/stm32/src/common.rs | 1 + 3 files changed, 44 insertions(+), 40 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 1a601533d..aa4c2a024 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -98,7 +98,7 @@ pub trait Cipher<'c> { DmaOut: crate::cryp::DmaOut, {} - /// Called prior to processing the first associated data block for cipher-specific operations. + /// Returns the AAD header block as required by the cipher. fn get_header_block(&self) -> &[u8] { return [0; 0].as_slice(); } @@ -500,7 +500,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } #[cfg(cryp_v3)] - fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. p.cr().modify(|w| w.set_npblb(padding_len as u8)); [0; 4] @@ -643,7 +643,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } #[cfg(cryp_v3)] - fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. p.cr().modify(|w| w.set_npblb(padding_len as u8)); [0; 4] @@ -861,7 +861,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } #[cfg(cryp_v3)] - fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. p.cr().modify(|w| w.set_npblb(padding_len as u8)); [0; 4] @@ -1039,10 +1039,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { instance } - /// Start a new cipher operation. - /// Key size must be 128, 192, or 256 bits. - /// Initialization vector must only be supplied if necessary. - /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. + /// Start a new encrypt or decrypt operation for the given cipher. pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { let mut ctx: Context<'c, C> = Context { dir, @@ -1117,10 +1114,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { ctx } - /// Start a new cipher operation. - /// Key size must be 128, 192, or 256 bits. - /// Initialization vector must only be supplied if necessary. - /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. + /// Start a new encrypt or decrypt operation for the given cipher. pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&mut self, cipher: &'c C, dir: Direction) -> Context<'c, C> where DmaIn: crate::cryp::DmaIn, @@ -1201,10 +1195,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { #[cfg(any(cryp_v2, cryp_v3))] /// Controls the header phase of cipher processing. - /// This function is only valid for GCM, CCM, and GMAC modes. - /// It only needs to be called if using one of these modes and there is associated data. - /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. - /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block. + /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. + /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload_blocking`. + /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. /// When supplying the last block of AAD, `last_aad_block` must be `true`. pub fn aad_blocking< 'c, @@ -1299,10 +1292,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { #[cfg(any(cryp_v2, cryp_v3))] /// Controls the header phase of cipher processing. - /// This function is only valid for GCM, CCM, and GMAC modes. - /// It only needs to be called if using one of these modes and there is associated data. - /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. - /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block. + /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. + /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`. + /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. /// When supplying the last block of AAD, `last_aad_block` must be `true`. pub async fn aad< 'c, @@ -1402,7 +1394,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { /// The context determines algorithm, mode, and state of the crypto accelerator. /// When the last piece of data is supplied, `last_block` should be `true`. /// This function panics under various mismatches of parameters. - /// Input and output buffer lengths must match. + /// Output buffer must be at least as long as the input buffer. /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. /// Padding or ciphertext stealing must be managed by the application for these modes. /// Data must also be a multiple of block size unless `last_block` is `true`. @@ -1455,9 +1447,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { for block in 0..num_full_blocks { let index = block * C::BLOCK_SIZE; // Write block in - self.write_bytes_blocking(C::BLOCK_SIZE, &input[index..index + 4]); + self.write_bytes_blocking(C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]); // Read block out - self.read_bytes_blocking(C::BLOCK_SIZE, &mut output[index..index + 4]); + self.read_bytes_blocking(C::BLOCK_SIZE, &mut output[index..index + C::BLOCK_SIZE]); } // Handle the final block, which is incomplete. @@ -1491,7 +1483,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { /// The context determines algorithm, mode, and state of the crypto accelerator. /// When the last piece of data is supplied, `last_block` should be `true`. /// This function panics under various mismatches of parameters. - /// Input and output buffer lengths must match. + /// Output buffer must be at least as long as the input buffer. /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. /// Padding or ciphertext stealing must be managed by the application for these modes. /// Data must also be a multiple of block size unless `last_block` is `true`. @@ -1548,9 +1540,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { for block in 0..num_full_blocks { let index = block * C::BLOCK_SIZE; // Read block out - let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut output[index..index + 4]); + let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut output[index..index + C::BLOCK_SIZE]); // Write block in - let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + 4]); + let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]); embassy_futures::join::join(read, write).await; } @@ -1583,8 +1575,8 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } #[cfg(any(cryp_v2, cryp_v3))] - /// This function only needs to be called for GCM, CCM, and GMAC modes to - /// generate an authentication tag. + /// Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. + /// Called after the all data has been encrypted/decrypted by `payload`. pub fn finish_blocking< 'c, const TAG_SIZE: usize, @@ -1629,8 +1621,8 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } #[cfg(any(cryp_v2, cryp_v3))] - /// This function only needs to be called for GCM, CCM, and GMAC modes to - /// generate an authentication tag. + // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. + /// Called after the all data has been encrypted/decrypted by `payload`. pub async fn finish<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated>(&mut self, mut ctx: Context<'c, C>) -> [u8; TAG_SIZE] where DmaIn: crate::cryp::DmaIn, diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index f105abf26..6bca55f55 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs @@ -10,9 +10,17 @@ use aes_gcm::aead::{AeadInPlace, KeyInit}; use aes_gcm::Aes128Gcm; use common::*; use embassy_executor::Spawner; -use embassy_stm32::cryp::*; +use embassy_stm32::{ + bind_interrupts, + cryp::{self, *}, + peripherals +}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + CRYP => cryp::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); @@ -22,27 +30,30 @@ async fn main(_spawner: Spawner) { const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1"; const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg"; - let hw_cryp = Cryp::new(p.CRYP); + let in_dma = peri!(p, CRYP_IN_DMA); + let out_dma = peri!(p, CRYP_OUT_DMA); + + let mut hw_cryp = Cryp::new(p.CRYP, in_dma, out_dma, Irqs); let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; - // Encrypt in hardware using AES-GCM 128-bit + // Encrypt in hardware using AES-GCM 128-bit in blocking mode. let aes_gcm = AesGcm::new(&key, &iv); - let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); + let mut gcm_encrypt = hw_cryp.start_blocking(&aes_gcm, Direction::Encrypt); hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false); hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true); hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false); hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true); let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); - // Decrypt in hardware using AES-GCM 128-bit - let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); - hw_cryp.aad_blocking(&mut gcm_decrypt, AAD1, false); - hw_cryp.aad_blocking(&mut gcm_decrypt, AAD2, true); - hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); - let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); + // Decrypt in hardware using AES-GCM 128-bit in async (DMA) mode. + let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await; + hw_cryp.aad(&mut gcm_decrypt, AAD1, false).await; + hw_cryp.aad(&mut gcm_decrypt, AAD2, true).await; + hw_cryp.payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true).await; + let decrypt_tag = hw_cryp.finish(gcm_decrypt).await; info!("AES-GCM Ciphertext: {:?}", ciphertext); info!("AES-GCM Plaintext: {:?}", plaintext); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 3297ea7e2..c379863a8 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -140,6 +140,7 @@ define_peris!( ); #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] define_peris!( + CRYP_IN_DMA = DMA1_CH0, CRYP_OUT_DMA = DMA1_CH1, UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, ADC = ADC1, DAC = DAC1, DAC_PIN = PA4, From 2634a57098ebee5fb2ea3efe7cfb5629817a5b43 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:05:22 -0400 Subject: [PATCH 688/760] Correct cryp CI build issues. --- embassy-stm32/src/cryp/mod.rs | 98 +++++++++++++++++++------------- examples/stm32f7/src/bin/cryp.rs | 4 +- tests/stm32/src/bin/cryp.rs | 6 +- 3 files changed, 66 insertions(+), 42 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index aa4c2a024..74b095b6f 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -60,11 +60,12 @@ pub trait Cipher<'c> { fn init_phase_blocking(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp) {} /// Performs any cipher-specific initialization. - async fn init_phase(&self, _p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) + async fn init_phase(&self, _p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) where DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, - {} + { + } /// Called prior to processing the last data block for cipher-specific operations. fn pre_final(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { @@ -92,11 +93,11 @@ pub trait Cipher<'c> { _int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], _padding_mask: [u8; 16], - ) - where + ) where DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, - {} + { + } /// Returns the AAD header block as required by the cipher. fn get_header_block(&self) -> &[u8] { @@ -479,7 +480,11 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { while p.cr().read().crypen() {} } - async fn init_phase(&self, p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { + async fn init_phase( + &self, + p: &pac::cryp::Cryp, + _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + ) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -541,12 +546,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], padding_mask: [u8; AES_BLOCK_SIZE], - ) - where - DmaIn: crate::cryp::DmaIn, + ) where + DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, { - if dir == Direction::Encrypt { // Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); @@ -562,7 +565,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { let read = Cryp::::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); let write = Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); - + embassy_futures::join::join(read, write).await; int_data.copy_from_slice(&out_data); @@ -622,7 +625,11 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { while p.cr().read().crypen() {} } - async fn init_phase(&self, p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { + async fn init_phase( + &self, + p: &pac::cryp::Cryp, + _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + ) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -684,12 +691,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], padding_mask: [u8; AES_BLOCK_SIZE], - ) - where - DmaIn: crate::cryp::DmaIn, + ) where + DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, { - if dir == Direction::Encrypt { // Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); @@ -705,7 +710,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { let read = Cryp::::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); let write = Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); - + embassy_futures::join::join(read, write).await; } } @@ -826,7 +831,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip async fn init_phase(&self, p: &pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) where - DmaIn: crate::cryp::DmaIn, + DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, { p.cr().modify(|w| w.set_gcm_ccmph(0)); @@ -913,8 +918,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip int_data: &mut [u8; AES_BLOCK_SIZE], temp1: [u32; 4], padding_mask: [u8; 16], - ) - where + ) where DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, { @@ -1040,7 +1044,11 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } /// Start a new encrypt or decrypt operation for the given cipher. - pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { + pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>( + &self, + cipher: &'c C, + dir: Direction, + ) -> Context<'c, C> { let mut ctx: Context<'c, C> = Context { dir, last_block_processed: false, @@ -1115,7 +1123,11 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } /// Start a new encrypt or decrypt operation for the given cipher. - pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&mut self, cipher: &'c C, dir: Direction) -> Context<'c, C> + pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>( + &mut self, + cipher: &'c C, + dir: Direction, + ) -> Context<'c, C> where DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, @@ -1296,17 +1308,12 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`. /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. /// When supplying the last block of AAD, `last_aad_block` must be `true`. - pub async fn aad< - 'c, - const TAG_SIZE: usize, - C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, - >( + pub async fn aad<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated>( &mut self, ctx: &mut Context<'c, C>, aad: &[u8], last_aad_block: bool, - ) - where + ) where DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, { @@ -1493,8 +1500,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { input: &[u8], output: &mut [u8], last_block: bool, - ) - where + ) where DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, { @@ -1540,7 +1546,11 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { for block in 0..num_full_blocks { let index = block * C::BLOCK_SIZE; // Read block out - let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut output[index..index + C::BLOCK_SIZE]); + let read = Self::read_bytes( + &mut self.outdma, + C::BLOCK_SIZE, + &mut output[index..index + C::BLOCK_SIZE], + ); // Write block in let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]); embassy_futures::join::join(read, write).await; @@ -1566,7 +1576,8 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { let mut mask: [u8; 16] = [0; 16]; mask[..last_block_remainder].fill(0xFF); ctx.cipher - .post_final(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask).await; + .post_final(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask) + .await; } ctx.payload_len += input.len() as u64; @@ -1623,7 +1634,14 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { #[cfg(any(cryp_v2, cryp_v3))] // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. /// Called after the all data has been encrypted/decrypted by `payload`. - pub async fn finish<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated>(&mut self, mut ctx: Context<'c, C>) -> [u8; TAG_SIZE] + pub async fn finish< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( + &mut self, + mut ctx: Context<'c, C>, + ) -> [u8; TAG_SIZE] where DmaIn: crate::cryp::DmaIn, DmaOut: crate::cryp::DmaOut, @@ -1663,7 +1681,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { tag } - + fn load_key(&self, key: &[u8]) { // Load the key into the registers. let mut keyidx = 0; @@ -1766,7 +1784,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { async fn write_bytes(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u8]) where - DmaIn: crate::cryp::DmaIn, + DmaIn: crate::cryp::DmaIn, { if blocks.len() == 0 { return; @@ -1788,6 +1806,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { dma_transfer.await; } + #[cfg(any(cryp_v2, cryp_v3))] fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) { assert_eq!((blocks.len() * 4) % block_size, 0); let mut byte_counter: usize = 0; @@ -1801,10 +1820,11 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } } + #[cfg(any(cryp_v2, cryp_v3))] async fn write_words(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u32]) where DmaIn: crate::cryp::DmaIn, - { + { if blocks.len() == 0 { return; } @@ -1840,7 +1860,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } } - async fn read_bytes(dma: &mut PeripheralRef<'_, DmaOut>, block_size: usize, blocks: &mut [u8]) + async fn read_bytes(dma: &mut PeripheralRef<'_, DmaOut>, block_size: usize, blocks: &mut [u8]) where DmaOut: crate::cryp::DmaOut, { @@ -1894,4 +1914,4 @@ foreach_interrupt!( ); dma_trait!(DmaIn, Instance); -dma_trait!(DmaOut, Instance); \ No newline at end of file +dma_trait!(DmaOut, Instance); diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index a5418765b..ce2cf0489 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -44,7 +44,9 @@ async fn main(_spawner: Spawner) -> ! { // Decrypt in hardware using AES-GCM 128-bit let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await; hw_cryp.aad(&mut gcm_decrypt, aad, true).await; - hw_cryp.payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true).await; + hw_cryp + .payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true) + .await; let decrypt_tag = hw_cryp.finish(gcm_decrypt).await; let hw_end_time = Instant::now(); diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index 6bca55f55..cc317f625 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs @@ -13,7 +13,7 @@ use embassy_executor::Spawner; use embassy_stm32::{ bind_interrupts, cryp::{self, *}, - peripherals + peripherals, }; use {defmt_rtt as _, panic_probe as _}; @@ -52,7 +52,9 @@ async fn main(_spawner: Spawner) { let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await; hw_cryp.aad(&mut gcm_decrypt, AAD1, false).await; hw_cryp.aad(&mut gcm_decrypt, AAD2, true).await; - hw_cryp.payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true).await; + hw_cryp + .payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true) + .await; let decrypt_tag = hw_cryp.finish(gcm_decrypt).await; info!("AES-GCM Ciphertext: {:?}", ciphertext); From b1ba2729878a1553145f215dff40281c65b75983 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:13:06 -0400 Subject: [PATCH 689/760] rustfmt --- examples/stm32f7/src/bin/cryp.rs | 7 ++----- tests/stm32/src/bin/cryp.rs | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index ce2cf0489..235853cb9 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -6,11 +6,8 @@ use aes_gcm::aead::{AeadInPlace, KeyInit}; use aes_gcm::Aes128Gcm; use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::{ - bind_interrupts, - cryp::{self, *}, -}; -use embassy_stm32::{peripherals, Config}; +use embassy_stm32::cryp::{self, *}; +use embassy_stm32::{bind_interrupts, peripherals, Config}; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index cc317f625..60778bdaa 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs @@ -10,11 +10,8 @@ use aes_gcm::aead::{AeadInPlace, KeyInit}; use aes_gcm::Aes128Gcm; use common::*; use embassy_executor::Spawner; -use embassy_stm32::{ - bind_interrupts, - cryp::{self, *}, - peripherals, -}; +use embassy_stm32::cryp::{self, *}; +use embassy_stm32::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { From 12a3af5043fd1d9a32f57b5cab9b5729a304ffc5 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 7 Mar 2024 22:48:25 +1000 Subject: [PATCH 690/760] Shared frame types. Remove BXCAN speciffic id and frame modules Remove SizedClassicData --- embassy-stm32/src/can/bx/frame.rs | 248 ------------------------- embassy-stm32/src/can/bx/id.rs | 113 ----------- embassy-stm32/src/can/bx/mod.rs | 104 +++++++---- embassy-stm32/src/can/bxcan.rs | 17 +- embassy-stm32/src/can/fd/peripheral.rs | 2 +- embassy-stm32/src/can/frame.rs | 54 +++++- examples/stm32f1/src/bin/can.rs | 6 +- examples/stm32f4/src/bin/can.rs | 4 +- examples/stm32f7/src/bin/can.rs | 2 +- tests/stm32/src/bin/can.rs | 4 +- 10 files changed, 138 insertions(+), 416 deletions(-) delete mode 100644 embassy-stm32/src/can/bx/frame.rs delete mode 100644 embassy-stm32/src/can/bx/id.rs diff --git a/embassy-stm32/src/can/bx/frame.rs b/embassy-stm32/src/can/bx/frame.rs deleted file mode 100644 index 828f375be..000000000 --- a/embassy-stm32/src/can/bx/frame.rs +++ /dev/null @@ -1,248 +0,0 @@ -#[cfg(test)] -use core::cmp::Ordering; -use core::ops::{Deref, DerefMut}; - -use crate::can::bx::{Id, IdReg}; - -/// A CAN data or remote frame. -#[derive(Clone, Debug, Eq)] -//#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Frame { - pub(crate) id: IdReg, - pub(crate) data: Data, -} - -impl Frame { - /// Creates a new data frame. - pub fn new_data(id: impl Into, data: impl Into) -> Self { - let id = match id.into() { - Id::Standard(id) => IdReg::new_standard(id), - Id::Extended(id) => IdReg::new_extended(id), - }; - - Self { id, data: data.into() } - } - - /// Creates a new remote frame with configurable data length code (DLC). - /// - /// # Panics - /// - /// This function will panic if `dlc` is not inside the valid range `0..=8`. - pub fn new_remote(id: impl Into, dlc: u8) -> Self { - assert!(dlc <= 8); - - let mut frame = Self::new_data(id, []); - // Just extend the data length, even with no data present. The API does not hand out this - // `Data` object. - frame.data.len = dlc; - frame.id = frame.id.with_rtr(true); - frame - } - - /// Returns true if this frame is an extended frame. - #[inline] - pub fn is_extended(&self) -> bool { - self.id.is_extended() - } - - /// Returns true if this frame is a standard frame. - #[inline] - pub fn is_standard(&self) -> bool { - self.id.is_standard() - } - - /// Returns true if this frame is a remote frame. - #[inline] - pub fn is_remote_frame(&self) -> bool { - self.id.rtr() - } - - /// Returns true if this frame is a data frame. - #[inline] - pub fn is_data_frame(&self) -> bool { - !self.is_remote_frame() - } - - /// Returns the frame identifier. - #[inline] - pub fn id(&self) -> Id { - self.id.to_id() - } - - /// Returns the priority of this frame. - #[inline] - pub fn priority(&self) -> FramePriority { - FramePriority(self.id) - } - - /// Returns the data length code (DLC) which is in the range 0..8. - /// - /// For data frames the DLC value always matches the length of the data. - /// Remote frames do not carry any data, yet the DLC can be greater than 0. - #[inline] - pub fn dlc(&self) -> u8 { - self.data.len() as u8 - } - - /// Returns the frame data (0..8 bytes in length) if this is a data frame. - /// - /// If this is a remote frame, returns `None`. - pub fn data(&self) -> Option<&Data> { - if self.is_data_frame() { - Some(&self.data) - } else { - None - } - } -} - -impl PartialEq for Frame { - fn eq(&self, other: &Self) -> bool { - match (self.data(), other.data()) { - (None, None) => self.id.eq(&other.id), - (Some(a), Some(b)) => self.id.eq(&other.id) && a.eq(b), - (None, Some(_)) | (Some(_), None) => false, - } - } -} - -/// Priority of a CAN frame. -/// -/// Returned by [`Frame::priority`]. -/// -/// The priority of a frame is determined by the bits that are part of the *arbitration field*. -/// These consist of the frame identifier bits (including the *IDE* bit, which is 0 for extended -/// frames and 1 for standard frames), as well as the *RTR* bit, which determines whether a frame -/// is a data or remote frame. Lower values of the *arbitration field* have higher priority. -/// -/// This struct wraps the *arbitration field* and implements `PartialOrd` and `Ord` accordingly, -/// ordering higher priorities greater than lower ones. -#[derive(Debug, Copy, Clone)] -pub struct FramePriority(IdReg); - -/// Ordering is based on the Identifier and frame type (data vs. remote) and can be used to sort -/// frames by priority. -impl Ord for FramePriority { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl PartialOrd for FramePriority { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for FramePriority { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == core::cmp::Ordering::Equal - } -} - -impl Eq for FramePriority {} - -/// Payload of a CAN data frame. -/// -/// Contains 0 to 8 Bytes of data. -/// -/// `Data` implements `From<[u8; N]>` for all `N` up to 8, which provides a convenient lossless -/// conversion from fixed-length arrays. -#[derive(Debug, Copy, Clone)] -pub struct Data { - pub(crate) len: u8, - pub(crate) bytes: [u8; 8], -} - -impl Data { - /// Creates a data payload from a raw byte slice. - /// - /// Returns `None` if `data` contains more than 8 Bytes (which is the maximum). - /// - /// `Data` can also be constructed from fixed-length arrays up to length 8 via `From`/`Into`. - pub fn new(data: &[u8]) -> Option { - if data.len() > 8 { - return None; - } - - let mut bytes = [0; 8]; - bytes[..data.len()].copy_from_slice(data); - - Some(Self { - len: data.len() as u8, - bytes, - }) - } - - /// Creates an empty data payload containing 0 bytes. - #[inline] - pub const fn empty() -> Self { - Self { len: 0, bytes: [0; 8] } - } -} - -impl Deref for Data { - type Target = [u8]; - - #[inline] - fn deref(&self) -> &[u8] { - &self.bytes[..usize::from(self.len)] - } -} - -impl DerefMut for Data { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - &mut self.bytes[..usize::from(self.len)] - } -} - -impl AsRef<[u8]> for Data { - #[inline] - fn as_ref(&self) -> &[u8] { - self.deref() - } -} - -impl AsMut<[u8]> for Data { - #[inline] - fn as_mut(&mut self) -> &mut [u8] { - self.deref_mut() - } -} - -impl PartialEq for Data { - fn eq(&self, other: &Self) -> bool { - self.as_ref() == other.as_ref() - } -} - -impl Eq for Data {} - -#[cfg(feature = "defmt")] -impl defmt::Format for Data { - fn format(&self, fmt: defmt::Formatter<'_>) { - self.as_ref().format(fmt) - } -} - -macro_rules! data_from_array { - ( $($len:literal),+ ) => { - $( - impl From<[u8; $len]> for Data { - #[inline] - fn from(arr: [u8; $len]) -> Self { - let mut bytes = [0; 8]; - bytes[..$len].copy_from_slice(&arr); - Self { - len: $len, - bytes, - } - } - } - )+ - }; -} - -data_from_array!(0, 1, 2, 3, 4, 5, 6, 7, 8); diff --git a/embassy-stm32/src/can/bx/id.rs b/embassy-stm32/src/can/bx/id.rs deleted file mode 100644 index 9fdcd8319..000000000 --- a/embassy-stm32/src/can/bx/id.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! CAN Identifiers. - -/// Standard 11-bit CAN Identifier (`0..=0x7FF`). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct StandardId(u16); - -impl StandardId { - /// CAN ID `0`, the highest priority. - pub const ZERO: Self = Self(0); - - /// CAN ID `0x7FF`, the lowest priority. - pub const MAX: Self = Self(0x7FF); - - /// Tries to create a `StandardId` from a raw 16-bit integer. - /// - /// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`). - #[inline] - pub const fn new(raw: u16) -> Option { - if raw <= 0x7FF { - Some(Self(raw)) - } else { - None - } - } - - /// Creates a new `StandardId` without checking if it is inside the valid range. - /// - /// # Safety - /// - /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is - /// undefined. - #[inline] - pub const unsafe fn new_unchecked(raw: u16) -> Self { - Self(raw) - } - - /// Returns this CAN Identifier as a raw 16-bit integer. - #[inline] - pub fn as_raw(&self) -> u16 { - self.0 - } -} - -/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct ExtendedId(u32); - -impl ExtendedId { - /// CAN ID `0`, the highest priority. - pub const ZERO: Self = Self(0); - - /// CAN ID `0x1FFFFFFF`, the lowest priority. - pub const MAX: Self = Self(0x1FFF_FFFF); - - /// Tries to create a `ExtendedId` from a raw 32-bit integer. - /// - /// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`). - #[inline] - pub const fn new(raw: u32) -> Option { - if raw <= 0x1FFF_FFFF { - Some(Self(raw)) - } else { - None - } - } - - /// Creates a new `ExtendedId` without checking if it is inside the valid range. - /// - /// # Safety - /// - /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is - /// undefined. - #[inline] - pub const unsafe fn new_unchecked(raw: u32) -> Self { - Self(raw) - } - - /// Returns this CAN Identifier as a raw 32-bit integer. - #[inline] - pub fn as_raw(&self) -> u32 { - self.0 - } - - /// Returns the Base ID part of this extended identifier. - pub fn standard_id(&self) -> StandardId { - // ID-28 to ID-18 - StandardId((self.0 >> 18) as u16) - } -} - -/// A CAN Identifier (standard or extended). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Id { - /// Standard 11-bit Identifier (`0..=0x7FF`). - Standard(StandardId), - - /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`). - Extended(ExtendedId), -} - -impl From for Id { - #[inline] - fn from(id: StandardId) -> Self { - Id::Standard(id) - } -} - -impl From for Id { - #[inline] - fn from(id: ExtendedId) -> Self { - Id::Extended(id) - } -} diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index f639260a1..650d4414b 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -25,19 +25,26 @@ //mod embedded_hal; pub mod filter; -mod frame; -mod id; #[allow(clippy::all)] // generated code use core::cmp::{Ord, Ordering}; -use core::convert::{Infallible, TryInto}; +use core::convert::{Infallible, Into, TryInto}; use core::marker::PhantomData; use core::mem; -pub use id::{ExtendedId, Id, StandardId}; +pub use embedded_can::{ExtendedId, Id, StandardId}; + +/// CAN Header: includes ID and length +pub type Header = crate::can::frame::Header; + +/// Data for a CAN Frame +pub type Data = crate::can::frame::ClassicData; + +/// CAN Frame +pub type Frame = crate::can::frame::ClassicFrame; use crate::can::bx::filter::MasterFilters; -pub use crate::can::bx::frame::{Data, Frame, FramePriority}; +use crate::can::frame::ClassicData; /// A bxCAN peripheral instance. /// @@ -148,13 +155,13 @@ impl IdReg { /// Sets the remote transmission (RTR) flag. This marks the identifier as /// being part of a remote frame. #[must_use = "returns a new IdReg without modifying `self`"] - fn with_rtr(self, rtr: bool) -> IdReg { + /*fn with_rtr(self, rtr: bool) -> IdReg { if rtr { Self(self.0 | Self::RTR_MASK) } else { Self(self.0 & !Self::RTR_MASK) } - } + }*/ /// Returns the identifier. fn to_id(self) -> Id { @@ -165,15 +172,28 @@ impl IdReg { } } + /// Returns the identifier. + fn id(self) -> embedded_can::Id { + if self.is_extended() { + embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT) + .unwrap() + .into() + } else { + embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16) + .unwrap() + .into() + } + } + /// Returns `true` if the identifier is an extended identifier. fn is_extended(self) -> bool { self.0 & Self::IDE_MASK != 0 } /// Returns `true` if the identifier is a standard identifier. - fn is_standard(self) -> bool { + /*fn is_standard(self) -> bool { !self.is_extended() - } + }*/ /// Returns `true` if the identifer is part of a remote frame (RTR bit set). fn rtr(self) -> bool { @@ -181,6 +201,21 @@ impl IdReg { } } +impl From<&embedded_can::Id> for IdReg { + fn from(eid: &embedded_can::Id) -> Self { + match eid { + embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()), + embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()), + } + } +} + +impl From for embedded_can::Id { + fn from(idr: IdReg) -> Self { + idr.id() + } +} + /// `IdReg` is ordered by priority. impl Ord for IdReg { fn cmp(&self, other: &Self) -> Ordering { @@ -682,9 +717,9 @@ where // The controller schedules pending frames of same priority based on the // mailbox index instead. As a workaround check all pending mailboxes // and only accept higher priority frames. - self.check_priority(0, frame.id)?; - self.check_priority(1, frame.id)?; - self.check_priority(2, frame.id)?; + self.check_priority(0, frame.id().into())?; + self.check_priority(1, frame.id().into())?; + self.check_priority(2, frame.id().into())?; let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); if all_frames_are_pending { @@ -739,14 +774,15 @@ where debug_assert!(idx < 3); let mb = self.canregs.tx(idx); - mb.tdtr().write(|w| w.set_dlc(frame.dlc() as u8)); + mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); mb.tdlr() - .write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[0..4].try_into().unwrap())); + .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); mb.tdhr() - .write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[4..8].try_into().unwrap())); + .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); + let id: IdReg = frame.id().into(); mb.tir().write(|w| { - w.0 = frame.id.0; + w.0 = id.0; w.set_txrq(true); }); } @@ -756,16 +792,17 @@ where debug_assert!(idx < 3); let mb = self.canregs.tx(idx); - // Read back the pending frame. - let mut pending_frame = Frame { - id: IdReg(mb.tir().read().0), - data: Data::empty(), - }; - pending_frame.data.bytes[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); - pending_frame.data.bytes[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); - pending_frame.data.len = mb.tdtr().read().dlc(); - Some(pending_frame) + let id = IdReg(mb.tir().read().0).id(); + let mut data = [0xff; 8]; + data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); + data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); + let len = mb.tdtr().read().dlc(); + + Some(Frame::new( + Header::new(id, len, false), + ClassicData::new(&data).unwrap(), + )) } else { // Abort request failed because the frame was already sent (or being sent) on // the bus. All mailboxes are now free. This can happen for small prescaler @@ -898,18 +935,19 @@ fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result Can<'d, T> { } let rir = fifo.rir().read(); - let id = if rir.ide() == Ide::STANDARD { - Id::from(StandardId::new_unchecked(rir.stid())) + let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { + embedded_can::StandardId::new(rir.stid()).unwrap().into() } else { let stid = (rir.stid() & 0x7FF) as u32; let exid = rir.exid() & 0x3FFFF; let id = (stid << 18) | (exid); - Id::from(ExtendedId::new_unchecked(id)) + embedded_can::ExtendedId::new(id).unwrap().into() }; - let data_len = fifo.rdtr().read().dlc() as usize; + let data_len = fifo.rdtr().read().dlc(); let mut data: [u8; 8] = [0; 8]; data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); - let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); + let frame = Frame::new(Header::new(id, data_len, false), Data::new(&data).unwrap()); let envelope = Envelope { #[cfg(feature = "time")] ts, diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 8ec09ac12..cce4e5e8d 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -182,7 +182,7 @@ impl Registers { DataLength::Fdcan(len) => len, DataLength::Classic(len) => len, }; - if len as usize > ClassicFrame::MAX_DATA_LEN { + if len as usize > ClassicData::MAX_DATA_LEN { return None; } diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index 9c293035d..0dc74d299 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -9,6 +9,20 @@ pub struct Header { flags: u8, } +#[cfg(feature = "defmt")] +impl defmt::Format for Header { + fn format(&self, fmt: defmt::Formatter<'_>) { + match self.id() { + embedded_can::Id::Standard(id) => { + defmt::write!(fmt, "Can Standard ID={:x} len={}", id.as_raw(), self.len,) + } + embedded_can::Id::Extended(id) => { + defmt::write!(fmt, "Can Extended ID={:x} len={}", id.as_raw(), self.len,) + } + } + } +} + impl Header { const FLAG_RTR: usize = 0; // Remote const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN @@ -54,6 +68,14 @@ impl Header { pub fn bit_rate_switching(&self) -> bool { self.flags.get_bit(Self::FLAG_BRS) } + + /// Get priority of frame + pub(crate) fn priority(&self) -> u32 { + match self.id() { + embedded_can::Id::Standard(id) => (id.as_raw() as u32) << 18, + embedded_can::Id::Extended(id) => id.as_raw(), + } + } } /// Trait for FDCAN frame types, providing ability to construct from a Header @@ -70,11 +92,13 @@ pub trait CanHeader: Sized { /// /// Contains 0 to 8 Bytes of data. #[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ClassicData { - pub(crate) bytes: [u8; 8], + pub(crate) bytes: [u8; Self::MAX_DATA_LEN], } impl ClassicData { + pub(crate) const MAX_DATA_LEN: usize = 8; /// Creates a data payload from a raw byte slice. /// /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or @@ -110,19 +134,34 @@ impl ClassicData { } } +impl From<&[u8]> for ClassicData { + fn from(d: &[u8]) -> Self { + ClassicData::new(d).unwrap() + } +} + /// Frame with up to 8 bytes of data payload as per Classic CAN #[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ClassicFrame { can_header: Header, data: ClassicData, } impl ClassicFrame { - pub(crate) const MAX_DATA_LEN: usize = 8; - /// Create a new CAN classic Frame - pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame { - ClassicFrame { can_header, data } + pub fn new(can_header: Header, data: impl Into) -> ClassicFrame { + ClassicFrame { + can_header, + data: data.into(), + } + } + + /// Creates a new data frame. + pub fn new_data(id: impl Into, data: &[u8]) -> Self { + let eid: embedded_can::Id = id.into(); + let header = Header::new(eid, data.len() as u8, false); + Self::new(header, data) } /// Create new extended frame @@ -181,6 +220,11 @@ impl ClassicFrame { pub fn data(&self) -> &[u8] { &self.data.raw() } + + /// Get priority of frame + pub fn priority(&self) -> u32 { + self.header().priority() + } } impl embedded_can::Frame for ClassicFrame { diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index 00d61096f..a43fb4427 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -46,16 +46,16 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i, 0, 1, 2, 3, 4, 5, 6]); + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]); can.write(&tx_frame).await; match can.read().await { Ok(env) => match env.frame.id() { Id::Extended(id) => { - defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap()); + defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data()); } Id::Standard(id) => { - defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap()); + defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data()); } }, Err(err) => { diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index b20af8cf1..2ed631a46 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs @@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]); let tx_ts = Instant::now(); can.write(&tx_frame).await; @@ -65,7 +65,7 @@ async fn main(_spawner: Spawner) { info!( "loopback frame {=u8}, latency: {} us", - unwrap!(envelope.frame.data())[0], + envelope.frame.data()[0], latency.as_micros() ); i += 1; diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index c3e14bbf4..2701196ed 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::task] pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { loop { - let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); + let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]); tx.write(&frame).await; embassy_time::Timer::after_secs(1).await; } diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index e869e8fb9..e36137b38 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]); info!("Transmitting frame..."); let tx_ts = Instant::now(); @@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) { info!("Frame received!"); info!("loopback time {}", envelope.ts); - info!("loopback frame {=u8}", envelope.frame.data().unwrap()[0]); + info!("loopback frame {=u8}", envelope.frame.data()[0]); let latency = envelope.ts.saturating_duration_since(tx_ts); info!("loopback latency {} us", latency.as_micros()); From 242759a600418aaaed1bbbec96a9fc7e7effc383 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Tue, 12 Mar 2024 21:19:06 +1000 Subject: [PATCH 691/760] Use Result instead of Option for Frame creation. --- embassy-stm32/src/can/bx/mod.rs | 11 +- embassy-stm32/src/can/bxcan.rs | 2 +- embassy-stm32/src/can/enums.rs | 12 +++ embassy-stm32/src/can/fd/peripheral.rs | 5 +- embassy-stm32/src/can/frame.rs | 140 ++++++++++--------------- examples/stm32f1/src/bin/can.rs | 2 +- examples/stm32f4/src/bin/can.rs | 2 +- examples/stm32f7/src/bin/can.rs | 2 +- tests/stm32/src/bin/can.rs | 2 +- 9 files changed, 78 insertions(+), 100 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 650d4414b..ae8bafaa8 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -44,7 +44,6 @@ pub type Data = crate::can::frame::ClassicData; pub type Frame = crate::can::frame::ClassicFrame; use crate::can::bx::filter::MasterFilters; -use crate::can::frame::ClassicData; /// A bxCAN peripheral instance. /// @@ -799,10 +798,7 @@ where data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); let len = mb.tdtr().read().dlc(); - Some(Frame::new( - Header::new(id, len, false), - ClassicData::new(&data).unwrap(), - )) + Some(Frame::new(Header::new(id, len, false), &data).unwrap()) } else { // Abort request failed because the frame was already sent (or being sent) on // the bus. All mailboxes are now free. This can happen for small prescaler @@ -944,10 +940,7 @@ fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result Can<'d, T> { data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); - let frame = Frame::new(Header::new(id, data_len, false), Data::new(&data).unwrap()); + let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); let envelope = Envelope { #[cfg(feature = "time")] ts, diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 36139a45c..651de9194 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs @@ -28,3 +28,15 @@ pub enum BusError { /// At least one of error counter has reached the Error_Warning limit of 96. BusWarning, } + +/// Frame Create Errors +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum FrameCreateError { + /// Data in header does not match supplied. + NotEnoughData, + /// Invalid data length not 0-8 for Classic packet or valid for FD. + InvalidDataLength, + /// Invalid ID. + InvalidCanId, +} diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index cce4e5e8d..e14977d91 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -56,7 +56,10 @@ impl Registers { match maybe_header { Some((header, ts)) => { let data = &buffer[0..header.len() as usize]; - Some((F::from_header(header, data)?, ts)) + match F::from_header(header, data) { + Ok(frame) => Some((frame, ts)), + Err(_) => None, + } } None => None, } diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index 0dc74d299..14fc32c51 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -1,6 +1,8 @@ //! Definition for CAN Frames use bit_field::BitField; +use crate::can::enums::FrameCreateError; + /// CAN Header, without meta data #[derive(Debug, Copy, Clone)] pub struct Header { @@ -82,7 +84,7 @@ impl Header { /// and to retrieve the Header from a frame pub trait CanHeader: Sized { /// Construct frame from header and payload - fn from_header(header: Header, data: &[u8]) -> Option; + fn from_header(header: Header, data: &[u8]) -> Result; /// Get this frame's header struct fn header(&self) -> &Header; @@ -103,15 +105,15 @@ impl ClassicData { /// /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or /// cannot be represented with an FDCAN DLC. - pub fn new(data: &[u8]) -> Option { - if !FdData::is_valid_len(data.len()) { - return None; + pub fn new(data: &[u8]) -> Result { + if data.len() > 8 { + return Err(FrameCreateError::InvalidDataLength); } let mut bytes = [0; 8]; bytes[..data.len()].copy_from_slice(data); - Some(Self { bytes }) + Ok(Self { bytes }) } /// Raw read access to data. @@ -134,12 +136,6 @@ impl ClassicData { } } -impl From<&[u8]> for ClassicData { - fn from(d: &[u8]) -> Self { - ClassicData::new(d).unwrap() - } -} - /// Frame with up to 8 bytes of data payload as per Classic CAN #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -150,59 +146,42 @@ pub struct ClassicFrame { impl ClassicFrame { /// Create a new CAN classic Frame - pub fn new(can_header: Header, data: impl Into) -> ClassicFrame { - ClassicFrame { - can_header, - data: data.into(), - } + pub fn new(can_header: Header, raw_data: &[u8]) -> Result { + let data = ClassicData::new(raw_data)?; + Ok(ClassicFrame { can_header, data: data }) } /// Creates a new data frame. - pub fn new_data(id: impl Into, data: &[u8]) -> Self { + pub fn new_data(id: impl Into, data: &[u8]) -> Result { let eid: embedded_can::Id = id.into(); let header = Header::new(eid, data.len() as u8, false); Self::new(header, data) } /// Create new extended frame - pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option { + pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result { if let Some(id) = embedded_can::ExtendedId::new(raw_id) { - match ClassicData::new(raw_data) { - Some(data) => Some(ClassicFrame::new( - Header::new(id.into(), raw_data.len() as u8, false), - data, - )), - None => None, - } + Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data) } else { - None + Err(FrameCreateError::InvalidCanId) } } /// Create new standard frame - pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option { + pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result { if let Some(id) = embedded_can::StandardId::new(raw_id) { - match ClassicData::new(raw_data) { - Some(data) => Some(ClassicFrame::new( - Header::new(id.into(), raw_data.len() as u8, false), - data, - )), - None => None, - } + Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data) } else { - None + Err(FrameCreateError::InvalidCanId) } } /// Create new remote frame - pub fn new_remote(id: impl Into, len: usize) -> Option { + pub fn new_remote(id: impl Into, len: usize) -> Result { if len <= 8usize { - Some(ClassicFrame::new( - Header::new(id.into(), len as u8, true), - ClassicData::empty(), - )) + Self::new(Header::new(id.into(), len as u8, true), &[0; 8]) } else { - None + Err(FrameCreateError::InvalidDataLength) } } @@ -229,20 +208,19 @@ impl ClassicFrame { impl embedded_can::Frame for ClassicFrame { fn new(id: impl Into, raw_data: &[u8]) -> Option { - match ClassicData::new(raw_data) { - Some(data) => Some(ClassicFrame::new( - Header::new(id.into(), raw_data.len() as u8, false), - data, - )), - None => None, + let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data); + match frameopt { + Ok(frame) => Some(frame), + Err(_) => None, } } fn new_remote(id: impl Into, len: usize) -> Option { if len <= 8 { - Some(ClassicFrame::new( - Header::new(id.into(), len as u8, true), - ClassicData::empty(), - )) + let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]); + match frameopt { + Ok(frame) => Some(frame), + Err(_) => None, + } } else { None } @@ -268,8 +246,8 @@ impl embedded_can::Frame for ClassicFrame { } impl CanHeader for ClassicFrame { - fn from_header(header: Header, data: &[u8]) -> Option { - Some(Self::new(header, ClassicData::new(data)?)) + fn from_header(header: Header, data: &[u8]) -> Result { + Self::new(header, data) } fn header(&self) -> &Header { @@ -290,15 +268,15 @@ impl FdData { /// /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or /// cannot be represented with an FDCAN DLC. - pub fn new(data: &[u8]) -> Option { + pub fn new(data: &[u8]) -> Result { if !FdData::is_valid_len(data.len()) { - return None; + return Err(FrameCreateError::InvalidDataLength); } let mut bytes = [0; 64]; bytes[..data.len()].copy_from_slice(data); - Some(Self { bytes }) + Ok(Self { bytes }) } /// Raw read access to data. @@ -337,40 +315,35 @@ pub struct FdFrame { impl FdFrame { /// Create a new CAN classic Frame - pub fn new(can_header: Header, data: FdData) -> FdFrame { - FdFrame { can_header, data } + pub fn new(can_header: Header, raw_data: &[u8]) -> Result { + let data = FdData::new(raw_data)?; + Ok(FdFrame { can_header, data }) } /// Create new extended frame - pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option { + pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result { if let Some(id) = embedded_can::ExtendedId::new(raw_id) { - match FdData::new(raw_data) { - Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), - None => None, - } + Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data) } else { - None + Err(FrameCreateError::InvalidCanId) } } /// Create new standard frame - pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option { + pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result { if let Some(id) = embedded_can::StandardId::new(raw_id) { - match FdData::new(raw_data) { - Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), - None => None, - } + Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data) } else { - None + Err(FrameCreateError::InvalidCanId) } } /// Create new remote frame - pub fn new_remote(id: impl Into, len: usize) -> Option { + pub fn new_remote(id: impl Into, len: usize) -> Result { if len <= 8 { - Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty())) + Self::new(Header::new(id.into(), len as u8, true), &[0; 8]) } else { - None + Err(FrameCreateError::InvalidDataLength) } } @@ -392,20 +365,17 @@ impl FdFrame { impl embedded_can::Frame for FdFrame { fn new(id: impl Into, raw_data: &[u8]) -> Option { - match FdData::new(raw_data) { - Some(data) => Some(FdFrame::new( - Header::new_fd(id.into(), raw_data.len() as u8, false, true), - data, - )), - None => None, + match FdFrame::new(Header::new_fd(id.into(), raw_data.len() as u8, false, true), raw_data) { + Ok(frame) => Some(frame), + Err(_) => None, } } fn new_remote(id: impl Into, len: usize) -> Option { if len <= 8 { - Some(FdFrame::new( - Header::new_fd(id.into(), len as u8, true, true), - FdData::empty(), - )) + match FdFrame::new(Header::new_fd(id.into(), len as u8, true, true), &[0; 64]) { + Ok(frame) => Some(frame), + Err(_) => None, + } } else { None } @@ -432,8 +402,8 @@ impl embedded_can::Frame for FdFrame { } impl CanHeader for FdFrame { - fn from_header(header: Header, data: &[u8]) -> Option { - Some(Self::new(header, FdData::new(data)?)) + fn from_header(header: Header, data: &[u8]) -> Result { + Self::new(header, data) } fn header(&self) -> &Header { diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index a43fb4427..ac337e8a0 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]); + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); can.write(&tx_frame).await; match can.read().await { diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index 2ed631a46..71b9453eb 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs @@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]); + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap(); let tx_ts = Instant::now(); can.write(&tx_frame).await; diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 2701196ed..221ac2a05 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::task] pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { loop { - let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]); + let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap(); tx.write(&frame).await; embassy_time::Timer::after_secs(1).await; } diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index e36137b38..c08c69a3b 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]); + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap(); info!("Transmitting frame..."); let tx_ts = Instant::now(); From 535e4c20e88f131189241bcf1625ff7c32e0443b Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 14 Mar 2024 08:21:45 +1000 Subject: [PATCH 692/760] Remove unused methods including incorrect #[must_use... --- embassy-stm32/src/can/bx/mod.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index ae8bafaa8..33e702c6e 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -151,17 +151,6 @@ impl IdReg { Self(reg & 0xFFFF_FFFE) } - /// Sets the remote transmission (RTR) flag. This marks the identifier as - /// being part of a remote frame. - #[must_use = "returns a new IdReg without modifying `self`"] - /*fn with_rtr(self, rtr: bool) -> IdReg { - if rtr { - Self(self.0 | Self::RTR_MASK) - } else { - Self(self.0 & !Self::RTR_MASK) - } - }*/ - /// Returns the identifier. fn to_id(self) -> Id { if self.is_extended() { @@ -189,11 +178,6 @@ impl IdReg { self.0 & Self::IDE_MASK != 0 } - /// Returns `true` if the identifier is a standard identifier. - /*fn is_standard(self) -> bool { - !self.is_extended() - }*/ - /// Returns `true` if the identifer is part of a remote frame (RTR bit set). fn rtr(self) -> bool { self.0 & Self::RTR_MASK != 0 From 9f699e5772815d95da473dcec4f4f574e2659e06 Mon Sep 17 00:00:00 2001 From: Vo Trung Chi Date: Thu, 14 Mar 2024 23:02:22 +0700 Subject: [PATCH 693/760] stm32: add usb_hid_keyboard example Signed-off-by: Vo Trung Chi --- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 222 +++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 examples/stm32f4/src/bin/usb_hid_keyboard.rs diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs new file mode 100644 index 000000000..19b5971fb --- /dev/null +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -0,0 +1,222 @@ +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::Pull; +use embassy_stm32::time::Hertz; +use embassy_stm32::usb_otg::Driver; +use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; +use embassy_usb::control::OutResponse; +use embassy_usb::{Builder, Handler}; +use futures::future::join; +use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + OTG_FS => usb_otg::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL168, + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. + divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV4; + config.rcc.apb2_pre = APBPrescaler::DIV2; + config.rcc.sys = Sysclk::PLL1_P; + } + let p = embassy_stm32::init(config); + + // Create the driver, from the HAL. + let mut ep_out_buffer = [0u8; 256]; + let mut config = embassy_stm32::usb_otg::Config::default(); + config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); + + // Create embassy-usb Config + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("HID keyboard example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + // You can also add a Microsoft OS descriptor. + let mut msos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let request_handler = MyRequestHandler {}; + let mut device_handler = MyDeviceHandler::new(); + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut msos_descriptor, + &mut control_buf, + ); + + builder.handler(&mut device_handler); + + // Create classes on the builder. + let config = embassy_usb::class::hid::Config { + report_descriptor: KeyboardReport::desc(), + request_handler: Some(&request_handler), + poll_ms: 60, + max_packet_size: 8, + }; + + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + let (reader, mut writer) = hid.split(); + + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); + + // Do stuff with the class! + let in_fut = async { + loop { + button.wait_for_rising_edge().await; + // signal_pin.wait_for_high().await; + info!("Button pressed!"); + // Create a report with the A key pressed. (no shift modifier) + let report = KeyboardReport { + keycodes: [4, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + // Send the report. + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + + button.wait_for_falling_edge().await; + // signal_pin.wait_for_low().await; + info!("Button released!"); + let report = KeyboardReport { + keycodes: [0, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } + }; + + let out_fut = async { + reader.run(false, &request_handler).await; + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, join(in_fut, out_fut)).await; +} + +struct MyRequestHandler {} + +impl RequestHandler for MyRequestHandler { + fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + info!("Get report for {:?}", id); + None + } + + fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + info!("Set report for {:?}: {=[u8]}", id, data); + OutResponse::Accepted + } + + fn set_idle_ms(&self, id: Option, dur: u32) { + info!("Set idle rate for {:?} to {:?}", id, dur); + } + + fn get_idle_ms(&self, id: Option) -> Option { + info!("Get idle rate for {:?}", id); + None + } +} + +struct MyDeviceHandler { + configured: AtomicBool, +} + +impl MyDeviceHandler { + fn new() -> Self { + MyDeviceHandler { + configured: AtomicBool::new(false), + } + } +} + +impl Handler for MyDeviceHandler { + fn enabled(&mut self, enabled: bool) { + self.configured.store(false, Ordering::Relaxed); + if enabled { + info!("Device enabled"); + } else { + info!("Device disabled"); + } + } + + fn reset(&mut self) { + self.configured.store(false, Ordering::Relaxed); + info!("Bus reset, the Vbus current limit is 100mA"); + } + + fn addressed(&mut self, addr: u8) { + self.configured.store(false, Ordering::Relaxed); + info!("USB address set to: {}", addr); + } + + fn configured(&mut self, configured: bool) { + self.configured.store(configured, Ordering::Relaxed); + if configured { + info!("Device configured, it may now draw up to the configured current limit from Vbus.") + } else { + info!("Device is no longer configured, the Vbus current limit is 100mA."); + } + } +} From e95e95ac7a00ca014b23f6ac57ecffce7fc6ffa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Tue, 12 Mar 2024 20:38:37 +0100 Subject: [PATCH 694/760] [UCPD] Take interrupt in constructor and enable it --- embassy-stm32/src/ucpd.rs | 6 ++++++ examples/stm32g4/src/bin/usb_c_pd.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 51cfe4a24..b7af877b7 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -24,6 +24,7 @@ use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; use crate::interrupt; +use crate::interrupt::typelevel::Interrupt; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; use crate::rcc::RccPeripheral; @@ -93,10 +94,13 @@ impl<'d, T: Instance> Ucpd<'d, T> { /// Creates a new UCPD driver instance. pub fn new( _peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, _cc1: impl Peripheral

> + 'd, _cc2: impl Peripheral

> + 'd, ) -> Self { T::enable_and_reset(); + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; let r = T::REGS; r.cfgr1().write(|w| { @@ -206,6 +210,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> { } else { r.cfgr1().write(|w| w.set_ucpden(false)); T::disable(); + T::Interrupt::disable(); } } } @@ -323,6 +328,7 @@ impl<'d, T: Instance> Drop for PdPhy<'d, T> { } else { r.cfgr1().write(|w| w.set_ucpden(false)); T::disable(); + T::Interrupt::disable(); } } } diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 0e80840df..c850b2753 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -4,10 +4,14 @@ use defmt::{error, info, Format}; use embassy_executor::Spawner; use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; -use embassy_stm32::Config; +use embassy_stm32::{bind_interrupts, peripherals, Config}; use embassy_time::{with_timeout, Duration}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UCPD1 => ucpd::InterruptHandler; +}); + #[derive(Debug, Format)] enum CableOrientation { Normal, @@ -50,7 +54,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let mut ucpd = Ucpd::new(p.UCPD1, p.PB6, p.PB4); + let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4); ucpd.cc_phy().set_pull(CcPull::Sink); info!("Waiting for USB connection..."); From 6e5bb8003acf98e20592dd1e86fc1a5f1928e14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Tue, 12 Mar 2024 20:40:00 +0100 Subject: [PATCH 695/760] [UCPD] Adjust TX clock divider --- embassy-stm32/src/ucpd.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index b7af877b7..01cf42672 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -112,10 +112,8 @@ impl<'d, T: Instance> Ucpd<'d, T> { // Prescaler to produce a target half-bit frequency of 600kHz which is required // to produce transmit with a nominal nominal bit rate of 300Kbps+-10% using // biphase mark coding (BMC, aka differential manchester coding). - // A divider of 13 gives the target frequency closest to spec (~615kHz, 1.625us) - // but we go with the (hopefully well tested) default value used by the Cube HAL - // which is 14 divides the clock down to ~571kHz, 1.75us. - w.set_hbitclkdiv(14 - 1); + // A divider of 13 gives the target frequency closest to spec (~615kHz, 1.625us). + w.set_hbitclkdiv(13 - 1); // Time window for detecting non-idle (12-20us). // 1.75us * 8 = 14us. From b634f8f5111001a51a8a80559aeab11e8209d65f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Tue, 12 Mar 2024 20:40:47 +0100 Subject: [PATCH 696/760] [UCPD] Fix hard reset interrupt disable flags --- embassy-stm32/src/ucpd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 01cf42672..54d4bb132 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -484,8 +484,8 @@ impl<'d, T: Instance> PdPhy<'d, T> { // Clear the hardreset interrupt flags. T::REGS.icr().write(|w| { - w.set_txmsgdisccf(true); - w.set_txmsgsentcf(true); + w.set_hrstdisccf(true); + w.set_hrstsentcf(true); }); // Trigger hard reset transmission. From 88d1d38be787ff7e742dfde53cf8b527a6a07dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Tue, 12 Mar 2024 22:43:36 +0100 Subject: [PATCH 697/760] [UCPD] RXORDSETEN can only be modified when disabled --- embassy-stm32/src/ucpd.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 54d4bb132..d251b1c72 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -124,6 +124,14 @@ impl<'d, T: Instance> Ucpd<'d, T> { // 1.75us * 17 = ~30us w.set_ifrgap(17 - 1); + // TODO: Currently only hard reset and SOP messages can be received. + // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing). + w.set_rxordseten(0b1001); + + // Enable DMA + w.set_txdmaen(true); + w.set_rxdmaen(true); + w.set_ucpden(true); }); @@ -150,15 +158,6 @@ impl<'d, T: Instance> Ucpd<'d, T> { // TODO: Currently only SOP messages are supported. r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); - r.cfgr1().modify(|w| { - // TODO: Currently only hard reset and SOP messages can be received. - w.set_rxordseten(0b1001); - - // Enable DMA - w.set_txdmaen(true); - w.set_rxdmaen(true); - }); - // Enable the receiver on one of the two CC lines. r.cr().modify(|w| { w.set_phyccsel(cc_sel); @@ -216,7 +215,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> { impl<'d, T: Instance> CcPhy<'d, T> { /// Sets the pull-up/pull-down resistor values exposed on the CC pins. pub fn set_pull(&mut self, cc_pull: CcPull) { - T::REGS.cr().write(|w| { + T::REGS.cr().modify(|w| { w.set_anamode(if cc_pull == CcPull::Sink { Anamode::SINK } else { From 62b0410e865044080781765d9ccee06202a82dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Wed, 13 Mar 2024 17:45:15 +0100 Subject: [PATCH 698/760] [UCPD] Set CC pins to analog mode Example: On STM32G431 CC2 has a pull-up (default JTAG signal) which needs to be disabled. --- embassy-stm32/src/ucpd.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index d251b1c72..dcc4454d3 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -95,9 +95,13 @@ impl<'d, T: Instance> Ucpd<'d, T> { pub fn new( _peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - _cc1: impl Peripheral

> + 'd, - _cc2: impl Peripheral

> + 'd, + cc1: impl Peripheral

> + 'd, + cc2: impl Peripheral

> + 'd, ) -> Self { + into_ref!(cc1, cc2); + cc1.set_as_analog(); + cc2.set_as_analog(); + T::enable_and_reset(); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; From 57ca072dc3807a868415d91b39f814c30c2e844b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 14 Mar 2024 22:05:22 +0100 Subject: [PATCH 699/760] [UCPD] Enable RX PHY only when receiving --- embassy-stm32/src/ucpd.rs | 61 +++++++++++++++------------------------ 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index dcc4454d3..2d119c973 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -163,10 +163,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); // Enable the receiver on one of the two CC lines. - r.cr().modify(|w| { - w.set_phyccsel(cc_sel); - w.set_phyrxen(true); - }); + r.cr().modify(|w| w.set_phyccsel(cc_sel)); // Enable hard reset receive interrupt. r.imr().modify(|w| w.set_rxhrstdetie(true)); @@ -319,15 +316,12 @@ pub struct PdPhy<'d, T: Instance> { impl<'d, T: Instance> Drop for PdPhy<'d, T> { fn drop(&mut self) { - let r = T::REGS; - r.cr().modify(|w| w.set_phyrxen(false)); - // Check if the Type-C part was dropped already. let drop_not_ready = &T::state().drop_not_ready; if drop_not_ready.load(Ordering::Relaxed) { drop_not_ready.store(true, Ordering::Relaxed); } else { - r.cfgr1().write(|w| w.set_ucpden(false)); + T::REGS.cfgr1().write(|w| w.set_ucpden(false)); T::disable(); T::Interrupt::disable(); } @@ -341,16 +335,6 @@ impl<'d, T: Instance> PdPhy<'d, T> { pub async fn receive(&mut self, buf: &mut [u8]) -> Result { let r = T::REGS; - // Check if a message is already being received. If yes, wait until its - // done, ignore errors and try to receive the next message. - if r.sr().read().rxorddet() { - if let Err(RxError::HardReset) = self.wait_rx_done().await { - return Err(RxError::HardReset); - } - r.rxdr().read(); // Clear the RX buffer. - } - - // Keep the DMA transfer alive so its drop code does not stop it right away. let dma = unsafe { Transfer::new_read( &self.rx_dma_ch, @@ -361,22 +345,20 @@ impl<'d, T: Instance> PdPhy<'d, T> { ) }; - self.wait_rx_done().await?; + // Clear interrupt flags (possibly set from last receive). + r.icr().write(|w| { + w.set_rxorddetcf(true); + w.set_rxovrcf(true); + w.set_rxmsgendcf(true); + }); - // Make sure the the last byte to byte was fetched by DMA. - while r.sr().read().rxne() { - if dma.get_remaining_transfers() == 0 { - return Err(RxError::Overrun); - } - } + r.cr().modify(|w| w.set_phyrxen(true)); + let _on_drop = OnDrop::new(|| { + r.cr().modify(|w| w.set_phyrxen(false)); + self.enable_rx_interrupt(false); + }); - Ok(r.rx_payszr().read().rxpaysz().into()) - } - - async fn wait_rx_done(&self) -> Result<(), RxError> { - let _on_drop = OnDrop::new(|| self.enable_rx_interrupt(false)); poll_fn(|cx| { - let r = T::REGS; let sr = r.sr().read(); if sr.rxhrstdet() { // Clean and re-enable hard reset receive interrupt. @@ -391,12 +373,6 @@ impl<'d, T: Instance> PdPhy<'d, T> { } else { Ok(()) }; - // Message received, clear interrupt flags. - r.icr().write(|w| { - w.set_rxorddetcf(true); - w.set_rxovrcf(true); - w.set_rxmsgendcf(true); - }); Poll::Ready(ret) } else { T::state().waker.register(cx.waker()); @@ -404,7 +380,16 @@ impl<'d, T: Instance> PdPhy<'d, T> { Poll::Pending } }) - .await + .await?; + + // Make sure that the last byte was fetched by DMA. + while r.sr().read().rxne() { + if dma.get_remaining_transfers() == 0 { + return Err(RxError::Overrun); + } + } + + Ok(r.rx_payszr().read().rxpaysz().into()) } fn enable_rx_interrupt(&self, enable: bool) { From 7b80de5e3db69a3d348bc74f6294e8642a11785e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Thu, 14 Mar 2024 22:14:20 +0100 Subject: [PATCH 700/760] [UCPD] Enable dead-battery support in example --- examples/stm32g4/src/bin/usb_c_pd.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index c850b2753..7caea634f 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -49,8 +49,9 @@ async fn wait_attached(cc_phy: &mut CcPhy<'_, T>) -> CableOri #[embassy_executor::main] async fn main(_spawner: Spawner) { - // TODO: Disable DBCC pin functionality by default but have flag in the config to keep it enabled when required. - let p = embassy_stm32::init(Config::default()); + let mut config = Config::default(); + config.enable_ucpd1_dead_battery = true; + let p = embassy_stm32::init(config); info!("Hello World!"); From 47b97581513bcb1917e515acfaf5e17ccd1b5d18 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Fri, 15 Mar 2024 21:38:32 +0800 Subject: [PATCH 701/760] feat: impl `MultiwriteNorFlash` for `BlockingAsync` Signed-off-by: Haobo Gu --- embassy-embedded-hal/src/adapter/blocking_async.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-embedded-hal/src/adapter/blocking_async.rs b/embassy-embedded-hal/src/adapter/blocking_async.rs index ae0d0a7f9..bafc31583 100644 --- a/embassy-embedded-hal/src/adapter/blocking_async.rs +++ b/embassy-embedded-hal/src/adapter/blocking_async.rs @@ -104,8 +104,10 @@ where } /// NOR flash wrapper -use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; -use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; +use embedded_storage::nor_flash::{ErrorType, MultiwriteNorFlash, NorFlash, ReadNorFlash}; +use embedded_storage_async::nor_flash::{ + MultiwriteNorFlash as AsyncMultiwriteNorFlash, NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash, +}; impl ErrorType for BlockingAsync where @@ -143,3 +145,5 @@ where self.wrapped.capacity() } } + +impl AsyncMultiwriteNorFlash for BlockingAsync where T: MultiwriteNorFlash {} From 21e2499f353c995d71710a2ed62d6f3914d6d60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Fri, 15 Mar 2024 17:44:27 +0100 Subject: [PATCH 702/760] [UCPD] Fix dead-battery disable for G0 Inverted flag got missed in the original PR. --- embassy-stm32/src/ucpd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 2d119c973..9c37d2c04 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -42,8 +42,8 @@ pub(crate) fn init( // strobe will apply the CC pin configuration from the control register // (which is why we need to be careful about when we call this) crate::pac::SYSCFG.cfgr1().modify(|w| { - w.set_ucpd1_strobe(ucpd1_db_enable); - w.set_ucpd2_strobe(ucpd2_db_enable); + w.set_ucpd1_strobe(!ucpd1_db_enable); + w.set_ucpd2_strobe(!ucpd2_db_enable); }); } From 067e677ae5c3c765bca1db6e4cb7aef5de163086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kro=CC=88ger?= Date: Fri, 15 Mar 2024 17:45:48 +0100 Subject: [PATCH 703/760] [UCPD] Add unit test for stm32g071rb board One test for changing the CC line pull-up resistor is skipped for now. --- tests/stm32/Cargo.toml | 8 ++- tests/stm32/src/bin/ucpd.rs | 119 ++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 tests/stm32/src/bin/ucpd.rs diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bfe003a11..0332fc526 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -13,7 +13,7 @@ stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] -stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] +stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] @@ -47,6 +47,7 @@ mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] embassy-stm32-wpan = [] not-gpdma = [] dac = [] +ucpd = [] cm0 = ["portable-atomic/unsafe-assume-single-core"] @@ -160,6 +161,11 @@ name = "timer" path = "src/bin/timer.rs" required-features = [] +[[bin]] +name = "ucpd" +path = "src/bin/ucpd.rs" +required-features = [] + [[bin]] name = "usart" path = "src/bin/usart.rs" diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs new file mode 100644 index 000000000..daaa56c32 --- /dev/null +++ b/tests/stm32/src/bin/ucpd.rs @@ -0,0 +1,119 @@ +#![no_std] +#![no_main] +#[path = "../common.rs"] +mod common; + +use common::*; +use defmt::{assert, assert_eq}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, RxError, Ucpd}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_time::Timer; + +bind_interrupts!(struct Irqs { + UCPD1_2 => ucpd::InterruptHandler, ucpd::InterruptHandler; +}); + +static SRC_TO_SNK: [u8; 6] = [0, 1, 2, 3, 4, 5]; +static SNK_TO_SRC: [u8; 4] = [9, 8, 7, 6]; + +async fn wait_for_vstate(cc_phy: &mut CcPhy<'_, T>, vstate: CcVState) { + let (mut cc1, mut _cc2) = cc_phy.vstate(); + while cc1 != vstate { + (cc1, _cc2) = cc_phy.wait_for_vstate_change().await; + } +} + +async fn source( + mut ucpd: Ucpd<'static, peripherals::UCPD1>, + rx_dma: peripherals::DMA1_CH1, + tx_dma: peripherals::DMA1_CH2, +) { + debug!("source: setting default current pull-up"); + ucpd.cc_phy().set_pull(CcPull::SourceDefaultUsb); + + // Wait for default sink. + debug!("source: wait for sink"); + wait_for_vstate(ucpd.cc_phy(), CcVState::LOW).await; + + // Advertise a higher current by changing the pull-up resistor. + debug!("source: sink detected, setting 3.0A current pull-up"); + ucpd.cc_phy().set_pull(CcPull::Source3_0A); + + let (_, mut pd_phy) = ucpd.split_pd_phy(rx_dma, tx_dma, CcSel::CC1); + + // Listen for an incoming message + debug!("source: wait for message from sink"); + let mut snk_to_src_buf = [0_u8; 30]; + let n = unwrap!(pd_phy.receive(snk_to_src_buf.as_mut()).await); + assert_eq!(n, SNK_TO_SRC.len()); + assert_eq!(&snk_to_src_buf[..n], SNK_TO_SRC.as_slice()); + + // Send message + debug!("source: message received, sending message"); + unwrap!(pd_phy.transmit(SRC_TO_SNK.as_slice()).await); + + // Wait for hard-reset + debug!("source: message sent, waiting for hard-reset"); + assert!(matches!( + pd_phy.receive(snk_to_src_buf.as_mut()).await, + Err(RxError::HardReset) + )); +} + +async fn sink( + mut ucpd: Ucpd<'static, peripherals::UCPD2>, + rx_dma: peripherals::DMA1_CH3, + tx_dma: peripherals::DMA1_CH4, +) { + debug!("sink: setting pull down"); + ucpd.cc_phy().set_pull(CcPull::Sink); + + // Wait for default source. + debug!("sink: waiting for default vstate"); + wait_for_vstate(ucpd.cc_phy(), CcVState::LOW).await; + + // Wait higher current pull-up. + //debug!("sink: source default vstate detected, waiting for 3.0A vstate"); + //wait_for_vstate(ucpd.cc_phy(), CcVState::HIGHEST).await; + //debug!("sink: source 3.0A vstate detected"); + // TODO: not working yet, why? no idea, replace with timer for now + Timer::after_millis(100).await; + + let (_, mut pd_phy) = ucpd.split_pd_phy(rx_dma, tx_dma, CcSel::CC1); + + // Send message + debug!("sink: sending message"); + unwrap!(pd_phy.transmit(SNK_TO_SRC.as_slice()).await); + + // Listen for an incoming message + debug!("sink: message sent, waiting for message from source"); + let mut src_to_snk_buf = [0_u8; 30]; + let n = unwrap!(pd_phy.receive(src_to_snk_buf.as_mut()).await); + assert_eq!(n, SRC_TO_SNK.len()); + assert_eq!(&src_to_snk_buf[..n], SRC_TO_SNK.as_slice()); + + // Send hard reset + debug!("sink: message received, sending hard-reset"); + unwrap!(pd_phy.transmit_hardreset().await); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(config()); + info!("Hello World!"); + + // Wire between PD0 and PA8 + let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15); + let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2); + + join( + source(ucpd1, p.DMA1_CH1, p.DMA1_CH2), + sink(ucpd2, p.DMA1_CH3, p.DMA1_CH4), + ) + .await; + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From 0f0301843487a921a5ef57eb8972971181ea0024 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 15 Mar 2024 19:47:05 +0100 Subject: [PATCH 704/760] tests/stm32: run ucpd only on g0. --- tests/stm32/Cargo.toml | 2 +- tests/stm32/src/bin/ucpd.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 0332fc526..e42470004 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -164,7 +164,7 @@ required-features = [] [[bin]] name = "ucpd" path = "src/bin/ucpd.rs" -required-features = [] +required-features = [ "ucpd",] [[bin]] name = "usart" diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs index daaa56c32..c09334ec8 100644 --- a/tests/stm32/src/bin/ucpd.rs +++ b/tests/stm32/src/bin/ucpd.rs @@ -1,3 +1,4 @@ +// required-features: ucpd #![no_std] #![no_main] #[path = "../common.rs"] From 3f5c8784afe2174fd1df8446bd21240608c558e0 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 16 Mar 2024 19:24:47 +1000 Subject: [PATCH 705/760] FDCAN: Fix offset issue preventing CAN2 and CAN3 from working. Fix for not H7 --- embassy-stm32/src/can/fd/peripheral.rs | 7 +++- tests/stm32/src/bin/fdcan.rs | 53 +++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index e14977d91..682e13f4b 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -30,7 +30,12 @@ impl Registers { &mut self.msg_ram_mut().transmit.tbsa[bufidx] } pub fn msg_ram_mut(&self) -> &mut RegisterBlock { + #[cfg(stm32h7)] + let ptr = self.msgram.ram(self.msg_ram_offset / 4).as_ptr() as *mut RegisterBlock; + + #[cfg(not(stm32h7))] let ptr = self.msgram.as_ptr() as *mut RegisterBlock; + unsafe { &mut (*ptr) } } @@ -637,7 +642,7 @@ impl Registers { use crate::can::fd::message_ram::*; //use fdcan::message_ram::*; - let mut offset_words = self.msg_ram_offset as u16; + let mut offset_words = (self.msg_ram_offset / 4) as u16; // 11-bit filter r.sidfc().modify(|w| w.set_flssa(offset_words)); diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index dd78d7fb3..c7373e294 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -13,7 +13,11 @@ use embassy_stm32::{bind_interrupts, can, Config}; use embassy_time::{Duration, Instant}; use {defmt_rtt as _, panic_probe as _}; -bind_interrupts!(struct Irqs { +bind_interrupts!(struct Irqs2 { + FDCAN2_IT0 => can::IT0InterruptHandler; + FDCAN2_IT1 => can::IT1InterruptHandler; +}); +bind_interrupts!(struct Irqs1 { FDCAN1_IT0 => can::IT0InterruptHandler; FDCAN1_IT1 => can::IT1InterruptHandler; }); @@ -75,17 +79,24 @@ async fn main(_spawner: Spawner) { let options = options(); let peripherals = embassy_stm32::init(options.config); - let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); + let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); + let mut can2 = can::FdcanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); // 250k bps can.set_bitrate(250_000); + can2.set_bitrate(250_000); can.set_extended_filter( can::filter::ExtendedFilterSlot::_0, can::filter::ExtendedFilter::accept_all_into_fifo1(), ); + can2.set_extended_filter( + can::filter::ExtendedFilterSlot::_0, + can::filter::ExtendedFilter::accept_all_into_fifo1(), + ); let mut can = can.into_internal_loopback_mode(); + let mut can2 = can2.into_internal_loopback_mode(); info!("CAN Configured"); @@ -126,6 +137,44 @@ async fn main(_spawner: Spawner) { } } + let mut i: u8 = 0; + loop { + let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); + + info!("Transmitting frame..."); + let tx_ts = Instant::now(); + can2.write(&tx_frame).await; + + let (frame, timestamp) = can2.read().await.unwrap(); + info!("Frame received!"); + + //print_regs().await; + // Check data. + assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); + + info!("loopback time {}", timestamp); + info!("loopback frame {=u8}", frame.data()[0]); + let latency = timestamp.saturating_duration_since(tx_ts); + info!("loopback latency {} us", latency.as_micros()); + + // Theoretical minimum latency is 55us, actual is usually ~80us + const MIN_LATENCY: Duration = Duration::from_micros(50); + // Was failing at 150 but we are not getting a real time stamp. I'm not + // sure if there are other delays + assert!( + MIN_LATENCY <= latency && latency <= options.max_latency, + "{} <= {} <= {}", + MIN_LATENCY, + latency, + options.max_latency + ); + + i += 1; + if i > 10 { + break; + } + } + let max_buffered = if options.second_fifo_working { 6 } else { 3 }; // Below here, check that we can receive from both FIFO0 and FIFO0 From 1f9ffbfb18efb1cdf6f6696b8a9339e72eea05f2 Mon Sep 17 00:00:00 2001 From: Harry Brooke Date: Mon, 18 Mar 2024 00:05:02 +0000 Subject: [PATCH 706/760] remove peripheral reads --- embassy-stm32/build.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index cee2d7e92..f88843896 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -595,20 +595,16 @@ fn main() { #start_rst crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); - // dummy read to ensure write is completed + + // we must wait two peripheral clock cycles before the clock is active + // this seems to work, but might be incorrect + // see http://efton.sk/STM32/gotcha/g183.html + + // dummy read (like in the ST HALs) let _ = crate::pac::RCC.#en_reg().read(); - // wait two peripheral clock cycles before the clock is active - // accomplish this with two dummy reads from the peripheral. this shouldn't - // cause any side effects since the peripheral is in reset - unsafe { - //apparently volatile accesses to ZST like () can be optimized out. lol - let ptr = crate::pac::#pname.as_ptr() as *const usize; - let _ = ::core::ptr::read_volatile(ptr); - let _ = ::core::ptr::read_volatile(ptr); - // wait for memory accesses to finish - cortex_m::asm::dsb(); - } + // DSB for good measure + cortex_m::asm::dsb(); #end_rst } From 5221965a1fb33fc2063d1262114cade01fb33caa Mon Sep 17 00:00:00 2001 From: Rafael Bachmann Date: Mon, 18 Mar 2024 23:02:46 +0100 Subject: [PATCH 707/760] Fix minor typos in embassy_rp/src/lib.rs --- embassy-rp/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 46973fdc8..7092b3fab 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -238,8 +238,8 @@ select_bootloader! { } /// Installs a stack guard for the CORE0 stack in MPU region 0. -/// Will fail if the MPU is already confgigured. This function requires -/// a `_stack_end` symbol to be defined by the linker script, and expexcts +/// Will fail if the MPU is already configured. This function requires +/// a `_stack_end` symbol to be defined by the linker script, and expects /// `_stack_end` to be located at the lowest address (largest depth) of /// the stack. /// From 255ed29853eb88bff2ee548c63fb4d0a6dfad7e8 Mon Sep 17 00:00:00 2001 From: Rafael Bachmann Date: Mon, 18 Mar 2024 23:28:58 +0100 Subject: [PATCH 708/760] fix minor clippy lints in embassy_rp --- embassy-rp/src/adc.rs | 11 +++-------- embassy-rp/src/clocks.rs | 4 +--- embassy-rp/src/flash.rs | 4 ++-- embassy-rp/src/gpio.rs | 6 +++--- embassy-rp/src/i2c.rs | 6 +++--- embassy-rp/src/i2c_slave.rs | 16 +++++++--------- embassy-rp/src/lib.rs | 4 ++-- embassy-rp/src/multicore.rs | 2 +- embassy-rp/src/pio/mod.rs | 12 +++++------- embassy-rp/src/pwm.rs | 6 +++--- embassy-rp/src/relocate.rs | 6 +++--- embassy-rp/src/rtc/mod.rs | 3 +-- embassy-rp/src/uart/buffered.rs | 4 ++-- embassy-rp/src/uart/mod.rs | 2 +- 14 files changed, 37 insertions(+), 49 deletions(-) diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 21360bf66..4c01fe195 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -19,14 +19,9 @@ static WAKER: AtomicWaker = AtomicWaker::new(); /// ADC config. #[non_exhaustive] +#[derive(Default)] pub struct Config {} -impl Default for Config { - fn default() -> Self { - Self {} - } -} - enum Source<'p> { Pin(PeripheralRef<'p, AnyPin>), TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), @@ -175,7 +170,7 @@ impl<'d, M: Mode> Adc<'d, M> { while !r.cs().read().ready() {} match r.cs().read().err() { true => Err(Error::ConversionFailed), - false => Ok(r.result().read().result().into()), + false => Ok(r.result().read().result()), } } } @@ -221,7 +216,7 @@ impl<'d> Adc<'d, Async> { Self::wait_for_ready().await; match r.cs().read().err() { true => Err(Error::ConversionFailed), - false => Ok(r.result().read().result().into()), + false => Ok(r.result().read().result()), } } diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 19232b801..b02f3796f 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1,5 +1,4 @@ //! Clock configuration for the RP2040 -use core::arch::asm; use core::marker::PhantomData; use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; @@ -8,7 +7,6 @@ use pac::clocks::vals::*; use crate::gpio::sealed::Pin; use crate::gpio::AnyPin; -use crate::pac::common::{Reg, RW}; use crate::{pac, reset, Peripheral}; // NOTE: all gpin handling is commented out for future reference. @@ -737,7 +735,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { assert!(config.refdiv >= 1 && config.refdiv <= 63); assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32); - assert!(vco_freq >= 750_000_000 && vco_freq <= 1800_000_000); + assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); // Load VCO-related dividers before starting VCO p.cs().write(|w| w.set_refdiv(config.refdiv as _)); diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 2d673cf6c..8bac93684 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -326,9 +326,9 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { // If the destination address is already aligned, then we can just DMA directly if (bytes.as_ptr() as u32) % 4 == 0 { // Safety: alignment and size have been checked for compatibility - let mut buf: &mut [u32] = + let buf: &mut [u32] = unsafe { core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u32, bytes.len() / 4) }; - self.background_read(offset, &mut buf)?.await; + self.background_read(offset, buf)?.await; return Ok(()); } diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 62eeb4cf6..405bddfd8 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -225,8 +225,8 @@ fn irq_handler(bank: pac::io::Io, wakers: &[AtomicWaker; N]) { // The status register is divided into groups of four, one group for // each pin. Each group consists of four trigger levels LEVEL_LOW, // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. - let pin_group = (pin % 8) as usize; - let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32; + let pin_group = pin % 8; + let event = (intsx.read().0 >> (pin_group * 4)) & 0xf; // no more than one event can be awaited per pin at any given time, so // we can just clear all interrupt enables for that pin without having @@ -238,7 +238,7 @@ fn irq_handler(bank: pac::io::Io, wakers: &[AtomicWaker; N]) { w.set_level_high(pin_group, true); w.set_level_low(pin_group, true); }); - wakers[pin as usize].wake(); + wakers[pin].wake(); } } } diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index ac0eac96d..26a819b25 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -352,7 +352,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -pub(crate) fn set_up_i2c_pin<'d, P, T>(pin: &P) +pub(crate) fn set_up_i2c_pin(pin: &P) where P: core::ops::Deref, T: crate::gpio::Pin, @@ -749,7 +749,7 @@ where let addr: u16 = address.into(); - if operations.len() > 0 { + if !operations.is_empty() { Self::setup(addr)?; } let mut iterator = operations.iter_mut(); @@ -762,7 +762,7 @@ where self.read_async_internal(buffer, false, last).await?; } Operation::Write(buffer) => { - self.write_async_internal(buffer.into_iter().cloned(), last).await?; + self.write_async_internal(buffer.iter().cloned(), last).await?; } } } diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 97ca17295..e2d4fbac0 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -289,7 +289,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result { let p = T::regs(); - if buffer.len() == 0 { + if buffer.is_empty() { return Err(Error::InvalidResponseBufferLength); } @@ -318,15 +318,13 @@ impl<'d, T: Instance> I2cSlave<'d, T> { } Poll::Pending + } else if stat.rx_done() { + p.ic_clr_rx_done().read(); + Poll::Ready(Ok(ReadStatus::Done)) + } else if stat.rd_req() && stat.tx_empty() { + Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) } else { - if stat.rx_done() { - p.ic_clr_rx_done().read(); - Poll::Ready(Ok(ReadStatus::Done)) - } else if stat.rd_req() && stat.tx_empty() { - Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) - } else { - Poll::Pending - } + Poll::Pending } }, |_me| { diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 46973fdc8..7092b3fab 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -238,8 +238,8 @@ select_bootloader! { } /// Installs a stack guard for the CORE0 stack in MPU region 0. -/// Will fail if the MPU is already confgigured. This function requires -/// a `_stack_end` symbol to be defined by the linker script, and expexcts +/// Will fail if the MPU is already configured. This function requires +/// a `_stack_end` symbol to be defined by the linker script, and expects /// `_stack_end` to be located at the lowest address (largest depth) of /// the stack. /// diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 252f30dc1..d9d65694a 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -59,7 +59,7 @@ static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); #[inline(always)] fn core1_setup(stack_bottom: *mut usize) { - if let Err(_) = install_stack_guard(stack_bottom) { + if install_stack_guard(stack_bottom).is_err() { // currently only happens if the MPU was already set up, which // would indicate that the core is already in use from outside // embassy, somehow. trap if so since we can't deal with that. diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index ca9795024..804a7636d 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -268,7 +268,7 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { } /// Set the pin's input sync bypass. - pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { + pub fn set_input_sync_bypass(&mut self, bypass: bool) { let mask = 1 << self.pin(); if bypass { PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); @@ -463,7 +463,7 @@ impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { } } -fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) { +fn assert_consecutive(pins: &[&Pin]) { for (p1, p2) in pins.iter().zip(pins.iter().skip(1)) { // purposely does not allow wrap-around because we can't claim pins 30 and 31. assert!(p1.pin() + 1 == p2.pin(), "pins must be consecutive"); @@ -749,7 +749,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_set_count(1); }); // SET PINDIRS, (dir) - unsafe { sm.exec_instr(0b111_00000_100_00000 | dir as u16) }; + unsafe { sm.exec_instr(0b1110_0000_1000_0000 | dir as u16) }; } }); } @@ -764,7 +764,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_set_count(1); }); // SET PINS, (dir) - unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) }; + unsafe { sm.exec_instr(0b1110_0000_0000_0000 | level as u16) }; } }); } @@ -867,9 +867,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { prog: &Program, ) -> Result, LoadError> { match prog.origin { - Some(origin) => self - .try_load_program_at(prog, origin) - .map_err(|a| LoadError::AddressInUse(a)), + Some(origin) => self.try_load_program_at(prog, origin).map_err(LoadError::AddressInUse), None => { // naively search for free space, allowing wraparound since // PIO does support that. with only 32 instruction slots it diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 784a05f92..e6f3b2aa2 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -114,8 +114,8 @@ impl<'d, T: Channel> Pwm<'d, T> { } Self { inner, - pin_a: a.into(), - pin_b: b.into(), + pin_a: a, + pin_b: b, } } @@ -190,7 +190,7 @@ impl<'d, T: Channel> Pwm<'d, T> { } fn configure(p: pac::pwm::Channel, config: &Config) { - if config.divider > FixedU16::::from_bits(0xFF_F) { + if config.divider > FixedU16::::from_bits(0xFFF) { panic!("Requested divider is too large"); } diff --git a/embassy-rp/src/relocate.rs b/embassy-rp/src/relocate.rs index b35b4ed72..40cb2667b 100644 --- a/embassy-rp/src/relocate.rs +++ b/embassy-rp/src/relocate.rs @@ -22,15 +22,15 @@ where { type Item = u16; fn next(&mut self) -> Option { - self.iter.next().and_then(|&instr| { - Some(if instr & 0b1110_0000_0000_0000 == 0 { + self.iter.next().map(|&instr| { + if instr & 0b1110_0000_0000_0000 == 0 { // this is a JMP instruction -> add offset to address let address = (instr & 0b1_1111) as u8; let address = address.wrapping_add(self.offset) % 32; instr & (!0b11111) | address as u16 } else { instr - }) + } }) } } diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index b696989f5..c8691bdc2 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -29,8 +29,7 @@ impl<'d, T: Instance> Rtc<'d, T> { // Set the RTC divider inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); - let result = Self { inner }; - result + Self { inner } } /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 99c958129..7622539f1 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -467,7 +467,7 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { // TX is inactive if the the buffer is not available. // We can now unregister the interrupt handler - if state.tx_buf.len() == 0 { + if state.tx_buf.is_empty() { T::Interrupt::disable(); } } @@ -480,7 +480,7 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { // RX is inactive if the the buffer is not available. // We can now unregister the interrupt handler - if state.rx_buf.len() == 0 { + if state.rx_buf.is_empty() { T::Interrupt::disable(); } } diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index f372cb640..65dcf4eb4 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -322,7 +322,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { fn drop(&mut self) { - if let Some(_) = self.rx_dma { + if self.rx_dma.is_some() { T::Interrupt::disable(); // clear dma flags. irq handlers use these to disambiguate among themselves. T::regs().uartdmacr().write_clear(|reg| { From 5a879b3ed1617f49670f5d66e659a4d6c3e7b0fb Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Tue, 19 Mar 2024 02:17:50 +0000 Subject: [PATCH 709/760] STM32: SAI: Fix MCKDIV for SAI v3/v4 --- embassy-stm32/src/sai/mod.rs | 144 ++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 02f96f8a9..294620031 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -386,6 +386,7 @@ impl OutputDrive { /// Master clock divider. #[derive(Copy, Clone, PartialEq)] #[allow(missing_docs)] +#[cfg(any(sai_v1, sai_v2))] pub enum MasterClockDivider { MasterClockDisabled, Div1, @@ -406,8 +407,79 @@ pub enum MasterClockDivider { Div30, } +/// Master clock divider. +#[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] +#[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] +pub enum MasterClockDivider { + MasterClockDisabled, + Div1, + Div2, + Div3, + Div4, + Div5, + Div6, + Div7, + Div8, + Div9, + Div10, + Div11, + Div12, + Div13, + Div14, + Div15, + Div16, + Div17, + Div18, + Div19, + Div20, + Div21, + Div22, + Div23, + Div24, + Div25, + Div26, + Div27, + Div28, + Div29, + Div30, + Div31, + Div32, + Div33, + Div34, + Div35, + Div36, + Div37, + Div38, + Div39, + Div40, + Div41, + Div42, + Div43, + Div44, + Div45, + Div46, + Div47, + Div48, + Div49, + Div50, + Div51, + Div52, + Div53, + Div54, + Div55, + Div56, + Div57, + Div58, + Div59, + Div60, + Div61, + Div62, + Div63, +} + impl MasterClockDivider { - #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] + #[cfg(any(sai_v1, sai_v2))] const fn mckdiv(&self) -> u8 { match self { MasterClockDivider::MasterClockDisabled => 0, @@ -429,6 +501,76 @@ impl MasterClockDivider { MasterClockDivider::Div30 => 15, } } + + #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] + const fn mckdiv(&self) -> u8 { + match self { + MasterClockDivider::MasterClockDisabled => 0, + MasterClockDivider::Div1 => 1, + MasterClockDivider::Div2 => 2, + MasterClockDivider::Div3 => 3, + MasterClockDivider::Div4 => 4, + MasterClockDivider::Div5 => 5, + MasterClockDivider::Div6 => 6, + MasterClockDivider::Div7 => 7, + MasterClockDivider::Div8 => 8, + MasterClockDivider::Div9 => 9, + MasterClockDivider::Div10 => 10, + MasterClockDivider::Div11 => 11, + MasterClockDivider::Div12 => 12, + MasterClockDivider::Div13 => 13, + MasterClockDivider::Div14 => 14, + MasterClockDivider::Div15 => 15, + MasterClockDivider::Div16 => 16, + MasterClockDivider::Div17 => 17, + MasterClockDivider::Div18 => 18, + MasterClockDivider::Div19 => 19, + MasterClockDivider::Div20 => 20, + MasterClockDivider::Div21 => 21, + MasterClockDivider::Div22 => 22, + MasterClockDivider::Div23 => 23, + MasterClockDivider::Div24 => 24, + MasterClockDivider::Div25 => 25, + MasterClockDivider::Div26 => 26, + MasterClockDivider::Div27 => 27, + MasterClockDivider::Div28 => 28, + MasterClockDivider::Div29 => 29, + MasterClockDivider::Div30 => 30, + MasterClockDivider::Div31 => 31, + MasterClockDivider::Div32 => 32, + MasterClockDivider::Div33 => 33, + MasterClockDivider::Div34 => 34, + MasterClockDivider::Div35 => 35, + MasterClockDivider::Div36 => 36, + MasterClockDivider::Div37 => 37, + MasterClockDivider::Div38 => 38, + MasterClockDivider::Div39 => 39, + MasterClockDivider::Div40 => 40, + MasterClockDivider::Div41 => 41, + MasterClockDivider::Div42 => 42, + MasterClockDivider::Div43 => 43, + MasterClockDivider::Div44 => 44, + MasterClockDivider::Div45 => 45, + MasterClockDivider::Div46 => 46, + MasterClockDivider::Div47 => 47, + MasterClockDivider::Div48 => 48, + MasterClockDivider::Div49 => 49, + MasterClockDivider::Div50 => 50, + MasterClockDivider::Div51 => 51, + MasterClockDivider::Div52 => 52, + MasterClockDivider::Div53 => 53, + MasterClockDivider::Div54 => 54, + MasterClockDivider::Div55 => 55, + MasterClockDivider::Div56 => 56, + MasterClockDivider::Div57 => 57, + MasterClockDivider::Div58 => 58, + MasterClockDivider::Div59 => 59, + MasterClockDivider::Div60 => 60, + MasterClockDivider::Div61 => 61, + MasterClockDivider::Div62 => 62, + MasterClockDivider::Div63 => 63, + } + } } /// [`SAI`] configuration. From 530ff9d4d33abff34edb718d650c71a41dd68f8c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Mar 2024 20:44:33 +0100 Subject: [PATCH 710/760] stm32/usb: merge usb and usb_otg into single module. --- embassy-stm32/build.rs | 28 +-- embassy-stm32/src/lib.rs | 8 +- embassy-stm32/src/usb/mod.rs | 39 +---- .../src/{usb_otg/usb.rs => usb/otg.rs} | 157 ++++++++++++++++- embassy-stm32/src/usb/usb.rs | 31 +++- embassy-stm32/src/usb_otg/mod.rs | 163 ------------------ examples/stm32f4/src/bin/usb_ethernet.rs | 8 +- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 8 +- examples/stm32f4/src/bin/usb_hid_mouse.rs | 8 +- examples/stm32f4/src/bin/usb_raw.rs | 8 +- examples/stm32f4/src/bin/usb_serial.rs | 8 +- examples/stm32f7/src/bin/usb_serial.rs | 8 +- examples/stm32h7/src/bin/usb_serial.rs | 8 +- examples/stm32l4/src/bin/usb_serial.rs | 8 +- examples/stm32u5/src/bin/usb_serial.rs | 8 +- 15 files changed, 243 insertions(+), 255 deletions(-) rename embassy-stm32/src/{usb_otg/usb.rs => usb/otg.rs} (90%) delete mode 100644 embassy-stm32/src/usb_otg/mod.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index fe5236ed6..ee224da67 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -826,20 +826,20 @@ fn main() { (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)), (("usb", "DP"), quote!(crate::usb::DpPin)), (("usb", "DM"), quote!(crate::usb::DmPin)), - (("otg", "DP"), quote!(crate::usb_otg::DpPin)), - (("otg", "DM"), quote!(crate::usb_otg::DmPin)), - (("otg", "ULPI_CK"), quote!(crate::usb_otg::UlpiClkPin)), - (("otg", "ULPI_DIR"), quote!(crate::usb_otg::UlpiDirPin)), - (("otg", "ULPI_NXT"), quote!(crate::usb_otg::UlpiNxtPin)), - (("otg", "ULPI_STP"), quote!(crate::usb_otg::UlpiStpPin)), - (("otg", "ULPI_D0"), quote!(crate::usb_otg::UlpiD0Pin)), - (("otg", "ULPI_D1"), quote!(crate::usb_otg::UlpiD1Pin)), - (("otg", "ULPI_D2"), quote!(crate::usb_otg::UlpiD2Pin)), - (("otg", "ULPI_D3"), quote!(crate::usb_otg::UlpiD3Pin)), - (("otg", "ULPI_D4"), quote!(crate::usb_otg::UlpiD4Pin)), - (("otg", "ULPI_D5"), quote!(crate::usb_otg::UlpiD5Pin)), - (("otg", "ULPI_D6"), quote!(crate::usb_otg::UlpiD6Pin)), - (("otg", "ULPI_D7"), quote!(crate::usb_otg::UlpiD7Pin)), + (("otg", "DP"), quote!(crate::usb::DpPin)), + (("otg", "DM"), quote!(crate::usb::DmPin)), + (("otg", "ULPI_CK"), quote!(crate::usb::UlpiClkPin)), + (("otg", "ULPI_DIR"), quote!(crate::usb::UlpiDirPin)), + (("otg", "ULPI_NXT"), quote!(crate::usb::UlpiNxtPin)), + (("otg", "ULPI_STP"), quote!(crate::usb::UlpiStpPin)), + (("otg", "ULPI_D0"), quote!(crate::usb::UlpiD0Pin)), + (("otg", "ULPI_D1"), quote!(crate::usb::UlpiD1Pin)), + (("otg", "ULPI_D2"), quote!(crate::usb::UlpiD2Pin)), + (("otg", "ULPI_D3"), quote!(crate::usb::UlpiD3Pin)), + (("otg", "ULPI_D4"), quote!(crate::usb::UlpiD4Pin)), + (("otg", "ULPI_D5"), quote!(crate::usb::UlpiD5Pin)), + (("otg", "ULPI_D6"), quote!(crate::usb::UlpiD6Pin)), + (("otg", "ULPI_D7"), quote!(crate::usb::UlpiD7Pin)), (("can", "TX"), quote!(crate::can::TxPin)), (("can", "RX"), quote!(crate::can::RxPin)), (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index b38b5c29d..9e26a3513 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -79,10 +79,8 @@ pub mod ucpd; pub mod uid; #[cfg(usart)] pub mod usart; -#[cfg(usb)] +#[cfg(any(usb, otg))] pub mod usb; -#[cfg(otg)] -pub mod usb_otg; #[cfg(iwdg)] pub mod wdg; @@ -107,10 +105,10 @@ pub use crate::_generated::interrupt; /// Example of how to bind one interrupt: /// /// ```rust,ignore -/// use embassy_stm32::{bind_interrupts, usb_otg, peripherals}; +/// use embassy_stm32::{bind_interrupts, usb, peripherals}; /// /// bind_interrupts!(struct Irqs { -/// OTG_FS => usb_otg::InterruptHandler; +/// OTG_FS => usb::InterruptHandler; /// }); /// ``` /// diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 4debd4e54..974880900 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -1,37 +1,6 @@ //! Universal Serial Bus (USB) -use crate::interrupt; -use crate::rcc::RccPeripheral; - -mod usb; -pub use usb::*; - -pub(crate) mod sealed { - pub trait Instance { - fn regs() -> crate::pac::usb::Usb; - } -} - -/// USB instance trait. -pub trait Instance: sealed::Instance + RccPeripheral + 'static { - /// Interrupt for this USB instance. - type Interrupt: interrupt::typelevel::Interrupt; -} - -// Internal PHY pins -pin_trait!(DpPin, Instance); -pin_trait!(DmPin, Instance); - -foreach_interrupt!( - ($inst:ident, usb, $block:ident, LP, $irq:ident) => { - impl sealed::Instance for crate::peripherals::$inst { - fn regs() -> crate::pac::usb::Usb { - crate::pac::$inst - } - } - - impl Instance for crate::peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$irq; - } - }; -); +#[cfg_attr(usb, path = "usb.rs")] +#[cfg_attr(otg, path = "otg.rs")] +mod _version; +pub use _version::*; diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb/otg.rs similarity index 90% rename from embassy-stm32/src/usb_otg/usb.rs rename to embassy-stm32/src/usb/otg.rs index 373697ec8..d15d929f6 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -11,7 +11,6 @@ use embassy_usb_driver::{ }; use futures::future::poll_fn; -use super::*; use crate::gpio::sealed::AFType; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; @@ -1469,3 +1468,159 @@ fn calculate_trdt(speed: vals::Dspd, ahb_freq: Hertz) -> u8 { fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool { r.cid().read().0 & 0xf000 == 0x1000 } + +// Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps +const MAX_EP_COUNT: usize = 9; + +pub(crate) mod sealed { + pub trait Instance { + const HIGH_SPEED: bool; + const FIFO_DEPTH_WORDS: u16; + const ENDPOINT_COUNT: usize; + + fn regs() -> crate::pac::otg::Otg; + fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>; + } +} + +/// USB instance trait. +pub trait Instance: sealed::Instance + RccPeripheral + 'static { + /// Interrupt for this USB instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +// Internal PHY pins +pin_trait!(DpPin, Instance); +pin_trait!(DmPin, Instance); + +// External PHY pins +pin_trait!(UlpiClkPin, Instance); +pin_trait!(UlpiDirPin, Instance); +pin_trait!(UlpiNxtPin, Instance); +pin_trait!(UlpiStpPin, Instance); +pin_trait!(UlpiD0Pin, Instance); +pin_trait!(UlpiD1Pin, Instance); +pin_trait!(UlpiD2Pin, Instance); +pin_trait!(UlpiD3Pin, Instance); +pin_trait!(UlpiD4Pin, Instance); +pin_trait!(UlpiD5Pin, Instance); +pin_trait!(UlpiD6Pin, Instance); +pin_trait!(UlpiD7Pin, Instance); + +foreach_interrupt!( + (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => { + impl sealed::Instance for crate::peripherals::USB_OTG_FS { + const HIGH_SPEED: bool = false; + + cfg_if::cfg_if! { + if #[cfg(stm32f1)] { + const FIFO_DEPTH_WORDS: u16 = 128; + const ENDPOINT_COUNT: usize = 8; + } else if #[cfg(any( + stm32f2, + stm32f401, + stm32f405, + stm32f407, + stm32f411, + stm32f415, + stm32f417, + stm32f427, + stm32f429, + stm32f437, + stm32f439, + ))] { + const FIFO_DEPTH_WORDS: u16 = 320; + const ENDPOINT_COUNT: usize = 4; + } else if #[cfg(any( + stm32f412, + stm32f413, + stm32f423, + stm32f446, + stm32f469, + stm32f479, + stm32f7, + stm32l4, + stm32u5, + ))] { + const FIFO_DEPTH_WORDS: u16 = 320; + const ENDPOINT_COUNT: usize = 6; + } else if #[cfg(stm32g0x1)] { + const FIFO_DEPTH_WORDS: u16 = 512; + const ENDPOINT_COUNT: usize = 8; + } else if #[cfg(stm32h7)] { + const FIFO_DEPTH_WORDS: u16 = 1024; + const ENDPOINT_COUNT: usize = 9; + } else if #[cfg(stm32u5)] { + const FIFO_DEPTH_WORDS: u16 = 320; + const ENDPOINT_COUNT: usize = 6; + } else { + compile_error!("USB_OTG_FS peripheral is not supported by this chip."); + } + } + + fn regs() -> crate::pac::otg::Otg { + crate::pac::USB_OTG_FS + } + + fn state() -> &'static State { + static STATE: State = State::new(); + &STATE + } + } + + impl Instance for crate::peripherals::USB_OTG_FS { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; + + (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => { + impl sealed::Instance for crate::peripherals::USB_OTG_HS { + const HIGH_SPEED: bool = true; + + cfg_if::cfg_if! { + if #[cfg(any( + stm32f2, + stm32f405, + stm32f407, + stm32f415, + stm32f417, + stm32f427, + stm32f429, + stm32f437, + stm32f439, + ))] { + const FIFO_DEPTH_WORDS: u16 = 1024; + const ENDPOINT_COUNT: usize = 6; + } else if #[cfg(any( + stm32f446, + stm32f469, + stm32f479, + stm32f7, + stm32h7, + ))] { + const FIFO_DEPTH_WORDS: u16 = 1024; + const ENDPOINT_COUNT: usize = 9; + } else if #[cfg(stm32u5)] { + const FIFO_DEPTH_WORDS: u16 = 1024; + const ENDPOINT_COUNT: usize = 9; + } else { + compile_error!("USB_OTG_HS peripheral is not supported by this chip."); + } + } + + fn regs() -> crate::pac::otg::Otg { + // OTG HS registers are a superset of FS registers + unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) } + } + + fn state() -> &'static State { + static STATE: State = State::new(); + &STATE + } + } + + impl Instance for crate::peripherals::USB_OTG_HS { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; +); diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index be321a19b..b3b3470e4 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -12,7 +12,6 @@ use embassy_usb_driver::{ Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, }; -use super::{DmPin, DpPin, Instance}; use crate::interrupt::typelevel::Interrupt; use crate::pac::usb::regs; use crate::pac::usb::vals::{EpType, Stat}; @@ -1057,3 +1056,33 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { }); } } + +pub(crate) mod sealed { + pub trait Instance { + fn regs() -> crate::pac::usb::Usb; + } +} + +/// USB instance trait. +pub trait Instance: sealed::Instance + RccPeripheral + 'static { + /// Interrupt for this USB instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +// Internal PHY pins +pin_trait!(DpPin, Instance); +pin_trait!(DmPin, Instance); + +foreach_interrupt!( + ($inst:ident, usb, $block:ident, LP, $irq:ident) => { + impl sealed::Instance for crate::peripherals::$inst { + fn regs() -> crate::pac::usb::Usb { + crate::pac::$inst + } + } + + impl Instance for crate::peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; +); diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs deleted file mode 100644 index 0649e684b..000000000 --- a/embassy-stm32/src/usb_otg/mod.rs +++ /dev/null @@ -1,163 +0,0 @@ -//! USB On The Go (OTG) - -use crate::rcc::RccPeripheral; -use crate::{interrupt, peripherals}; - -mod usb; -pub use usb::*; - -// Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps -const MAX_EP_COUNT: usize = 9; - -pub(crate) mod sealed { - pub trait Instance { - const HIGH_SPEED: bool; - const FIFO_DEPTH_WORDS: u16; - const ENDPOINT_COUNT: usize; - - fn regs() -> crate::pac::otg::Otg; - fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>; - } -} - -/// USB OTG instance. -pub trait Instance: sealed::Instance + RccPeripheral { - /// Interrupt for this USB OTG instance. - type Interrupt: interrupt::typelevel::Interrupt; -} - -// Internal PHY pins -pin_trait!(DpPin, Instance); -pin_trait!(DmPin, Instance); - -// External PHY pins -pin_trait!(UlpiClkPin, Instance); -pin_trait!(UlpiDirPin, Instance); -pin_trait!(UlpiNxtPin, Instance); -pin_trait!(UlpiStpPin, Instance); -pin_trait!(UlpiD0Pin, Instance); -pin_trait!(UlpiD1Pin, Instance); -pin_trait!(UlpiD2Pin, Instance); -pin_trait!(UlpiD3Pin, Instance); -pin_trait!(UlpiD4Pin, Instance); -pin_trait!(UlpiD5Pin, Instance); -pin_trait!(UlpiD6Pin, Instance); -pin_trait!(UlpiD7Pin, Instance); - -foreach_interrupt!( - (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => { - impl sealed::Instance for peripherals::USB_OTG_FS { - const HIGH_SPEED: bool = false; - - cfg_if::cfg_if! { - if #[cfg(stm32f1)] { - const FIFO_DEPTH_WORDS: u16 = 128; - const ENDPOINT_COUNT: usize = 8; - } else if #[cfg(any( - stm32f2, - stm32f401, - stm32f405, - stm32f407, - stm32f411, - stm32f415, - stm32f417, - stm32f427, - stm32f429, - stm32f437, - stm32f439, - ))] { - const FIFO_DEPTH_WORDS: u16 = 320; - const ENDPOINT_COUNT: usize = 4; - } else if #[cfg(any( - stm32f412, - stm32f413, - stm32f423, - stm32f446, - stm32f469, - stm32f479, - stm32f7, - stm32l4, - stm32u5, - ))] { - const FIFO_DEPTH_WORDS: u16 = 320; - const ENDPOINT_COUNT: usize = 6; - } else if #[cfg(stm32g0x1)] { - const FIFO_DEPTH_WORDS: u16 = 512; - const ENDPOINT_COUNT: usize = 8; - } else if #[cfg(stm32h7)] { - const FIFO_DEPTH_WORDS: u16 = 1024; - const ENDPOINT_COUNT: usize = 9; - } else if #[cfg(stm32u5)] { - const FIFO_DEPTH_WORDS: u16 = 320; - const ENDPOINT_COUNT: usize = 6; - } else { - compile_error!("USB_OTG_FS peripheral is not supported by this chip."); - } - } - - fn regs() -> crate::pac::otg::Otg { - crate::pac::USB_OTG_FS - } - - fn state() -> &'static State { - static STATE: State = State::new(); - &STATE - } - } - - impl Instance for peripherals::USB_OTG_FS { - type Interrupt = crate::interrupt::typelevel::$irq; - } - }; - - (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => { - impl sealed::Instance for peripherals::USB_OTG_HS { - const HIGH_SPEED: bool = true; - - cfg_if::cfg_if! { - if #[cfg(any( - stm32f2, - stm32f405, - stm32f407, - stm32f415, - stm32f417, - stm32f427, - stm32f429, - stm32f437, - stm32f439, - ))] { - const FIFO_DEPTH_WORDS: u16 = 1024; - const ENDPOINT_COUNT: usize = 6; - } else if #[cfg(any( - stm32f446, - stm32f469, - stm32f479, - stm32f7, - stm32h7, - ))] { - const FIFO_DEPTH_WORDS: u16 = 1024; - const ENDPOINT_COUNT: usize = 9; - } else if #[cfg(stm32u5)] { - const FIFO_DEPTH_WORDS: u16 = 1024; - const ENDPOINT_COUNT: usize = 9; - } else { - compile_error!("USB_OTG_HS peripheral is not supported by this chip."); - } - } - - fn regs() -> crate::pac::otg::Otg { - // OTG HS registers are a superset of FS registers - unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) } - } - - fn state() -> &'static State { - static STATE: State = State::new(); - &STATE - } - } - - impl Instance for peripherals::USB_OTG_HS { - type Interrupt = crate::interrupt::typelevel::$irq; - } - }; -); diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index a196259a8..60e580609 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -7,8 +7,8 @@ use embassy_net::tcp::TcpSocket; use embassy_net::{Stack, StackResources}; use embassy_stm32::rng::{self, Rng}; use embassy_stm32::time::Hertz; -use embassy_stm32::usb_otg::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::Driver; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; @@ -36,7 +36,7 @@ async fn net_task(stack: &'static Stack>) -> ! { } bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; HASH_RNG => rng::InterruptHandler; }); @@ -69,7 +69,7 @@ async fn main(spawner: Spawner) { // Create the driver, from the HAL. static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; - let mut config = embassy_stm32::usb_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 19b5971fb..ae4ce6b6a 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -8,8 +8,8 @@ use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; use embassy_stm32::time::Hertz; -use embassy_stm32::usb_otg::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::Driver; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Handler}; @@ -18,7 +18,7 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -47,7 +47,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_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index c98792880..5c64f4969 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -4,8 +4,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; -use embassy_stm32::usb_otg::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::Driver; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::Timer; use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; @@ -15,7 +15,7 @@ use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -44,7 +44,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_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index afff55187..c13fe051f 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -52,8 +52,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; -use embassy_stm32::usb_otg::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::Driver; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; use embassy_usb::msos::{self, windows_version}; use embassy_usb::types::InterfaceNumber; @@ -66,7 +66,7 @@ use {defmt_rtt as _, panic_probe as _}; const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"]; bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -97,7 +97,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_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 58d994a61..21e255612 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -4,8 +4,8 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; -use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -13,7 +13,7 @@ use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -44,7 +44,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_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 97daf6bd1..bdd7b76ff 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -4,8 +4,8 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; -use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -13,7 +13,7 @@ use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -44,7 +44,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_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index d81efb541..3d42a24f3 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -3,8 +3,8 @@ use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -12,7 +12,7 @@ use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -45,7 +45,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_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 9247e56a1..c7f4add7f 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -5,8 +5,8 @@ use defmt::{panic, *}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_stm32::rcc::*; -use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -14,7 +14,7 @@ use futures::future::join; use panic_probe as _; bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -38,7 +38,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_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 61851e5a2..98ae46b1c 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -4,8 +4,8 @@ use defmt::{panic, *}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; -use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -13,7 +13,7 @@ use futures::future::join; use panic_probe as _; bind_interrupts!(struct Irqs { - OTG_FS => usb_otg::InterruptHandler; + OTG_FS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -41,7 +41,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_otg::Config::default(); + let mut config = embassy_stm32::usb::Config::default(); config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); From daa64bd5400c4db7da25e3f538b4ee0c31435029 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Mar 2024 21:32:22 +0100 Subject: [PATCH 711/760] stm32/usb: extract common init code. --- embassy-stm32/src/usb/mod.rs | 50 ++++++++++++++++++++++++++++++++++++ embassy-stm32/src/usb/otg.rs | 38 +-------------------------- embassy-stm32/src/usb/usb.rs | 13 ++-------- 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 974880900..130c728e6 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -4,3 +4,53 @@ #[cfg_attr(otg, path = "otg.rs")] mod _version; pub use _version::*; + +use crate::interrupt::typelevel::Interrupt; +use crate::rcc::sealed::RccPeripheral; + +/// clock, power initialization stuff that's common for USB and OTG. +fn common_init() { + #[cfg(any(stm32l4, stm32l5, stm32wb))] + critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); + + #[cfg(pwr_h5)] + critical_section::with(|_| crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true))); + + #[cfg(stm32h7)] + { + // If true, VDD33USB is generated by internal regulator from VDD50USB + // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) + // TODO: unhardcode + let internal_regulator = false; + + // Enable USB power + critical_section::with(|_| { + crate::pac::PWR.cr3().modify(|w| { + w.set_usb33den(true); + w.set_usbregen(internal_regulator); + }) + }); + + // Wait for USB power to stabilize + while !crate::pac::PWR.cr3().read().usb33rdy() {} + } + + #[cfg(stm32u5)] + { + // Enable USB power + critical_section::with(|_| { + crate::pac::PWR.svmcr().modify(|w| { + w.set_usv(true); + w.set_uvmen(true); + }) + }); + + // Wait for USB power to stabilize + while !crate::pac::PWR.svmsr().read().vddusbrdy() {} + } + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + ::enable_and_reset(); +} diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index d15d929f6..80a08f3c5 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -560,8 +560,7 @@ impl<'d, T: Instance> Bus<'d, T> { impl<'d, T: Instance> Bus<'d, T> { fn init(&mut self) { - #[cfg(stm32l4)] - critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); + super::common_init::(); #[cfg(stm32f7)] { @@ -589,22 +588,6 @@ impl<'d, T: Instance> Bus<'d, T> { #[cfg(stm32h7)] { - // If true, VDD33USB is generated by internal regulator from VDD50USB - // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) - // TODO: unhardcode - let internal_regulator = false; - - // Enable USB power - critical_section::with(|_| { - crate::pac::PWR.cr3().modify(|w| { - w.set_usb33den(true); - w.set_usbregen(internal_regulator); - }) - }); - - // Wait for USB power to stabilize - while !crate::pac::PWR.cr3().read().usb33rdy() {} - // Enable ULPI clock if external PHY is used let ulpien = !self.phy_type.internal(); critical_section::with(|_| { @@ -625,25 +608,6 @@ impl<'d, T: Instance> Bus<'d, T> { }); } - #[cfg(stm32u5)] - { - // Enable USB power - critical_section::with(|_| { - crate::pac::PWR.svmcr().modify(|w| { - w.set_usv(true); - w.set_uvmen(true); - }) - }); - - // Wait for USB power to stabilize - while !crate::pac::PWR.svmsr().read().vddusbrdy() {} - } - - ::enable_and_reset(); - - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - let r = T::regs(); let core_id = r.cid().read().0; trace!("Core id {:08x}", core_id); diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index b3b3470e4..1fb2c9ebb 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -12,7 +12,6 @@ use embassy_usb_driver::{ Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, }; -use crate::interrupt::typelevel::Interrupt; use crate::pac::usb::regs; use crate::pac::usb::vals::{EpType, Stat}; use crate::pac::USBRAM; @@ -258,19 +257,11 @@ impl<'d, T: Instance> Driver<'d, T> { dm: impl Peripheral

> + 'd, ) -> Self { into_ref!(dp, dm); - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; + + super::common_init::(); let regs = T::regs(); - #[cfg(any(stm32l4, stm32l5, stm32wb))] - crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); - - #[cfg(pwr_h5)] - crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); - - ::enable_and_reset(); - regs.cntr().write(|w| { w.set_pdwn(false); w.set_fres(true); From d90abb8ac91440602386b807edb221cae59e82f9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Mar 2024 21:33:20 +0100 Subject: [PATCH 712/760] stm32/usb: assert usb clock is okay. --- embassy-stm32/src/usb/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 130c728e6..788f61f16 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -10,6 +10,19 @@ use crate::rcc::sealed::RccPeripheral; /// clock, power initialization stuff that's common for USB and OTG. fn common_init() { + // Check the USB clock is enabled and running at exactly 48 MHz. + // frequency() will panic if not enabled + let freq = T::frequency(); + // Check frequency is within the 0.25% tolerance allowed by the spec. + // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user + // has tight clock restrictions due to something else (like audio). + if freq.0.abs_diff(48_000_000) > 120_000 { + panic!( + "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", + freq.0 + ) + } + #[cfg(any(stm32l4, stm32l5, stm32wb))] critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); From 4858a53a397c6e96f68340417a19274dd25b4ddc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Mar 2024 21:49:47 +0100 Subject: [PATCH 713/760] stm32/usb: ensure mux is configured in examples. --- examples/stm32f4/src/bin/usb_ethernet.rs | 1 + examples/stm32f4/src/bin/usb_hid_keyboard.rs | 1 + examples/stm32f4/src/bin/usb_hid_mouse.rs | 1 + examples/stm32f4/src/bin/usb_raw.rs | 1 + examples/stm32f4/src/bin/usb_serial.rs | 1 + examples/stm32f7/src/bin/usb_serial.rs | 1 + examples/stm32h7/src/bin/usb_serial.rs | 1 + examples/stm32l4/src/bin/usb_serial.rs | 28 +++++++++++--------- examples/stm32l5/src/bin/usb_ethernet.rs | 28 +++++++++++--------- examples/stm32l5/src/bin/usb_hid_mouse.rs | 28 +++++++++++--------- examples/stm32l5/src/bin/usb_serial.rs | 28 +++++++++++--------- examples/stm32u5/src/bin/usb_serial.rs | 1 + 12 files changed, 71 insertions(+), 49 deletions(-) diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 60e580609..405cce6bc 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -63,6 +63,7 @@ async fn main(spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV4; config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.sys = Sysclk::PLL1_P; + config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; } let p = embassy_stm32::init(config); diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index ae4ce6b6a..6c25a0a64 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -42,6 +42,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV4; config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.sys = Sysclk::PLL1_P; + config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; } let p = embassy_stm32::init(config); diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 5c64f4969..d4725d597 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -39,6 +39,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV4; config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.sys = Sysclk::PLL1_P; + config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; } let p = embassy_stm32::init(config); diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index c13fe051f..15a98ff8b 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -92,6 +92,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV4; config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.sys = Sysclk::PLL1_P; + config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; } let p = embassy_stm32::init(config); diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 21e255612..6080b34a8 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -39,6 +39,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV4; config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.sys = Sysclk::PLL1_P; + config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; } let p = embassy_stm32::init(config); diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index bdd7b76ff..26ecf3bc8 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -39,6 +39,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV4; config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.sys = Sysclk::PLL1_P; + config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; } let p = embassy_stm32::init(config); diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 3d42a24f3..c3ddda72a 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -40,6 +40,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.mux.usbsel = mux::Usbsel::HSI48; } let p = embassy_stm32::init(config); diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index c7f4add7f..047234d60 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -4,7 +4,6 @@ use defmt::{panic, *}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; -use embassy_stm32::rcc::*; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; @@ -22,18 +21,21 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut config = Config::default(); - config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.hsi = true; - config.rcc.pll = Some(Pll { - source: PllSource::HSI, - prediv: PllPreDiv::DIV1, - mul: PllMul::MUL10, - divp: None, - divq: None, - divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) - }); - + { + use embassy_stm32::rcc::*; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL10, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) + }); + config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; + } let p = embassy_stm32::init(config); // Create the driver, from the HAL. diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index f6d8b16d0..dc1e7022d 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -5,7 +5,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Stack, StackResources}; -use embassy_stm32::rcc::*; use embassy_stm32::rng::Rng; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; @@ -44,17 +43,22 @@ async fn net_task(stack: &'static Stack>) -> ! { #[embassy_executor::main] async fn main(spawner: Spawner) { let mut config = Config::default(); - config.rcc.hsi = true; - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.pll = Some(Pll { - // 80Mhz clock (16 / 1 * 10 / 2) - source: PllSource::HSI, - prediv: PllPreDiv::DIV1, - mul: PllMul::MUL10, - divp: None, - divq: None, - divr: Some(PllRDiv::DIV2), - }); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.pll = Some(Pll { + // 80Mhz clock (16 / 1 * 10 / 2) + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL10, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), + }); + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; + } let p = embassy_stm32::init(config); // Create the driver, from the HAL. diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index c51ed96e0..b86fba455 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_stm32::rcc::*; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::Timer; @@ -21,17 +20,22 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.hsi = true; - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.pll = Some(Pll { - // 80Mhz clock (16 / 1 * 10 / 2) - source: PllSource::HSI, - prediv: PllPreDiv::DIV1, - mul: PllMul::MUL10, - divp: None, - divq: None, - divr: Some(PllRDiv::DIV2), - }); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.pll = Some(Pll { + // 80Mhz clock (16 / 1 * 10 / 2) + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL10, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), + }); + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; + } let p = embassy_stm32::init(config); // Create the driver, from the HAL. diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 87987f2ce..5e2378b58 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -4,7 +4,6 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_stm32::rcc::*; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; @@ -19,17 +18,22 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.hsi = true; - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.pll = Some(Pll { - // 80Mhz clock (16 / 1 * 10 / 2) - source: PllSource::HSI, - prediv: PllPreDiv::DIV1, - mul: PllMul::MUL10, - divp: None, - divq: None, - divr: Some(PllRDiv::DIV2), - }); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.pll = Some(Pll { + // 80Mhz clock (16 / 1 * 10 / 2) + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL10, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), + }); + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 98ae46b1c..33e02ce3b 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -35,6 +35,7 @@ async fn main(_spawner: Spawner) { config.rcc.sys = Sysclk::PLL1_R; config.rcc.voltage_range = VoltageScale::RANGE1; config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK } let p = embassy_stm32::init(config); From d65724207d7f0cb65e60966982ef671f57986abf Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Wed, 20 Mar 2024 01:12:04 +0100 Subject: [PATCH 714/760] Forward transaction() from blocking I2cDevice to underlying bus --- .../src/shared_bus/blocking/i2c.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index 233c9e1fd..1b08cb28e 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -67,9 +67,11 @@ where } fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { - let _ = address; - let _ = operations; - todo!() + self.bus.lock(|bus| { + bus.borrow_mut() + .transaction(address, operations) + .map_err(I2cDeviceError::I2c) + }) } } @@ -171,8 +173,10 @@ where } fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { - let _ = address; - let _ = operations; - todo!() + self.bus.lock(|bus| { + let mut bus = bus.borrow_mut(); + bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?; + bus.transaction(address, operations).map_err(I2cDeviceError::I2c) + }) } } From 7c08616c02d8e0f49daa7402fd000887d13d4fe5 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Wed, 20 Mar 2024 02:10:45 +0100 Subject: [PATCH 715/760] Introduce frame options to control start/stop conditions --- embassy-stm32/src/i2c/v1.rs | 197 +++++++++++++++++++++++++----------- 1 file changed, 138 insertions(+), 59 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index cbbc201de..0843f45cf 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -41,6 +41,68 @@ pub unsafe fn on_interrupt() { }); } +/// Frame type in I2C transaction. +/// +/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST +/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an +/// ACK or NACK after the last byte received. +/// +/// For write operations, the following options are identical because they differ only in the (N)ACK +/// treatment relevant for read operations: +/// +/// - `FirstFrame` and `FirstAndNextFrame` +/// - `NextFrame` and `LastFrameNoStop` +/// +/// Abbreviations used below: +/// +/// - `ST` = start condition +/// - `SR` = repeated start condition +/// - `SP` = stop condition +#[derive(Copy, Clone)] +enum FrameOptions { + /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in operation and last frame overall in this + /// transaction. + FirstAndLastFrame, + /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but + /// not the last frame overall. + FirstFrame, + /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last + /// frame in a read operation. + FirstAndNextFrame, + /// `[ACK]` Middle frame in a read operation (neither first nor last). + NextFrame, + /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame. + LastFrame, + /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction. + LastFrameNoStop, +} + +impl FrameOptions { + /// Sends start or repeated start condition before transfer. + fn send_start(self) -> bool { + match self { + Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, + Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false, + } + } + + /// Sends stop condition after transfer. + fn send_stop(self) -> bool { + match self { + Self::FirstAndLastFrame | Self::LastFrame => true, + Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false, + } + } + + /// Sends NACK after last byte received, indicating end of read operation. + fn send_nack(self) -> bool { + match self { + Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, + Self::FirstAndNextFrame | Self::NextFrame => false, + } + } +} + impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { T::regs().cr1().modify(|reg| { @@ -124,46 +186,57 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(sr1) } - fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> { - // Send a START condition + fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { + if frame.send_start() { + // Send a START condition - T::regs().cr1().modify(|reg| { - reg.set_start(true); - }); + T::regs().cr1().modify(|reg| { + reg.set_start(true); + }); - // Wait until START condition was generated - while !Self::check_and_clear_error_flags()?.start() { - timeout.check()?; + // Wait until START condition was generated + while !Self::check_and_clear_error_flags()?.start() { + timeout.check()?; + } + + // Also wait until signalled we're master and everything is waiting for us + while { + Self::check_and_clear_error_flags()?; + + let sr2 = T::regs().sr2().read(); + !sr2.msl() && !sr2.busy() + } { + timeout.check()?; + } + + // Set up current address, we're trying to talk to + T::regs().dr().write(|reg| reg.set_dr(addr << 1)); + + // Wait until address was sent + // Wait for the address to be acknowledged + // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. + while !Self::check_and_clear_error_flags()?.addr() { + timeout.check()?; + } + + // Clear condition by reading SR2 + let _ = T::regs().sr2().read(); } - // Also wait until signalled we're master and everything is waiting for us - while { - Self::check_and_clear_error_flags()?; - - let sr2 = T::regs().sr2().read(); - !sr2.msl() && !sr2.busy() - } { - timeout.check()?; - } - - // Set up current address, we're trying to talk to - T::regs().dr().write(|reg| reg.set_dr(addr << 1)); - - // Wait until address was sent - // Wait for the address to be acknowledged - // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. - while !Self::check_and_clear_error_flags()?.addr() { - timeout.check()?; - } - - // Clear condition by reading SR2 - let _ = T::regs().sr2().read(); - // Send bytes for c in bytes { self.send_byte(*c, timeout)?; } + if frame.send_stop() { + // Send a STOP condition + T::regs().cr1().modify(|reg| reg.set_stop(true)); + // Wait for STOP condition to transmit. + while T::regs().cr1().read().stop() { + timeout.check()?; + } + } + // Fallthrough is success Ok(()) } @@ -205,8 +278,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(value) } - fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> { - if let Some((last, buffer)) = buffer.split_last_mut() { + fn blocking_read_timeout( + &mut self, + addr: u8, + buffer: &mut [u8], + timeout: Timeout, + frame: FrameOptions, + ) -> Result<(), Error> { + let Some((last, buffer)) = buffer.split_last_mut() else { + return Err(Error::Overrun); + }; + + if frame.send_start() { // Send a START condition and set ACK bit T::regs().cr1().modify(|reg| { reg.set_start(true); @@ -237,49 +320,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Clear condition by reading SR2 let _ = T::regs().sr2().read(); + } - // Receive bytes into buffer - for c in buffer { - *c = self.recv_byte(timeout)?; - } + // Receive bytes into buffer + for c in buffer { + *c = self.recv_byte(timeout)?; + } - // Prepare to send NACK then STOP after next byte - T::regs().cr1().modify(|reg| { + // Prepare to send NACK then STOP after next byte + T::regs().cr1().modify(|reg| { + if frame.send_nack() { reg.set_ack(false); + } + if frame.send_stop() { reg.set_stop(true); - }); + } + }); - // Receive last byte - *last = self.recv_byte(timeout)?; + // Receive last byte + *last = self.recv_byte(timeout)?; + if frame.send_stop() { // Wait for the STOP to be sent. while T::regs().cr1().read().stop() { timeout.check()?; } - - // Fallthrough is success - Ok(()) - } else { - Err(Error::Overrun) } + + // Fallthrough is success + Ok(()) } /// Blocking read. pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(addr, read, self.timeout()) + self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) } /// Blocking write. pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { - let timeout = self.timeout(); - - self.write_bytes(addr, write, timeout)?; - // Send a STOP condition - T::regs().cr1().modify(|reg| reg.set_stop(true)); - // Wait for STOP condition to transmit. - while T::regs().cr1().read().stop() { - timeout.check()?; - } + self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; // Fallthrough is success Ok(()) @@ -289,8 +368,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { let timeout = self.timeout(); - self.write_bytes(addr, write, timeout)?; - self.blocking_read_timeout(addr, read, timeout)?; + self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; + self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; Ok(()) } From c96062fbcdb32b5ecc9b9d3507097f09bbe4b7ca Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Wed, 20 Mar 2024 02:55:18 +0100 Subject: [PATCH 716/760] Implement blocking transaction handling for I2C v1 --- embassy-stm32/src/i2c/mod.rs | 6 ++-- embassy-stm32/src/i2c/v1.rs | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 2416005b5..2c606c3c9 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -311,10 +311,10 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { fn transaction( &mut self, - _address: u8, - _operations: &mut [embedded_hal_1::i2c::Operation<'_>], + address: u8, + operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { - todo!(); + self.blocking_transaction(address, operations) } } diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 0843f45cf..678568706 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -10,6 +10,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_futures::select::{select, Either}; use embassy_hal_internal::drop::OnDrop; +use embedded_hal_1::i2c::Operation; use super::*; use crate::dma::Transfer; @@ -374,6 +375,66 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } + /// Blocking transaction with operations. + /// + /// Consecutive operations of same type are merged. See [transaction contract] for details. + /// + /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction + pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { + let timeout = self.timeout(); + + let mut operations = operations.iter_mut(); + + let mut prev_op: Option<&mut Operation<'_>> = None; + let mut next_op = operations.next(); + + while let Some(mut op) = next_op { + next_op = operations.next(); + + // Check if this is the first frame of this type. This is the case for the first overall + // frame in the transaction and whenever the type of operation changes. + let first_frame = + match (prev_op.as_ref(), &op) { + (None, _) => true, + (Some(Operation::Read(_)), Operation::Write(_)) + | (Some(Operation::Write(_)), Operation::Read(_)) => true, + (Some(Operation::Read(_)), Operation::Read(_)) + | (Some(Operation::Write(_)), Operation::Write(_)) => false, + }; + + let frame = match (first_frame, next_op.as_ref()) { + // If this is the first frame of this type, we generate a (repeated) start condition + // but have to consider the next operation: if it is the last, we generate the final + // stop condition. Otherwise, we branch on the operation: with read operations, only + // the last byte overall (before a write operation or the end of the transaction) is + // to be NACK'd, i.e. if another read operation follows, we must ACK this last byte. + (true, None) => FrameOptions::FirstAndLastFrame, + // Make sure to keep sending ACK for last byte in read operation when it is followed + // by another consecutive read operation. If the current operation is write, this is + // identical to `FirstFrame`. + (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame, + // Otherwise, send NACK for last byte (in read operation). (For write, this does not + // matter and could also be `FirstAndNextFrame`.) + (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame, + + // If this is not the first frame of its type, we do not generate a (repeated) start + // condition. Otherwise, we branch the same way as above. + (false, None) => FrameOptions::LastFrame, + (false, Some(Operation::Read(_))) => FrameOptions::NextFrame, + (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop, + }; + + match &mut op { + Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, + Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, + } + + prev_op = Some(op); + } + + Ok(()) + } + // Async #[inline] // pretty sure this should always be inlined From 8f19a2b537c90c2bf04f6e5ea9a7107f6e000067 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Wed, 20 Mar 2024 02:20:21 +0100 Subject: [PATCH 717/760] Avoid missing stop condition when write/read with empty read buffer --- embassy-stm32/src/i2c/v1.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 678568706..c96935d8f 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -367,6 +367,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { /// Blocking write, restart, read. pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + // Check empty read buffer before starting transaction. Otherwise, we would not generate the + // stop condition below. + if read.is_empty() { + return Err(Error::Overrun); + } + let timeout = self.timeout(); self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; @@ -381,6 +387,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { + // Check empty read buffer before starting transaction. Otherwise, we would not generate the + // stop condition below. + if operations.iter().any(|op| match op { + Operation::Read(read) => read.is_empty(), + Operation::Write(_) => false, + }) { + return Err(Error::Overrun); + } + let timeout = self.timeout(); let mut operations = operations.iter_mut(); From 4eb4108952ee75d75b2b575144a0db3a6380dd61 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Wed, 20 Mar 2024 03:30:38 +0100 Subject: [PATCH 718/760] Fix build for I2C v2 targets --- embassy-stm32/src/i2c/v2.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index bd3abaac1..1ac2740df 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -4,6 +4,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; +use embedded_hal_1::i2c::Operation; use super::*; use crate::dma::Transfer; @@ -579,6 +580,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Automatic Stop } + /// Blocking transaction with operations. + /// + /// Consecutive operations of same type are merged. See [transaction contract] for details. + /// + /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction + pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { + let _ = addr; + let _ = operations; + todo!() + } + /// Blocking write multiple buffers. /// /// The buffers are concatenated in a single write transaction. From d06dbf332bc2557d83045c93f71a86163663d481 Mon Sep 17 00:00:00 2001 From: Noah Bliss Date: Wed, 20 Mar 2024 03:19:01 +0000 Subject: [PATCH 719/760] Doc update: signaled does not clear signal signaled does not clear signal (doc update) --- embassy-sync/src/signal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index d75750ce7..520f1a896 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs @@ -125,7 +125,7 @@ where }) } - /// non-blocking method to check whether this signal has been signaled. + /// non-blocking method to check whether this signal has been signaled. This does not clear the signal. pub fn signaled(&self) -> bool { self.state.lock(|cell| { let state = cell.replace(State::None); From cff665f2ecf2c60358534cd4dfe06b1a469d45fa Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Wed, 20 Mar 2024 13:08:42 +0100 Subject: [PATCH 720/760] Avoid unnecessary double-reference --- embassy-stm32/src/i2c/v1.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index c96935d8f..f1ed7ca40 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -403,7 +403,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let mut prev_op: Option<&mut Operation<'_>> = None; let mut next_op = operations.next(); - while let Some(mut op) = next_op { + while let Some(op) = next_op { next_op = operations.next(); // Check if this is the first frame of this type. This is the case for the first overall @@ -439,7 +439,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop, }; - match &mut op { + match op { Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, } From a2fd4d751e1015905a6d8ce3a58db020cf45373d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 20 Mar 2024 13:49:19 +0100 Subject: [PATCH 721/760] stm32/gpio: add missing eh02 InputPin for OutputOpenDrain. --- embassy-stm32/src/gpio.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 00e3e1727..7cc28ff56 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -833,6 +833,18 @@ impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> { } } +impl<'d> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d> { + type Error = Infallible; + + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> { type Error = Infallible; From 47ebec82b86a9dc9aa029ee7404b270cb0e70344 Mon Sep 17 00:00:00 2001 From: Alejandro Nadal <32724827+AlejandroFNadal@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:56:15 +0100 Subject: [PATCH 722/760] Add comment warning for new users about changing pins on Ethernet for different devices Not all STM32H7 devices share the pins of the example. Added a warning and a specific example for STM32H747XIH --- examples/stm32h7/src/bin/eth.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index cd9a27fcd..825c16c6c 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -64,19 +64,21 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); + // warning: Not all STM32H7 devices have the exact same pins here + // for STM32H747XIH, replace p.PB13 for PG12 let device = Ethernet::new( PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, - p.PA1, - p.PA2, - p.PC1, - p.PA7, - p.PC4, - p.PC5, - p.PG13, - p.PB13, - p.PG11, + p.PA1, // ref_clk + p.PA2, // mdio + p.PC1, // eth_mdc + p.PA7, // CRS_DV: Carrier Sense + p.PC4, // RX_D0: Received Bit 0 + p.PC5, // RX_D1: Received Bit 1 + p.PG13,// TX_D0: Transmit Bit 0 + p.PB13,// TX_D1: Transmit Bit 1 + p.PG11,// TX_EN: Transmit Enable GenericSMI::new(0), mac_addr, ); From 2587ade63e30fc8aa222b4190515ab2e3fe51637 Mon Sep 17 00:00:00 2001 From: AlejandroFNadal Date: Wed, 20 Mar 2024 14:11:04 +0100 Subject: [PATCH 723/760] Rust formatting for comments. --- examples/stm32h7/src/bin/eth.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 825c16c6c..7c7964ecd 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -70,15 +70,15 @@ async fn main(spawner: Spawner) -> ! { PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, - p.PA1, // ref_clk - p.PA2, // mdio - p.PC1, // eth_mdc - p.PA7, // CRS_DV: Carrier Sense - p.PC4, // RX_D0: Received Bit 0 - p.PC5, // RX_D1: Received Bit 1 - p.PG13,// TX_D0: Transmit Bit 0 - p.PB13,// TX_D1: Transmit Bit 1 - p.PG11,// TX_EN: Transmit Enable + p.PA1, // ref_clk + p.PA2, // mdio + p.PC1, // eth_mdc + p.PA7, // CRS_DV: Carrier Sense + p.PC4, // RX_D0: Received Bit 0 + p.PC5, // RX_D1: Received Bit 1 + p.PG13, // TX_D0: Transmit Bit 0 + p.PB13, // TX_D1: Transmit Bit 1 + p.PG11, // TX_EN: Transmit Enable GenericSMI::new(0), mac_addr, ); From 3d842dac85a4ea21519f56d4ec6342b528805b8a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 20 Mar 2024 14:53:19 +0100 Subject: [PATCH 724/760] fmt: disable "unused" warnings. --- cyw43/src/fmt.rs | 3 +-- embassy-boot-nrf/src/fmt.rs | 3 +-- embassy-boot-rp/src/fmt.rs | 3 +-- embassy-boot-stm32/src/fmt.rs | 3 +-- embassy-boot/src/fmt.rs | 3 +-- embassy-executor/src/fmt.rs | 3 +-- embassy-futures/src/fmt.rs | 3 +-- embassy-hal-internal/src/fmt.rs | 3 +-- embassy-net-adin1110/src/fmt.rs | 29 +++++++++++++++------------ embassy-net-driver-channel/src/fmt.rs | 3 +-- embassy-net-enc28j60/src/fmt.rs | 3 +-- embassy-net-esp-hosted/src/fmt.rs | 3 +-- embassy-net-ppp/src/fmt.rs | 3 +-- embassy-net/src/fmt.rs | 3 +-- embassy-nrf/src/fmt.rs | 3 +-- embassy-rp/src/fmt.rs | 3 +-- embassy-stm32-wpan/src/fmt.rs | 3 +-- embassy-stm32/src/fmt.rs | 3 +-- embassy-sync/src/fmt.rs | 3 +-- embassy-time/src/fmt.rs | 3 +-- embassy-usb-dfu/src/fmt.rs | 3 +-- embassy-usb/src/fmt.rs | 3 +-- 22 files changed, 37 insertions(+), 55 deletions(-) diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/cyw43/src/fmt.rs +++ b/cyw43/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-boot-nrf/src/fmt.rs b/embassy-boot-nrf/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-boot-nrf/src/fmt.rs +++ b/embassy-boot-nrf/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-boot-rp/src/fmt.rs b/embassy-boot-rp/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-boot-rp/src/fmt.rs +++ b/embassy-boot-rp/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-boot-stm32/src/fmt.rs b/embassy-boot-stm32/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-boot-stm32/src/fmt.rs +++ b/embassy-boot-stm32/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-boot/src/fmt.rs b/embassy-boot/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-boot/src/fmt.rs +++ b/embassy-boot/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-executor/src/fmt.rs b/embassy-executor/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-executor/src/fmt.rs +++ b/embassy-executor/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-futures/src/fmt.rs +++ b/embassy-futures/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-hal-internal/src/fmt.rs b/embassy-hal-internal/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-hal-internal/src/fmt.rs +++ b/embassy-hal-internal/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-net-adin1110/src/fmt.rs b/embassy-net-adin1110/src/fmt.rs index 12737c690..2ac42c557 100644 --- a/embassy-net-adin1110/src/fmt.rs +++ b/embassy-net-adin1110/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -83,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -113,7 +116,7 @@ macro_rules! trace { #[cfg(feature = "defmt")] ::defmt::trace!($s $(, $x)*); #[cfg(not(any(feature = "log", feature="defmt")))] - let _ignored = ($( & $x ),*); + let _ = ($( & $x ),*); } }; } @@ -126,7 +129,7 @@ macro_rules! debug { #[cfg(feature = "defmt")] ::defmt::debug!($s $(, $x)*); #[cfg(not(any(feature = "log", feature="defmt")))] - let _ignored = ($( & $x ),*); + let _ = ($( & $x ),*); } }; } @@ -139,7 +142,7 @@ macro_rules! info { #[cfg(feature = "defmt")] ::defmt::info!($s $(, $x)*); #[cfg(not(any(feature = "log", feature="defmt")))] - let _ignored = ($( & $x ),*); + let _ = ($( & $x ),*); } }; } @@ -152,7 +155,7 @@ macro_rules! warn { #[cfg(feature = "defmt")] ::defmt::warn!($s $(, $x)*); #[cfg(not(any(feature = "log", feature="defmt")))] - let _ignored = ($( & $x ),*); + let _ = ($( & $x ),*); } }; } @@ -165,7 +168,7 @@ macro_rules! error { #[cfg(feature = "defmt")] ::defmt::error!($s $(, $x)*); #[cfg(not(any(feature = "log", feature="defmt")))] - let _ignored = ($( & $x ),*); + let _ = ($( & $x ),*); } }; } @@ -226,7 +229,7 @@ impl Try for Result { } } -pub struct Bytes<'a>(pub &'a [u8]); +pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { diff --git a/embassy-net-driver-channel/src/fmt.rs b/embassy-net-driver-channel/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net-driver-channel/src/fmt.rs +++ b/embassy-net-driver-channel/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-net-enc28j60/src/fmt.rs b/embassy-net-enc28j60/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net-enc28j60/src/fmt.rs +++ b/embassy-net-enc28j60/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-net-esp-hosted/src/fmt.rs b/embassy-net-esp-hosted/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net-esp-hosted/src/fmt.rs +++ b/embassy-net-esp-hosted/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-net-ppp/src/fmt.rs b/embassy-net-ppp/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net-ppp/src/fmt.rs +++ b/embassy-net-ppp/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-net/src/fmt.rs b/embassy-net/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net/src/fmt.rs +++ b/embassy-net/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-nrf/src/fmt.rs b/embassy-nrf/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-nrf/src/fmt.rs +++ b/embassy-nrf/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-rp/src/fmt.rs b/embassy-rp/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-rp/src/fmt.rs +++ b/embassy-rp/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-stm32-wpan/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-stm32-wpan/src/fmt.rs +++ b/embassy-stm32-wpan/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-stm32/src/fmt.rs +++ b/embassy-stm32/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-sync/src/fmt.rs +++ b/embassy-sync/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-time/src/fmt.rs b/embassy-time/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-time/src/fmt.rs +++ b/embassy-time/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-usb-dfu/src/fmt.rs b/embassy-usb-dfu/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-usb-dfu/src/fmt.rs +++ b/embassy-usb-dfu/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { diff --git a/embassy-usb/src/fmt.rs b/embassy-usb/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-usb/src/fmt.rs +++ b/embassy-usb/src/fmt.rs @@ -1,5 +1,5 @@ #![macro_use] -#![allow(unused_macros)] +#![allow(unused)] use core::fmt::{Debug, Display, LowerHex}; @@ -229,7 +229,6 @@ impl Try for Result { } } -#[allow(unused)] pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { From eca9aac194580956c851e42565546e5fc50d8070 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 20 Mar 2024 14:54:25 +0100 Subject: [PATCH 725/760] Fix warnings in recent nightly. --- embassy-executor-macros/src/util/ctxt.rs | 1 - embassy-executor/src/raw/mod.rs | 2 +- embassy-net-enc28j60/src/lib.rs | 7 +++---- embassy-net-tuntap/src/lib.rs | 2 +- embassy-nrf/src/gpio.rs | 2 ++ embassy-nrf/src/gpiote.rs | 2 ++ embassy-nrf/src/timer.rs | 2 -- embassy-rp/src/dma.rs | 2 +- embassy-rp/src/flash.rs | 2 -- embassy-rp/src/float/mod.rs | 1 + embassy-rp/src/gpio.rs | 2 -- embassy-rp/src/lib.rs | 3 ++- embassy-rp/src/relocate.rs | 2 -- embassy-rp/src/uart/buffered.rs | 10 ++-------- embassy-rp/src/usb.rs | 11 ---------- embassy-stm32-wpan/src/consts.rs | 2 -- embassy-stm32/src/can/bx/mod.rs | 2 +- embassy-stm32/src/can/bxcan.rs | 1 - embassy-stm32/src/can/fd/message_ram/mod.rs | 20 ------------------- embassy-stm32/src/can/fdcan.rs | 4 ++-- embassy-stm32/src/dma/mod.rs | 1 + embassy-stm32/src/flash/f0.rs | 1 - embassy-stm32/src/flash/f1f3.rs | 1 - embassy-stm32/src/flash/f4.rs | 1 - embassy-stm32/src/flash/f7.rs | 1 - embassy-stm32/src/flash/g.rs | 1 - embassy-stm32/src/flash/h7.rs | 1 - embassy-stm32/src/flash/u5.rs | 1 - embassy-stm32/src/i2c/v1.rs | 1 - embassy-stm32/src/i2c/v2.rs | 1 - embassy-stm32/src/rtc/datetime.rs | 5 +---- embassy-stm32/src/sdmmc/mod.rs | 2 -- embassy-stm32/src/time_driver.rs | 1 - embassy-stm32/src/timer/complementary_pwm.rs | 1 - embassy-stm32/src/timer/simple_pwm.rs | 1 - embassy-stm32/src/uid.rs | 2 +- embassy-stm32/src/usart/buffered.rs | 5 +---- embassy-stm32/src/usb/otg.rs | 4 ++-- embassy-stm32/src/usb/usb.rs | 11 ---------- examples/rp/src/bin/multicore.rs | 12 +++++++---- examples/std/src/bin/net.rs | 2 -- examples/std/src/bin/net_dns.rs | 2 -- examples/std/src/bin/tcp_accept.rs | 1 - examples/stm32f2/src/bin/pll.rs | 2 -- examples/stm32h7/src/bin/camera.rs | 4 ++-- .../src/bin/spe_adin1110_http_server.rs | 2 +- tests/rp/src/bin/gpio_multicore.rs | 12 +++++++---- tests/rp/src/bin/i2c.rs | 12 +++++++---- tests/rp/src/bin/multicore.rs | 12 +++++++---- 49 files changed, 59 insertions(+), 124 deletions(-) diff --git a/embassy-executor-macros/src/util/ctxt.rs b/embassy-executor-macros/src/util/ctxt.rs index 74c872c3c..9c78cda01 100644 --- a/embassy-executor-macros/src/util/ctxt.rs +++ b/embassy-executor-macros/src/util/ctxt.rs @@ -7,7 +7,6 @@ use std::thread; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; -use syn; /// A type to collect errors together and format them. /// diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3d5e3ab9f..d9ea5c005 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -30,7 +30,7 @@ use core::ptr::NonNull; use core::task::{Context, Poll}; #[cfg(feature = "integrated-timers")] -use embassy_time_driver::{self, AlarmHandle}; +use embassy_time_driver::AlarmHandle; #[cfg(feature = "rtos-trace")] use rtos_trace::trace; diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs index f18134927..dda35f498 100644 --- a/embassy-net-enc28j60/src/lib.rs +++ b/embassy-net-enc28j60/src/lib.rs @@ -17,7 +17,6 @@ mod phy; mod traits; use core::cmp; -use core::convert::TryInto; use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; use embassy_time::Duration; @@ -645,8 +644,8 @@ where Self: 'a; fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - let rx_buf = unsafe { &mut RX_BUF }; - let tx_buf = unsafe { &mut TX_BUF }; + let rx_buf = unsafe { &mut *core::ptr::addr_of_mut!(RX_BUF) }; + let tx_buf = unsafe { &mut *core::ptr::addr_of_mut!(TX_BUF) }; if let Some(n) = self.receive(rx_buf) { Some((RxToken { buf: &mut rx_buf[..n] }, TxToken { buf: tx_buf, eth: self })) } else { @@ -656,7 +655,7 @@ where } fn transmit(&mut self, _cx: &mut core::task::Context) -> Option> { - let tx_buf = unsafe { &mut TX_BUF }; + let tx_buf = unsafe { &mut *core::ptr::addr_of_mut!(TX_BUF) }; Some(TxToken { buf: tx_buf, eth: self }) } diff --git a/embassy-net-tuntap/src/lib.rs b/embassy-net-tuntap/src/lib.rs index de30934eb..56f55fba1 100644 --- a/embassy-net-tuntap/src/lib.rs +++ b/embassy-net-tuntap/src/lib.rs @@ -6,7 +6,7 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::task::Context; use async_io::Async; -use embassy_net_driver::{self, Capabilities, Driver, HardwareAddress, LinkState}; +use embassy_net_driver::{Capabilities, Driver, HardwareAddress, LinkState}; use log::*; /// Get the MTU of the given interface. diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 3649ea61a..f2353f21d 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -473,10 +473,12 @@ impl sealed::Pin for AnyPin { // ==================== +#[cfg(not(feature = "_nrf51"))] pub(crate) trait PselBits { fn psel_bits(&self) -> u32; } +#[cfg(not(feature = "_nrf51"))] impl<'a, P: Pin> PselBits for Option> { #[inline] fn psel_bits(&self) -> u32 { diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 12f4ed0a0..4a28279a9 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -167,8 +167,10 @@ unsafe fn handle_gpiote_interrupt() { } } +#[cfg(not(feature = "_nrf51"))] struct BitIter(u32); +#[cfg(not(feature = "_nrf51"))] impl Iterator for BitIter { type Item = u32; diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 3c35baee5..2970ad3f2 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -21,8 +21,6 @@ pub(crate) mod sealed { fn regs() -> &'static pac::timer0::RegisterBlock; } pub trait ExtendedInstance {} - - pub trait TimerType {} } /// Basic Timer instance. diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 088a842a1..44aabce6b 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -96,7 +96,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>( ) -> Transfer<'a, C> { copy_inner( ch, - &mut DUMMY as *const u32, + core::ptr::addr_of_mut!(DUMMY) as *const u32, to as *mut u32, len, W::size(), diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 2d673cf6c..68b1ecab3 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -420,8 +420,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash #[allow(dead_code)] mod ram_helpers { - use core::marker::PhantomData; - use super::*; use crate::rom_data; diff --git a/embassy-rp/src/float/mod.rs b/embassy-rp/src/float/mod.rs index 945afff90..3ad6f1c50 100644 --- a/embassy-rp/src/float/mod.rs +++ b/embassy-rp/src/float/mod.rs @@ -89,6 +89,7 @@ pub(crate) trait Float: } /// Returns true if `self` is infinity + #[allow(unused)] fn is_infinity(self) -> bool { (self.repr() & (Self::EXPONENT_MASK | Self::SIGNIFICAND_MASK)) == Self::EXPONENT_MASK } diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 62eeb4cf6..ddba8f8fb 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -976,8 +976,6 @@ impl_pin!(PIN_QSPI_SD3, Bank::Qspi, 5); // ==================== mod eh02 { - use core::convert::Infallible; - use super::*; impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 7092b3fab..d91cea410 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -274,7 +274,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> { extern "C" { static mut _stack_end: usize; } - unsafe { install_stack_guard(&mut _stack_end as *mut usize) } + unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) } } #[inline(always)] @@ -354,6 +354,7 @@ pub fn init(config: config::Config) -> Peripherals { /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. trait RegExt { + #[allow(unused)] fn write_xor(&self, f: impl FnOnce(&mut T) -> R) -> R; fn write_set(&self, f: impl FnOnce(&mut T) -> R) -> R; fn write_clear(&self, f: impl FnOnce(&mut T) -> R) -> R; diff --git a/embassy-rp/src/relocate.rs b/embassy-rp/src/relocate.rs index b35b4ed72..6139d892f 100644 --- a/embassy-rp/src/relocate.rs +++ b/embassy-rp/src/relocate.rs @@ -1,5 +1,3 @@ -use core::iter::Iterator; - use pio::{Program, SideSet, Wrap}; pub struct CodeIterator<'a, I> diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 99c958129..8178cd801 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -1,17 +1,11 @@ //! Buffered UART driver. -use core::future::{poll_fn, Future}; +use core::future::Future; use core::slice; -use core::task::Poll; -use atomic_polyfill::{AtomicU8, Ordering}; +use atomic_polyfill::AtomicU8; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; -use embassy_sync::waitqueue::AtomicWaker; -use embassy_time::Timer; use super::*; -use crate::clocks::clk_peri_freq; -use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{interrupt, RegExt}; pub struct State { tx_waker: AtomicWaker, diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 905661d64..d68dee4a3 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -465,7 +465,6 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { trait Dir { fn dir() -> Direction; - fn waker(i: usize) -> &'static AtomicWaker; } /// Type for In direction. @@ -474,11 +473,6 @@ impl Dir for In { fn dir() -> Direction { Direction::In } - - #[inline] - fn waker(i: usize) -> &'static AtomicWaker { - &EP_IN_WAKERS[i] - } } /// Type for Out direction. @@ -487,11 +481,6 @@ impl Dir for Out { fn dir() -> Direction { Direction::Out } - - #[inline] - fn waker(i: usize) -> &'static AtomicWaker { - &EP_OUT_WAKERS[i] - } } /// Endpoint for RP USB driver. diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs index bd70851ea..6aaef1d35 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs @@ -1,5 +1,3 @@ -use core::convert::TryFrom; - use crate::evt::CsEvt; use crate::PacketHeader; diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 33e702c6e..a369ae6fd 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -28,7 +28,7 @@ pub mod filter; #[allow(clippy::all)] // generated code use core::cmp::{Ord, Ordering}; -use core::convert::{Infallible, Into, TryInto}; +use core::convert::Infallible; use core::marker::PhantomData; use core::mem; diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index bb7cc3d7f..1a625bdc4 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -1,4 +1,3 @@ -use core::convert::AsMut; use core::future::poll_fn; use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; diff --git a/embassy-stm32/src/can/fd/message_ram/mod.rs b/embassy-stm32/src/can/fd/message_ram/mod.rs index 830edf3bb..040a999b4 100644 --- a/embassy-stm32/src/can/fd/message_ram/mod.rs +++ b/embassy-stm32/src/can/fd/message_ram/mod.rs @@ -140,26 +140,6 @@ pub(crate) struct _TxBufferElement; impl generic::Readable for TxBufferElementHeader {} impl generic::Writable for TxBufferElementHeader {} -/// FdCan Message RAM instance. -/// -/// # Safety -/// -/// It is only safe to implement this trait, when: -/// -/// * The implementing type has ownership of the Message RAM, preventing any -/// other accesses to the register block. -/// * `MSG_RAM` is a pointer to the Message RAM block and can be safely accessed -/// for as long as ownership or a borrow of the implementing type is present. -pub unsafe trait Instance { - const MSG_RAM: *mut RegisterBlock; - fn msg_ram(&self) -> &RegisterBlock { - unsafe { &*Self::MSG_RAM } - } - fn msg_ram_mut(&mut self) -> &mut RegisterBlock { - unsafe { &mut *Self::MSG_RAM } - } -} - // Ensure the RegisterBlock is the same size as on pg 1957 of RM0440. static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]); static_assertions::assert_eq_size!(Receive, [u32; 54]); diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index fe8969a5a..4c40f10e3 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -883,9 +883,9 @@ macro_rules! impl_fdcan { fn ram() -> &'static crate::pac::fdcanram::Fdcanram { &crate::pac::$msg_ram_inst } - unsafe fn mut_state() -> & 'static mut sealed::State { + unsafe fn mut_state() -> &'static mut sealed::State { static mut STATE: sealed::State = sealed::State::new(); - & mut STATE + &mut *core::ptr::addr_of_mut!(STATE) } fn state() -> &'static sealed::State { unsafe { peripherals::$inst::mut_state() } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index d5e88a20a..2f98b9857 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -44,6 +44,7 @@ pub(crate) mod sealed { fn id(&self) -> u8; } pub trait ChannelInterrupt { + #[cfg_attr(not(feature = "rt"), allow(unused))] unsafe fn on_irq(); } } diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index e0c76e6b2..e2f135208 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -1,4 +1,3 @@ -use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs index e7790369a..b16354a74 100644 --- a/embassy-stm32/src/flash/f1f3.rs +++ b/embassy-stm32/src/flash/f1f3.rs @@ -1,4 +1,3 @@ -use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 57447bea5..00e61f2d2 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -1,4 +1,3 @@ -use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, AtomicBool, Ordering}; diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 0f512bbc4..72de0b445 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -1,4 +1,3 @@ -use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index b69c4343b..6a5adc941 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -1,4 +1,3 @@ -use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 743925e17..e32a82eef 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -1,4 +1,3 @@ -use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs index 3787082f9..580c490da 100644 --- a/embassy-stm32/src/flash/u5.rs +++ b/embassy-stm32/src/flash/u5.rs @@ -1,4 +1,3 @@ -use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index f1ed7ca40..9f29ed5e0 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -15,7 +15,6 @@ use embedded_hal_1::i2c::Operation; use super::*; use crate::dma::Transfer; use crate::pac::i2c; -use crate::time::Hertz; // /!\ /!\ // /!\ Implementation note! /!\ diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 1ac2740df..8baf2849d 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -9,7 +9,6 @@ use embedded_hal_1::i2c::Operation; use super::*; use crate::dma::Transfer; use crate::pac::i2c; -use crate::time::Hertz; pub(crate) unsafe fn on_interrupt() { let regs = T::regs(); diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index ef92fa4bb..2bad79923 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -1,8 +1,5 @@ #[cfg(feature = "chrono")] -use core::convert::From; - -#[cfg(feature = "chrono")] -use chrono::{self, Datelike, NaiveDate, Timelike, Weekday}; +use chrono::{Datelike, NaiveDate, Timelike, Weekday}; #[cfg(any(feature = "defmt", feature = "time"))] use crate::peripherals::RTC; diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index fa1f710d8..c0b3a2183 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1427,8 +1427,6 @@ pub(crate) mod sealed { fn regs() -> RegBlock; fn state() -> &'static AtomicWaker; } - - pub trait Pins {} } /// SDMMC instance trait. diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 37b2e7526..9be56d3d1 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -1,7 +1,6 @@ #![allow(non_snake_case)] use core::cell::Cell; -use core::convert::TryInto; use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use core::{mem, ptr}; diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 72f1ec864..723e8506b 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -10,7 +10,6 @@ use super::*; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::{AnyPin, OutputType}; -use crate::time::Hertz; use crate::Peripheral; /// Complementary PWM pin wrapper. diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 6df2f66ec..4669fc6cc 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -8,7 +8,6 @@ use super::*; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::{AnyPin, OutputType}; -use crate::time::Hertz; use crate::Peripheral; /// Channel 1 marker type. diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs index aa13586f8..5e38532bd 100644 --- a/embassy-stm32/src/uid.rs +++ b/embassy-stm32/src/uid.rs @@ -27,5 +27,5 @@ pub fn uid_hex_bytes() -> &'static [u8; 24] { LOADED = true; } }); - unsafe { &UID_HEX } + unsafe { &*core::ptr::addr_of!(UID_HEX) } } diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index c11e3382f..683b0f8b2 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -1,13 +1,10 @@ -use core::future::poll_fn; use core::slice; -use core::sync::atomic::{AtomicBool, Ordering}; -use core::task::Poll; +use core::sync::atomic::AtomicBool; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_sync::waitqueue::AtomicWaker; use super::*; -use crate::interrupt::typelevel::Interrupt; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 80a08f3c5..d4095b466 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -6,8 +6,8 @@ use core::task::Poll; use embassy_hal_internal::{into_ref, Peripheral}; use embassy_sync::waitqueue::AtomicWaker; use embassy_usb_driver::{ - self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, - EndpointOut, EndpointType, Event, Unsupported, + Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, + EndpointType, Event, Unsupported, }; use futures::future::poll_fn; diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 1fb2c9ebb..c4f9140da 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -637,7 +637,6 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { trait Dir { fn dir() -> Direction; - fn waker(i: usize) -> &'static AtomicWaker; } /// Marker type for the "IN" direction. @@ -646,11 +645,6 @@ impl Dir for In { fn dir() -> Direction { Direction::In } - - #[inline] - fn waker(i: usize) -> &'static AtomicWaker { - &EP_IN_WAKERS[i] - } } /// Marker type for the "OUT" direction. @@ -659,11 +653,6 @@ impl Dir for Out { fn dir() -> Direction { Direction::Out } - - #[inline] - fn waker(i: usize) -> &'static AtomicWaker { - &EP_OUT_WAKERS[i] - } } /// USB endpoint. diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index c7b087476..7cb546c91 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs @@ -30,10 +30,14 @@ fn main() -> ! { let p = embassy_rp::init(Default::default()); let led = Output::new(p.PIN_25, Level::Low); - spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { - let executor1 = EXECUTOR1.init(Executor::new()); - executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); - }); + spawn_core1( + p.CORE1, + unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, + move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); + }, + ); let executor0 = EXECUTOR0.init(Executor::new()); executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index dad93d0a1..59813d8cb 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -1,5 +1,3 @@ -use std::default::Default; - use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index fca1e076e..3b6a3de37 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs @@ -1,5 +1,3 @@ -use std::default::Default; - use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::dns::DnsQueryType; diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 00ccd83a7..e8b6eaa6c 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs @@ -1,5 +1,4 @@ use core::fmt::Write as _; -use std::default::Default; use clap::Parser; use embassy_executor::{Executor, Spawner}; diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index e32f283d1..e39e2daec 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs @@ -1,8 +1,6 @@ #![no_std] #![no_main] -use core::convert::TryFrom; - use defmt::*; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index e5a104baf..170a5aa28 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -78,9 +78,9 @@ async fn main(_spawner: Spawner) { ); defmt::info!("attempting capture"); - defmt::unwrap!(dcmi.capture(unsafe { &mut FRAME }).await); + defmt::unwrap!(dcmi.capture(unsafe { &mut *core::ptr::addr_of_mut!(FRAME) }).await); - defmt::info!("captured frame: {:x}", unsafe { &FRAME }); + defmt::info!("captured frame: {:x}", unsafe { &*core::ptr::addr_of!(FRAME) }); defmt::info!("main loop running"); loop { diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 32bfab6eb..343e09e68 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -42,7 +42,7 @@ bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; }); -use embassy_net_adin1110::{self, Device, Runner, ADIN1110}; +use embassy_net_adin1110::{Device, Runner, ADIN1110}; use embedded_hal_bus::spi::ExclusiveDevice; use hal::gpio::Pull; use hal::i2c::Config as I2C_Config; diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs index 8aed9b80c..e9c6f3122 100644 --- a/tests/rp/src/bin/gpio_multicore.rs +++ b/tests/rp/src/bin/gpio_multicore.rs @@ -21,10 +21,14 @@ static CHANNEL1: Channel = Channel::new(); #[cortex_m_rt::entry] fn main() -> ! { let p = embassy_rp::init(Default::default()); - spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { - let executor1 = EXECUTOR1.init(Executor::new()); - executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(p.PIN_1)))); - }); + spawn_core1( + p.CORE1, + unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, + move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(p.PIN_1)))); + }, + ); let executor0 = EXECUTOR0.init(Executor::new()); executor0.run(|spawner| unwrap!(spawner.spawn(core0_task(p.PIN_0)))); } diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index 153b37999..9615007bd 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs @@ -210,10 +210,14 @@ async fn controller_task(con: &mut i2c::I2c<'static, I2C0, i2c::Async>) { config.addr = DEV_ADDR as u16; let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); - spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { - let executor1 = EXECUTOR1.init(Executor::new()); - executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); - }); + spawn_core1( + p.CORE1, + unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, + move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); + }, + ); let c_sda = p.PIN_21; let c_scl = p.PIN_20; diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs index 60d9f85ec..783ea0f27 100644 --- a/tests/rp/src/bin/multicore.rs +++ b/tests/rp/src/bin/multicore.rs @@ -19,10 +19,14 @@ static CHANNEL1: Channel = Channel::new(); #[cortex_m_rt::entry] fn main() -> ! { let p = embassy_rp::init(Default::default()); - spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { - let executor1 = EXECUTOR1.init(Executor::new()); - executor1.run(|spawner| unwrap!(spawner.spawn(core1_task()))); - }); + spawn_core1( + p.CORE1, + unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, + move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| unwrap!(spawner.spawn(core1_task()))); + }, + ); let executor0 = EXECUTOR0.init(Executor::new()); executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); } From e5b9b5b3e95a82dbbc15c0688781bfb6fee572ac Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 20 Mar 2024 16:37:42 +0100 Subject: [PATCH 726/760] Update Nightly in CI. --- 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 b8a7db353..98696fd2b 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2023-12-20" +channel = "nightly-2024-03-20" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", From fb9d42684bed1d0625da5b582e64c5fa56b7fd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Wed, 20 Mar 2024 19:59:17 +0100 Subject: [PATCH 727/760] stm32: Fix psc compile error with current stm32-data Commit https://github.com/embassy-rs/stm32-data/commit/cc525f1b252c91272529cbea1d3d4399b43c60b4 has changed the definition of the `psc` register. Update timer/mod.rs to reflect the stm32-data change. --- embassy-stm32/src/timer/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index ef893c7f5..e5e84c255 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -97,7 +97,7 @@ pub(crate) mod sealed { let arr = unwrap!(u16::try_from(divide_by - 1)); let regs = Self::regs_core(); - regs.psc().write(|r| r.set_psc(psc)); + regs.psc().write_value(psc); regs.arr().write(|r| r.set_arr(arr)); regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); @@ -137,7 +137,7 @@ pub(crate) mod sealed { let regs = Self::regs_core(); let arr = regs.arr().read().arr(); - let psc = regs.psc().read().psc(); + let psc = regs.psc().read(); timer_f / arr / (psc + 1) } @@ -378,7 +378,7 @@ pub(crate) mod sealed { let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()); let regs = Self::regs_gp32(); - regs.psc().write(|r| r.set_psc(psc)); + regs.psc().write_value(psc); regs.arr().write_value(arr); regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); @@ -392,7 +392,7 @@ pub(crate) mod sealed { let regs = Self::regs_gp32(); let arr = regs.arr().read(); - let psc = regs.psc().read().psc(); + let psc = regs.psc().read(); timer_f / arr / (psc + 1) } From ab7c767c464c566fdec6fe7c0f72f084a4c891de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Wed, 20 Mar 2024 20:31:02 +0100 Subject: [PATCH 728/760] Bump stm32-data to latest tag. --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d3626610e..7c6312f6c 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-c8b32ecae7d70cea2705095c4fc6bd5f59d238d5" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f84633553331c2d154ee72de779a40cbb10fd1bd" } vcell = "0.1.3" nb = "1.0.0" stm32-fmc = "0.3.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } 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-c8b32ecae7d70cea2705095c4fc6bd5f59d238d5", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f84633553331c2d154ee72de779a40cbb10fd1bd", default-features = false, features = ["metadata"]} [features] From 92fa49f5023a2f1932bfb122efd93372f40084a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Wed, 20 Mar 2024 20:42:03 +0100 Subject: [PATCH 729/760] Also fix time_driver.rs --- embassy-stm32/src/time_driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 9be56d3d1..e78f81dca 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -286,7 +286,7 @@ impl RtcDriver { Ok(n) => n, }; - r.psc().write(|w| w.set_psc(psc)); + r.psc().write_value(psc); r.arr().write(|w| w.set_arr(u16::MAX)); // Set URS, generate update and clear URS From 53ed4b8b2e79ee41692132793aa7910dd972e524 Mon Sep 17 00:00:00 2001 From: Felix Lelchuk <4553555+flelchuk@users.noreply.github.com> Date: Wed, 20 Mar 2024 21:15:22 +0100 Subject: [PATCH 730/760] usb-logger: avoid data loss at pipe wraparound --- embassy-usb-logger/src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index da5ff0f36..6f4836d21 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -151,7 +151,17 @@ struct Writer<'d, const N: usize>(&'d Pipe); impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { - let _ = self.0.try_write(s.as_bytes()); + // The Pipe is implemented in such way that we cannot + // write across the wraparound discontinuity. + let b = s.as_bytes(); + if let Ok(n) = self.0.try_write(b) { + if n < b.len() { + // We wrote some data but not all, attempt again + // as the reason might be a wraparound in the + // ring buffer, which resolves on second attempt. + let _ = self.0.try_write(&b[n..]); + } + } Ok(()) } } From 08e2ba9d74a1ea1a17b67d362db14839d26dfb77 Mon Sep 17 00:00:00 2001 From: Ralf Date: Thu, 21 Mar 2024 08:35:19 +0100 Subject: [PATCH 731/760] STM32 BufferedUart: wake receive task for each received byte Fixes https://github.com/embassy-rs/embassy/issues/2719 --- embassy-stm32/src/usart/buffered.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 683b0f8b2..51862e185 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -52,7 +52,7 @@ impl interrupt::typelevel::Handler for Interrupt // FIXME: Should we disable any further RX interrupts when the buffer becomes full. } - if state.rx_buf.is_full() { + if !state.rx_buf.is_empty() { state.rx_waker.wake(); } } From 3ae19bb8f983b627d067e6167db4a7f19af28d1e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 21 Mar 2024 15:15:51 +0100 Subject: [PATCH 732/760] Update stable Rust to 1.77 --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a6fe52ee2..2f5d17069 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.75" +channel = "1.77" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", From 10597e3b4d18818d322be95e1a57656855f99852 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Thu, 21 Mar 2024 19:18:35 +0100 Subject: [PATCH 733/760] nRF52840/config: add dcdc voltage parameter address #2700 --- embassy-nrf/src/lib.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 718f229a3..3457dd933 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -225,10 +225,31 @@ pub mod config { /// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used. #[cfg(feature = "nrf52840")] pub reg0: bool, + /// Configure the voltage of the first stage DCDC. It is stored in non-volatile memory (UICR.REGOUT0 register); pass None to not touch it. + #[cfg(feature = "nrf52840")] + pub reg0_voltage: Option, /// Config for the second stage DCDC (VDD -> DEC4), if disabled LDO will be used. pub reg1: bool, } + /// Output voltage setting for REG0 regulator stage. + #[cfg(feature = "nrf52840")] + pub enum Reg0Voltage { + /// 1.8 V + _1V8 = 0, + /// 2.1 V + _2V1 = 1, + /// 2.4 V + _2V4 = 2, + /// 2.7 V + _2V7 = 3, + /// 3.0 V + _3V0 = 4, + /// 3.3 V + _3v3 = 5, + //ERASED = 7, means 1.8V + } + /// Settings for enabling the built in DCDC converters. #[cfg(feature = "_nrf5340-app")] pub struct DcdcConfig { @@ -279,6 +300,8 @@ pub mod config { dcdc: DcdcConfig { #[cfg(feature = "nrf52840")] reg0: false, + #[cfg(feature = "nrf52840")] + reg0_voltage: None, reg1: false, }, #[cfg(feature = "_nrf5340-app")] @@ -337,6 +360,7 @@ mod consts { pub const UICR_PSELRESET2: *mut u32 = 0x10001204 as *mut u32; pub const UICR_NFCPINS: *mut u32 = 0x1000120C as *mut u32; pub const UICR_APPROTECT: *mut u32 = 0x10001208 as *mut u32; + pub const UICR_REGOUT0: *mut u32 = 0x10001304 as *mut u32; pub const APPROTECT_ENABLED: u32 = 0x0000_0000; pub const APPROTECT_DISABLED: u32 = 0x0000_005a; } @@ -493,6 +517,21 @@ pub fn init(config: config::Config) -> Peripherals { } } + #[cfg(feature = "nrf52840")] + unsafe { + if let Some(value) = config.dcdc.reg0_voltage { + let value = value as u32; + let res = uicr_write_masked(consts::UICR_REGOUT0, value, 0b00000000_00000000_00000000_00000111); + needs_reset |= res == WriteResult::Written; + if res == WriteResult::Failed { + warn!( + "Failed to set regulator voltage, as UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ + To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." + ); + } + } + } + if needs_reset { cortex_m::peripheral::SCB::sys_reset(); } From a85e9c6e68fbe23aa8f1fc6a1c1e7ca935c1506a Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Fri, 22 Mar 2024 12:29:01 +0100 Subject: [PATCH 734/760] Forward the "std" feature to the critical-section crate in embassy-sync. Otherwise, using embassy-sync in unit tests will result in linker errors when using the CriticalSectionRawMutex. --- embassy-sync/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 85673026c..aaf6fab1d 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -20,7 +20,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/ target = "thumbv7em-none-eabi" [features] -std = [] +std = ["critical-section/std"] turbowakers = [] [dependencies] From 7cf6490fbaea88410c91755f57cf8703806ab4a1 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Sat, 23 Mar 2024 00:11:05 +0000 Subject: [PATCH 735/760] usb: remove device_descriptor buffer, store bytes in UsbDevice.inner instead --- embassy-usb-logger/src/lib.rs | 3 -- embassy-usb/src/builder.rs | 7 --- embassy-usb/src/descriptor.rs | 51 ++++++++++--------- embassy-usb/src/lib.rs | 9 ++-- embassy-usb/src/msos.rs | 6 +-- .../boot/application/stm32wb-dfu/src/main.rs | 2 - .../boot/bootloader/stm32wb-dfu/src/main.rs | 2 - examples/nrf52840/src/bin/usb_ethernet.rs | 2 - examples/nrf52840/src/bin/usb_hid_keyboard.rs | 2 - examples/nrf52840/src/bin/usb_hid_mouse.rs | 2 - examples/nrf52840/src/bin/usb_serial.rs | 2 - .../nrf52840/src/bin/usb_serial_multitask.rs | 2 - .../nrf52840/src/bin/usb_serial_winusb.rs | 2 - examples/rp/src/bin/pio_uart.rs | 2 - examples/rp/src/bin/usb_ethernet.rs | 2 - examples/rp/src/bin/usb_hid_keyboard.rs | 2 - examples/rp/src/bin/usb_hid_mouse.rs | 2 - examples/rp/src/bin/usb_midi.rs | 2 - examples/rp/src/bin/usb_raw.rs | 2 - examples/rp/src/bin/usb_raw_bulk.rs | 2 - examples/rp/src/bin/usb_serial.rs | 2 - examples/rp/src/bin/usb_serial_with_logger.rs | 2 - examples/stm32f1/src/bin/usb_serial.rs | 2 - examples/stm32f3/src/bin/usb_serial.rs | 2 - examples/stm32f4/src/bin/usb_ethernet.rs | 2 - examples/stm32f4/src/bin/usb_hid_keyboard.rs | 2 - examples/stm32f4/src/bin/usb_hid_mouse.rs | 2 - examples/stm32f4/src/bin/usb_raw.rs | 2 - examples/stm32f4/src/bin/usb_serial.rs | 2 - examples/stm32f7/src/bin/usb_serial.rs | 2 - examples/stm32g0/src/bin/usb_serial.rs | 2 - examples/stm32g4/src/bin/usb_serial.rs | 2 - examples/stm32h5/src/bin/usb_serial.rs | 2 - examples/stm32h7/src/bin/usb_serial.rs | 2 - examples/stm32l1/src/bin/usb_serial.rs | 2 - examples/stm32l4/src/bin/usb_serial.rs | 2 - examples/stm32l5/src/bin/usb_ethernet.rs | 2 - examples/stm32l5/src/bin/usb_hid_mouse.rs | 2 - examples/stm32l5/src/bin/usb_serial.rs | 2 - examples/stm32u5/src/bin/usb_serial.rs | 2 - 40 files changed, 33 insertions(+), 113 deletions(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 6f4836d21..34d1ca663 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -16,7 +16,6 @@ type CS = embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; /// The logger state containing buffers that must live as long as the USB peripheral. pub struct LoggerState<'d> { state: State<'d>, - device_descriptor: [u8; 32], config_descriptor: [u8; 128], bos_descriptor: [u8; 16], msos_descriptor: [u8; 256], @@ -28,7 +27,6 @@ impl<'d> LoggerState<'d> { pub fn new() -> Self { Self { state: State::new(), - device_descriptor: [0; 32], config_descriptor: [0; 128], bos_descriptor: [0; 16], msos_descriptor: [0; 256], @@ -74,7 +72,6 @@ impl UsbLogger { let mut builder = Builder::new( driver, config, - &mut state.device_descriptor, &mut state.config_descriptor, &mut state.bos_descriptor, &mut state.msos_descriptor, diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index c4705d041..c06107396 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -128,7 +128,6 @@ pub struct Builder<'d, D: Driver<'d>> { driver: D, next_string_index: u8, - device_descriptor: DescriptorWriter<'d>, config_descriptor: DescriptorWriter<'d>, bos_descriptor: BosWriter<'d>, @@ -144,7 +143,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { pub fn new( driver: D, config: Config<'d>, - device_descriptor_buf: &'d mut [u8], config_descriptor_buf: &'d mut [u8], bos_descriptor_buf: &'d mut [u8], msos_descriptor_buf: &'d mut [u8], @@ -167,11 +165,9 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { _ => panic!("invalid max_packet_size_0, the allowed values are 8, 16, 32 or 64"), } - let mut device_descriptor = DescriptorWriter::new(device_descriptor_buf); let mut config_descriptor = DescriptorWriter::new(config_descriptor_buf); let mut bos_descriptor = BosWriter::new(DescriptorWriter::new(bos_descriptor_buf)); - device_descriptor.device(&config); config_descriptor.configuration(&config); bos_descriptor.bos(); @@ -183,7 +179,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { control_buf, next_string_index: STRING_INDEX_CUSTOM_START, - device_descriptor, config_descriptor, bos_descriptor, @@ -199,7 +194,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { self.bos_descriptor.end_bos(); // Log the number of allocator bytes actually used in descriptor buffers - info!("USB: device_descriptor used: {}", self.device_descriptor.position()); info!("USB: config_descriptor used: {}", self.config_descriptor.position()); info!("USB: bos_descriptor used: {}", self.bos_descriptor.writer.position()); info!("USB: msos_descriptor used: {}", msos_descriptor.len()); @@ -209,7 +203,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { self.driver, self.config, self.handlers, - self.device_descriptor.into_buf(), self.config_descriptor.into_buf(), self.bos_descriptor.writer.into_buf(), msos_descriptor, diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index fa83ef583..eb3d1f53a 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -82,30 +82,6 @@ impl<'a> DescriptorWriter<'a> { self.position = start + length; } - pub(crate) fn device(&mut self, config: &Config) { - self.write( - descriptor_type::DEVICE, - &[ - 0x10, - 0x02, // bcdUSB 2.1 - config.device_class, // bDeviceClass - config.device_sub_class, // bDeviceSubClass - config.device_protocol, // bDeviceProtocol - config.max_packet_size_0, // bMaxPacketSize0 - config.vendor_id as u8, - (config.vendor_id >> 8) as u8, // idVendor - config.product_id as u8, - (config.product_id >> 8) as u8, // idProduct - config.device_release as u8, - (config.device_release >> 8) as u8, // bcdDevice - config.manufacturer.map_or(0, |_| 1), // iManufacturer - config.product.map_or(0, |_| 2), // iProduct - config.serial_number.map_or(0, |_| 3), // iSerialNumber - 1, // bNumConfigurations - ], - ); - } - pub(crate) fn configuration(&mut self, config: &Config) { self.num_interfaces_mark = Some(self.position + 4); @@ -269,6 +245,33 @@ impl<'a> DescriptorWriter<'a> { } } +/// Create a new Device Descriptor array. +/// +/// All device descriptors are always 18 bytes, so there's no need for +/// a variable-length buffer or DescriptorWriter. +pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] { + [ + 18, // bLength + 0x01, // bDescriptorType + 0x10, + 0x02, // bcdUSB 2.1 + config.device_class, // bDeviceClass + config.device_sub_class, // bDeviceSubClass + config.device_protocol, // bDeviceProtocol + config.max_packet_size_0, // bMaxPacketSize0 + config.vendor_id as u8, + (config.vendor_id >> 8) as u8, // idVendor + config.product_id as u8, + (config.product_id >> 8) as u8, // idProduct + config.device_release as u8, + (config.device_release >> 8) as u8, // bcdDevice + config.manufacturer.map_or(0, |_| 1), // iManufacturer + config.product.map_or(0, |_| 2), // iProduct + config.serial_number.map_or(0, |_| 3), // iSerialNumber + 1, // bNumConfigurations + ] +} + /// A writer for Binary Object Store descriptor. pub struct BosWriter<'a> { pub(crate) writer: DescriptorWriter<'a>, diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 241e33a78..d58950838 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -168,8 +168,6 @@ struct Interface { #[derive(PartialEq, Eq, Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct UsbBufferReport { - /// Number of device descriptor bytes used - pub device_descriptor_used: usize, /// Number of config descriptor bytes used pub config_descriptor_used: usize, /// Number of bos descriptor bytes used @@ -191,7 +189,7 @@ struct Inner<'d, D: Driver<'d>> { bus: D::Bus, config: Config<'d>, - device_descriptor: &'d [u8], + device_descriptor: [u8; 18], config_descriptor: &'d [u8], bos_descriptor: &'d [u8], msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, @@ -217,7 +215,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { driver: D, config: Config<'d>, handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>, - device_descriptor: &'d [u8], config_descriptor: &'d [u8], bos_descriptor: &'d [u8], msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, @@ -227,6 +224,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { // Start the USB bus. // This prevent further allocation by consuming the driver. let (bus, control) = driver.start(config.max_packet_size_0 as u16); + let device_descriptor = descriptor::device_descriptor(&config); Self { control_buf, @@ -256,7 +254,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { /// Useful for tuning buffer sizes for actual usage pub fn buffer_usage(&self) -> UsbBufferReport { UsbBufferReport { - device_descriptor_used: self.inner.device_descriptor.len(), config_descriptor_used: self.inner.config_descriptor.len(), bos_descriptor_used: self.inner.bos_descriptor.len(), msos_descriptor_used: self.inner.msos_descriptor.len(), @@ -720,7 +717,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> { match dtype { descriptor_type::BOS => InResponse::Accepted(self.bos_descriptor), - descriptor_type::DEVICE => InResponse::Accepted(self.device_descriptor), + descriptor_type::DEVICE => InResponse::Accepted(&self.device_descriptor), descriptor_type::CONFIGURATION => InResponse::Accepted(self.config_descriptor), descriptor_type::STRING => { if index == 0 { diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs index 3858c0f51..a285a3ccd 100644 --- a/embassy-usb/src/msos.rs +++ b/embassy-usb/src/msos.rs @@ -255,7 +255,7 @@ use sealed::*; unsafe fn transmute_write_to(t: &T, buf: &mut [u8]) { let bytes = core::slice::from_raw_parts((t as *const T) as *const u8, size_of::()); assert!(buf.len() >= bytes.len(), "MS OS descriptor buffer full"); - (&mut buf[..bytes.len()]).copy_from_slice(bytes); + buf[..bytes.len()].copy_from_slice(bytes); } /// Table 9. Microsoft OS 2.0 descriptor wDescriptorType values. @@ -444,9 +444,9 @@ impl CompatibleIdFeatureDescriptor { pub fn new(compatible_id: &str, sub_compatible_id: &str) -> Self { assert!(compatible_id.len() <= 8 && sub_compatible_id.len() <= 8); let mut cid = [0u8; 8]; - (&mut cid[..compatible_id.len()]).copy_from_slice(compatible_id.as_bytes()); + cid[..compatible_id.len()].copy_from_slice(compatible_id.as_bytes()); let mut scid = [0u8; 8]; - (&mut scid[..sub_compatible_id.len()]).copy_from_slice(sub_compatible_id.as_bytes()); + scid[..sub_compatible_id.len()].copy_from_slice(sub_compatible_id.as_bytes()); Self::new_raw(cid, scid) } diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 37c3d7d90..929d6802c 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -41,7 +41,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-DFU Runtime example"); config.serial_number = Some("1235678"); - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -49,7 +48,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index d989fbfdf..093b39f9d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -49,7 +49,6 @@ fn main() -> ! { let mut buffer = AlignedBuffer([0; WRITE_SIZE]); let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 4096]; @@ -57,7 +56,6 @@ fn main() -> ! { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index 3469c6e5f..a7e5c2668 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -70,7 +70,6 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; // Create embassy-usb DeviceBuilder using the driver and config. - static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); @@ -78,7 +77,6 @@ async fn main(spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut DEVICE_DESC.init([0; 256])[..], &mut CONFIG_DESC.init([0; 256])[..], &mut BOS_DESC.init([0; 256])[..], &mut MSOS_DESC.init([0; 128])[..], diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 3e86590c4..52f081487 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -50,7 +50,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; @@ -63,7 +62,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 04ad841b7..5d2837793 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -43,7 +43,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; @@ -55,7 +54,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index aff539b1b..02048e692 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -48,7 +48,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; @@ -59,7 +58,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 4e8118fb8..895cca8b9 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -67,7 +67,6 @@ async fn main(spawner: Spawner) { let state = STATE.init(State::new()); // Create embassy-usb DeviceBuilder using the driver and config. - static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); @@ -75,7 +74,6 @@ async fn main(spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut DEVICE_DESC.init([0; 256])[..], &mut CONFIG_DESC.init([0; 256])[..], &mut BOS_DESC.init([0; 256])[..], &mut MSOS_DESC.init([0; 128])[..], diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index 060f9ba94..c6675a3d3 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -53,7 +53,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; @@ -64,7 +63,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index a07f1c180..53b696309 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -60,7 +60,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -70,7 +69,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 01f0d5967..f1b124efa 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -64,14 +64,12 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; // Create embassy-usb DeviceBuilder using the driver and config. - static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); let mut builder = Builder::new( driver, config, - &mut DEVICE_DESC.init([0; 256])[..], &mut CONFIG_DESC.init([0; 256])[..], &mut BOS_DESC.init([0; 256])[..], &mut [], // no msos descriptors diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index b5ac16245..710be8d13 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -36,7 +36,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; // You can also add a Microsoft OS descriptor. @@ -50,7 +49,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index afebd8813..e8b399cb1 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -39,7 +39,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; // You can also add a Microsoft OS descriptor. @@ -53,7 +52,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs index 95306a35c..11db1b2e1 100644 --- a/examples/rp/src/bin/usb_midi.rs +++ b/examples/rp/src/bin/usb_midi.rs @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -54,7 +53,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs index a6c8a5b2e..97e7e0244 100644 --- a/examples/rp/src/bin/usb_raw.rs +++ b/examples/rp/src/bin/usb_raw.rs @@ -93,7 +93,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; @@ -106,7 +105,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs index 0dc8e9f72..331c3da4c 100644 --- a/examples/rp/src/bin/usb_raw_bulk.rs +++ b/examples/rp/src/bin/usb_raw_bulk.rs @@ -71,7 +71,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; @@ -80,7 +79,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index ab24a994c..3c9bc96dd 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -56,7 +55,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs index 4ba4fc25c..f9cfdef94 100644 --- a/examples/rp/src/bin/usb_serial_with_logger.rs +++ b/examples/rp/src/bin/usb_serial_with_logger.rs @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -57,7 +56,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index 1ae6c1dee..ee99acf41 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs @@ -60,7 +60,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 7]; @@ -70,7 +69,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index ee1c43afd..5760f2c1c 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs @@ -54,7 +54,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 7]; @@ -64,7 +63,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 405cce6bc..d2cbeea1b 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -89,14 +89,12 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; // Create embassy-usb DeviceBuilder using the driver and config. - static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); let mut builder = Builder::new( driver, config, - &mut DEVICE_DESC.init([0; 256])[..], &mut CONFIG_DESC.init([0; 256])[..], &mut BOS_DESC.init([0; 256])[..], &mut [], // no msos descriptors diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 6c25a0a64..a799b4e72 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -69,7 +69,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; // You can also add a Microsoft OS descriptor. @@ -84,7 +83,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index d4725d597..0bc236119 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -64,7 +64,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -76,7 +75,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index 15a98ff8b..4e583aeb8 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -117,7 +117,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; @@ -130,7 +129,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 6080b34a8..f3a375d31 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -64,7 +64,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -74,7 +73,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 26ecf3bc8..39a5512f4 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -64,7 +64,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -74,7 +73,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs index 8b9915626..162dfd86b 100644 --- a/examples/stm32g0/src/bin/usb_serial.rs +++ b/examples/stm32g0/src/bin/usb_serial.rs @@ -36,7 +36,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 7]; @@ -46,7 +45,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index dc95aa6e5..dbe8f27c1 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -56,7 +56,6 @@ async fn main(_spawner: Spawner) { config.device_protocol = 0x01; config.composite_with_iads = true; - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -66,7 +65,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 83477c8fa..4f86bb342 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -65,7 +65,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -75,7 +74,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index c3ddda72a..576506ad3 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -65,7 +65,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -75,7 +74,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs index f738ea358..653bbd6d2 100644 --- a/examples/stm32l1/src/bin/usb_serial.rs +++ b/examples/stm32l1/src/bin/usb_serial.rs @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { config.device_protocol = 0x01; config.composite_with_iads = true; - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -56,7 +55,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 047234d60..198504b59 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -60,7 +60,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -70,7 +69,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index dc1e7022d..7f73fd677 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -79,14 +79,12 @@ async fn main(spawner: Spawner) { config.device_protocol = 0x01; // Create embassy-usb DeviceBuilder using the driver and config. - static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); let mut builder = Builder::new( driver, config, - &mut DEVICE_DESC.init([0; 256])[..], &mut CONFIG_DESC.init([0; 256])[..], &mut BOS_DESC.init([0; 256])[..], &mut [], // no msos descriptors diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index b86fba455..9d30205bb 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -51,7 +51,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -62,7 +61,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 5e2378b58..a64bda31b 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -47,7 +47,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 7]; @@ -57,7 +56,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 33e02ce3b..6a313efb0 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -61,7 +61,6 @@ async fn main(_spawner: Spawner) { // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut device_descriptor = [0; 256]; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; @@ -71,7 +70,6 @@ async fn main(_spawner: Spawner) { let mut builder = Builder::new( driver, config, - &mut device_descriptor, &mut config_descriptor, &mut bos_descriptor, &mut [], // no msos descriptors From 389cbc0a77daea15decae706818f104d89446020 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Mar 2024 00:35:06 +0100 Subject: [PATCH 736/760] stm32/timer: simplify traits, convert from trait methods to struct. --- ci.sh | 1 + embassy-stm32/src/time_driver.rs | 34 +- embassy-stm32/src/timer/complementary_pwm.rs | 38 +- embassy-stm32/src/timer/low_level.rs | 638 +++++++++++ embassy-stm32/src/timer/mod.rs | 1011 ++--------------- embassy-stm32/src/timer/qei.rs | 33 +- embassy-stm32/src/timer/simple_pwm.rs | 46 +- examples/stm32f4/src/bin/ws2812_pwm.rs | 5 +- examples/stm32h7/src/bin/dac_dma.rs | 26 +- .../stm32h7/src/bin/low_level_timer_api.rs | 34 +- examples/stm32l4/src/bin/dac_dma.rs | 26 +- 11 files changed, 885 insertions(+), 1007 deletions(-) create mode 100644 embassy-stm32/src/timer/low_level.rs diff --git a/ci.sh b/ci.sh index cd82af2f1..d17f4e13e 100755 --- a/ci.sh +++ b/ci.sh @@ -124,6 +124,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-tim1,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index e78f81dca..c961fc14b 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -8,7 +8,7 @@ use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; -use stm32_metapac::timer::regs; +use stm32_metapac::timer::{regs, TimGp16}; use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; @@ -16,8 +16,8 @@ use crate::rcc::sealed::RccPeripheral; #[cfg(feature = "low-power")] use crate::rtc::Rtc; #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] -use crate::timer::sealed::AdvancedControlInstance; -use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; +use crate::timer::AdvancedInstance1Channel; +use crate::timer::CoreInstance; use crate::{interrupt, peripherals}; // NOTE regarding ALARM_COUNT: @@ -207,6 +207,10 @@ foreach_interrupt! { }; } +fn regs_gp16() -> TimGp16 { + unsafe { TimGp16::from_ptr(T::regs()) } +} + // Clock timekeeping works with something we call "periods", which are time intervals // of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. // @@ -271,7 +275,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { impl RtcDriver { fn init(&'static self, cs: critical_section::CriticalSection) { - let r = T::regs_gp16(); + let r = regs_gp16(); ::enable_and_reset_with_cs(cs); @@ -308,9 +312,9 @@ impl RtcDriver { #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] { - ::CaptureCompareInterrupt::unpend(); + ::CaptureCompareInterrupt::unpend(); unsafe { - ::CaptureCompareInterrupt::enable(); + ::CaptureCompareInterrupt::enable(); } } @@ -318,7 +322,7 @@ impl RtcDriver { } fn on_interrupt(&self) { - let r = T::regs_gp16(); + let r = regs_gp16(); // XXX: reduce the size of this critical section ? critical_section::with(|cs| { @@ -349,7 +353,7 @@ impl RtcDriver { } fn next_period(&self) { - let r = T::regs_gp16(); + let r = regs_gp16(); // We only modify the period from the timer interrupt, so we know this can't race. let period = self.period.load(Ordering::Relaxed) + 1; @@ -413,7 +417,7 @@ impl RtcDriver { /// Add the given offset to the current time fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { let offset = offset.as_ticks(); - let cnt = T::regs_gp16().cnt().read().cnt() as u32; + let cnt = regs_gp16().cnt().read().cnt() as u32; let period = self.period.load(Ordering::SeqCst); // Correct the race, if it exists @@ -439,7 +443,7 @@ impl RtcDriver { let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; self.period.store(period, Ordering::SeqCst); - T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); + regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); // Now, recompute all alarms for i in 0..ALARM_COUNT { @@ -496,7 +500,7 @@ impl RtcDriver { .unwrap() .start_wakeup_alarm(time_until_next_alarm, cs); - T::regs_gp16().cr1().modify(|w| w.set_cen(false)); + regs_gp16().cr1().modify(|w| w.set_cen(false)); Ok(()) } @@ -506,7 +510,7 @@ impl RtcDriver { #[cfg(feature = "low-power")] /// Resume the timer with the given offset pub(crate) fn resume_time(&self) { - if T::regs_gp16().cr1().read().cen() { + if regs_gp16().cr1().read().cen() { // Time isn't currently stopped return; @@ -515,14 +519,14 @@ impl RtcDriver { critical_section::with(|cs| { self.stop_wakeup_alarm(cs); - T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + regs_gp16().cr1().modify(|w| w.set_cen(true)); }) } } impl Driver for RtcDriver { fn now(&self) -> u64 { - let r = T::regs_gp16(); + let r = regs_gp16(); let period = self.period.load(Ordering::Relaxed); compiler_fence(Ordering::Acquire); @@ -553,7 +557,7 @@ impl Driver for RtcDriver { fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { critical_section::with(|cs| { - let r = T::regs_gp16(); + let r = regs_gp16(); let n = alarm.id() as usize; let alarm = self.get_alarm(cs, alarm); diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 723e8506b..a892646cf 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -5,11 +5,15 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; use stm32_metapac::timer::vals::Ckd; -use super::simple_pwm::*; -use super::*; -#[allow(unused_imports)] -use crate::gpio::sealed::{AFType, Pin}; +use super::low_level::{CountingMode, OutputPolarity, Timer}; +use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin}; +use super::{ + AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin, + Channel4ComplementaryPin, +}; use crate::gpio::{AnyPin, OutputType}; +use crate::time::Hertz; +use crate::timer::low_level::OutputCompareMode; use crate::Peripheral; /// Complementary PWM pin wrapper. @@ -22,7 +26,7 @@ pub struct ComplementaryPwmPin<'d, T, C> { macro_rules! complementary_channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { + impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); @@ -47,11 +51,11 @@ complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); /// PWM driver with support for standard and complementary outputs. -pub struct ComplementaryPwm<'d, T> { - inner: PeripheralRef<'d, T>, +pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> { + inner: Timer<'d, T>, } -impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { +impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] pub fn new( @@ -71,11 +75,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { } fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { - into_ref!(tim); - - T::enable_and_reset(); - - let mut this = Self { inner: tim }; + let mut this = Self { inner: Timer::new(tim) }; this.inner.set_counting_mode(counting_mode); this.set_frequency(freq); @@ -122,7 +122,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { /// /// This value depends on the configured frequency and the timer's clock rate from RCC. pub fn get_max_duty(&self) -> u16 { - self.inner.get_max_compare_value() + 1 + self.inner.get_max_compare_value() as u16 + 1 } /// Set the duty for a given channel. @@ -130,7 +130,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + self.inner.set_compare_value(channel, duty as _) } /// Set the output polarity for a given channel. @@ -148,7 +148,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { } } -impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { +impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; @@ -168,16 +168,16 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - self.inner.get_compare_value(channel) + self.inner.get_compare_value(channel) as u16 } fn get_max_duty(&self) -> Self::Duty { - self.inner.get_max_compare_value() + 1 + self.inner.get_max_compare_value() as u16 + 1 } fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + self.inner.set_compare_value(channel, duty as u32) } fn set_period

(&mut self, period: P) diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs new file mode 100644 index 000000000..a5d942314 --- /dev/null +++ b/embassy-stm32/src/timer/low_level.rs @@ -0,0 +1,638 @@ +//! Low-level timer driver. +//! +//! This is an unopinionated, very low-level driver for all STM32 timers. It allows direct register +//! manipulation with the `regs_*()` methods, and has utility functions that are thin wrappers +//! over the registers. +//! +//! The available functionality depends on the timer type. + +use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; + +use super::*; +use crate::pac::timer::vals; +use crate::time::Hertz; + +/// Input capture mode. +#[derive(Clone, Copy)] +pub enum InputCaptureMode { + /// Rising edge only. + Rising, + /// Falling edge only. + Falling, + /// Both rising or falling edges. + BothEdges, +} + +/// Input TI selection. +#[derive(Clone, Copy)] +pub enum InputTISelection { + /// Normal + Normal, + /// Alternate + Alternate, + /// TRC + TRC, +} + +impl From for stm32_metapac::timer::vals::CcmrInputCcs { + fn from(tisel: InputTISelection) -> Self { + match tisel { + InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, + InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, + InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, + } + } +} + +/// Timer counting mode. +#[repr(u8)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum CountingMode { + #[default] + /// The timer counts up to the reload value and then resets back to 0. + EdgeAlignedUp, + /// The timer counts down to 0 and then resets back to the reload value. + EdgeAlignedDown, + /// The timer counts up to the reload value and then counts back to 0. + /// + /// The output compare interrupt flags of channels configured in output are + /// set when the counter is counting down. + CenterAlignedDownInterrupts, + /// The timer counts up to the reload value and then counts back to 0. + /// + /// The output compare interrupt flags of channels configured in output are + /// set when the counter is counting up. + CenterAlignedUpInterrupts, + /// The timer counts up to the reload value and then counts back to 0. + /// + /// The output compare interrupt flags of channels configured in output are + /// set when the counter is counting both up or down. + CenterAlignedBothInterrupts, +} + +impl CountingMode { + /// Return whether this mode is edge-aligned (up or down). + pub fn is_edge_aligned(&self) -> bool { + matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown) + } + + /// Return whether this mode is center-aligned. + pub fn is_center_aligned(&self) -> bool { + matches!( + self, + CountingMode::CenterAlignedDownInterrupts + | CountingMode::CenterAlignedUpInterrupts + | CountingMode::CenterAlignedBothInterrupts + ) + } +} + +impl From for (vals::Cms, vals::Dir) { + fn from(value: CountingMode) -> Self { + match value { + CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), + CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), + CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), + CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), + CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), + } + } +} + +impl From<(vals::Cms, vals::Dir)> for CountingMode { + fn from(value: (vals::Cms, vals::Dir)) -> Self { + match value { + (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, + (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, + (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, + (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, + (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, + } + } +} + +/// Output compare mode. +#[derive(Clone, Copy)] +pub enum OutputCompareMode { + /// The comparison between the output compare register TIMx_CCRx and + /// the counter TIMx_CNT has no effect on the outputs. + /// (this mode is used to generate a timing base). + Frozen, + /// Set channel to active level on match. OCxREF signal is forced high when the + /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). + ActiveOnMatch, + /// Set channel to inactive level on match. OCxREF signal is forced low when the + /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). + InactiveOnMatch, + /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. + Toggle, + /// Force inactive level - OCxREF is forced low. + ForceInactive, + /// Force active level - OCxREF is forced high. + ForceActive, + /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNTTIMx_CCRx else active (OCxREF=1). + PwmMode1, + /// PWM mode 2 - In upcounting, channel is inactive as long as + /// TIMx_CNTTIMx_CCRx else inactive. + PwmMode2, + // TODO: there's more modes here depending on the chip family. +} + +impl From for stm32_metapac::timer::vals::Ocm { + fn from(mode: OutputCompareMode) -> Self { + match mode { + OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, + OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, + OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, + OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, + OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, + OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, + OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, + OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, + } + } +} + +/// Timer output pin polarity. +#[derive(Clone, Copy)] +pub enum OutputPolarity { + /// Active high (higher duty value makes the pin spend more time high). + ActiveHigh, + /// Active low (higher duty value makes the pin spend more time low). + ActiveLow, +} + +impl From for bool { + fn from(mode: OutputPolarity) -> Self { + match mode { + OutputPolarity::ActiveHigh => false, + OutputPolarity::ActiveLow => true, + } + } +} + +/// Low-level timer driver. +pub struct Timer<'d, T: CoreInstance> { + tim: PeripheralRef<'d, T>, +} + +impl<'d, T: CoreInstance> Drop for Timer<'d, T> { + fn drop(&mut self) { + T::disable() + } +} + +impl<'d, T: CoreInstance> Timer<'d, T> { + /// Create a new timer driver. + pub fn new(tim: impl Peripheral

+ 'd) -> Self { + into_ref!(tim); + + T::enable_and_reset(); + + Self { tim } + } + + /// Get access to the virutal core 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_core(&self) -> crate::pac::timer::TimCore { + unsafe { crate::pac::timer::TimCore::from_ptr(T::regs()) } + } + + #[cfg(not(stm32l0))] + fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp32 { + unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } + } + + /// Start the timer. + pub fn start(&self) { + self.regs_core().cr1().modify(|r| r.set_cen(true)); + } + + /// Stop the timer. + pub fn stop(&self) { + self.regs_core().cr1().modify(|r| r.set_cen(false)); + } + + /// Reset the counter value to 0 + pub fn reset(&self) { + self.regs_core().cnt().write(|r| r.set_cnt(0)); + } + + /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. + /// + /// This means that in the default edge-aligned mode, + /// the timer counter will wrap around at the same frequency as is being set. + /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved + /// because it needs to count up and down. + pub fn set_frequency(&self, frequency: Hertz) { + let f = frequency.0; + assert!(f > 0); + let timer_f = T::frequency().0; + + match T::BITS { + TimerBits::Bits16 => { + let pclk_ticks_per_timer_period = timer_f / f; + let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); + let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1); + + // the timer counts `0..=arr`, we want it to count `0..divide_by` + let arr = unwrap!(u16::try_from(divide_by - 1)); + + let regs = self.regs_core(); + regs.psc().write_value(psc); + regs.arr().write(|r| r.set_arr(arr)); + + regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); + regs.egr().write(|r| r.set_ug(true)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); + } + #[cfg(not(stm32l0))] + TimerBits::Bits32 => { + let pclk_ticks_per_timer_period = (timer_f / f) as u64; + let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); + let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()); + + let regs = self.regs_gp32_unchecked(); + regs.psc().write_value(psc); + regs.arr().write_value(arr); + + regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); + regs.egr().write(|r| r.set_ug(true)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); + } + } + } + + /// Clear update interrupt. + /// + /// Returns whether the update interrupt flag was set. + pub fn clear_update_interrupt(&self) -> bool { + let regs = self.regs_core(); + let sr = regs.sr().read(); + if sr.uif() { + regs.sr().modify(|r| { + r.set_uif(false); + }); + true + } else { + false + } + } + + /// Enable/disable the update interrupt. + pub fn enable_update_interrupt(&self, enable: bool) { + self.regs_core().dier().modify(|r| r.set_uie(enable)); + } + + /// Enable/disable autoreload preload. + pub fn set_autoreload_preload(&self, enable: bool) { + self.regs_core().cr1().modify(|r| r.set_arpe(enable)); + } + + /// Get the timer frequency. + pub fn get_frequency(&self) -> Hertz { + let timer_f = T::frequency(); + + match T::BITS { + TimerBits::Bits16 => { + let regs = self.regs_core(); + let arr = regs.arr().read().arr(); + let psc = regs.psc().read(); + + timer_f / arr / (psc + 1) + } + #[cfg(not(stm32l0))] + TimerBits::Bits32 => { + let regs = self.regs_gp32_unchecked(); + let arr = regs.arr().read(); + let psc = regs.psc().read(); + + timer_f / arr / (psc + 1) + } + } + } +} + +impl<'d, T: BasicNoCr2Instance> Timer<'d, T> { + /// Get access to the Baisc 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 { + unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) } + } + + /// Enable/disable the update dma. + pub fn enable_update_dma(&self, enable: bool) { + self.regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); + } + + /// Get the update dma enable/disable state. + pub fn get_update_dma_state(&self) -> bool { + self.regs_basic_no_cr2().dier().read().ude() + } +} + +impl<'d, T: BasicInstance> Timer<'d, T> { + /// Get access to the Baisc 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_basic(&self) -> crate::pac::timer::TimBasic { + unsafe { crate::pac::timer::TimBasic::from_ptr(T::regs()) } + } +} + +impl<'d, T: GeneralInstance1Channel> Timer<'d, T> { + /// Get access to the general purpose 1 channel 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch { + unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) } + } + + /// Set clock divider. + pub fn set_clock_division(&self, ckd: vals::Ckd) { + self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); + } + + /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. + pub fn get_max_compare_value(&self) -> u32 { + match T::BITS { + TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32, + #[cfg(not(stm32l0))] + TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), + } + } +} + +impl<'d, T: GeneralInstance2Channel> Timer<'d, T> { + /// Get access to the general purpose 2 channel 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_2ch(&self) -> crate::pac::timer::Tim2ch { + unsafe { crate::pac::timer::Tim2ch::from_ptr(T::regs()) } + } +} + +impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { + /// Get access to the general purpose 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 { + unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) } + } + + /// Enable timer outputs. + pub fn enable_outputs(&self) { + self.tim.enable_outputs() + } + + /// Set counting mode. + pub fn set_counting_mode(&self, mode: CountingMode) { + let (cms, dir) = mode.into(); + + let timer_enabled = self.regs_core().cr1().read().cen(); + // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. + // Changing direction is discouraged while the timer is running. + assert!(!timer_enabled); + + self.regs_gp16().cr1().modify(|r| r.set_dir(dir)); + self.regs_gp16().cr1().modify(|r| r.set_cms(cms)) + } + + /// Get counting mode. + pub fn get_counting_mode(&self) -> CountingMode { + let cr1 = self.regs_gp16().cr1().read(); + (cr1.cms(), cr1.dir()).into() + } + + /// Set input capture filter. + pub fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) { + let raw_channel = channel.index(); + self.regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + + /// Clear input interrupt. + pub fn clear_input_interrupt(&self, channel: Channel) { + self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); + } + + /// Enable input interrupt. + pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) { + self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); + } + + /// Set input capture prescaler. + pub fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) { + let raw_channel = channel.index(); + self.regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + /// Set input TI selection. + pub fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) { + let raw_channel = channel.index(); + self.regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + + /// Set input capture mode. + pub fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) { + self.regs_gp16().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.index(), true); + r.set_ccp(channel.index(), true); + } + }); + } + + /// Set output compare mode. + pub fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) { + let raw_channel: usize = channel.index(); + self.regs_gp16() + .ccmr_output(raw_channel / 2) + .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); + } + + /// Set output polarity. + pub fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { + self.regs_gp16() + .ccer() + .modify(|w| w.set_ccp(channel.index(), polarity.into())); + } + + /// Enable/disable a channel. + pub fn enable_channel(&self, channel: Channel, enable: bool) { + self.regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); + } + + /// Get enable/disable state of a channel + pub fn get_channel_enable_state(&self, channel: Channel) -> bool { + self.regs_gp16().ccer().read().cce(channel.index()) + } + + /// Set compare value for a channel. + pub fn set_compare_value(&self, channel: Channel, value: u32) { + match T::BITS { + TimerBits::Bits16 => { + let value = unwrap!(u16::try_from(value)); + self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); + } + #[cfg(not(stm32l0))] + TimerBits::Bits32 => { + self.regs_gp32_unchecked().ccr(channel.index()).write_value(value); + } + } + } + + /// Get compare value for a channel. + pub fn get_compare_value(&self, channel: Channel) -> u32 { + match T::BITS { + TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32, + #[cfg(not(stm32l0))] + TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(), + } + } + + /// Get capture value for a channel. + pub fn get_capture_value(&self, channel: Channel) -> u32 { + self.get_compare_value(channel) + } + + /// Set output compare preload. + pub fn set_output_compare_preload(&self, channel: Channel, preload: bool) { + let channel_index = channel.index(); + self.regs_gp16() + .ccmr_output(channel_index / 2) + .modify(|w| w.set_ocpe(channel_index % 2, preload)); + } + + /// Get capture compare DMA selection + pub fn get_cc_dma_selection(&self) -> vals::Ccds { + self.regs_gp16().cr2().read().ccds() + } + + /// Set capture compare DMA selection + pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) { + self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) + } + + /// Get capture compare DMA enable state + pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { + self.regs_gp16().dier().read().ccde(channel.index()) + } + + /// Set capture compare DMA enable state + pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { + self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) + } +} + +#[cfg(not(stm32l0))] +impl<'d, T: GeneralInstance32bit4Channel> Timer<'d, T> { + /// Get access to the general purpose 32bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_gp32(&self) -> crate::pac::timer::TimGp32 { + unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } + } +} + +#[cfg(not(stm32l0))] +impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> { + /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp { + unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) } + } + + /// Set clock divider for the dead time. + pub fn set_dead_time_clock_division(&self, value: vals::Ckd) { + self.regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); + } + + /// Set dead time, as a fraction of the max duty value. + pub fn set_dead_time_value(&self, value: u8) { + self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); + } + + /// Set state of MOE-bit in BDTR register to en-/disable output + pub fn set_moe(&self, enable: bool) { + self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); + } +} + +#[cfg(not(stm32l0))] +impl<'d, T: AdvancedInstance2Channel> Timer<'d, T> { + /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. + /// + /// Note: This works even if the timer is more capable, because registers + /// for the less capable timers are a subset. This allows writing a driver + /// for a given set of capabilities, and having it transparently work with + /// more capable timers. + pub fn regs_2ch_cmp(&self) -> crate::pac::timer::Tim2chCmp { + unsafe { crate::pac::timer::Tim2chCmp::from_ptr(T::regs()) } + } +} + +#[cfg(not(stm32l0))] +impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> { + /// Get access to the advanced timer registers. + pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv { + unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) } + } + + /// Set complementary output polarity. + pub fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { + self.regs_advanced() + .ccer() + .modify(|w| w.set_ccnp(channel.index(), polarity.into())); + } + + /// Enable/disable a complementary channel. + pub fn enable_complementary_channel(&self, channel: Channel, enable: bool) { + self.regs_advanced() + .ccer() + .modify(|w| w.set_ccne(channel.index(), enable)); + } +} diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index e5e84c255..2ba6b3f11 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,490 +1,13 @@ //! Timers, PWM, quadrature decoder. -//! - -//! Timer inheritance -//! - -// sealed: -// -// Core -------------------------> 1CH -------------------------> 1CH_CMP -// | | ^ | -// +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV -// | | | ^ | | ^ ^ -// | | +------|--|--------------|-----------+ | -// | +--------------------+ +--------------|-----------|---------+ -// | | | | -// | +--------------------------------------|-----------+ -// +----------------------------------------------------+ - -//! ```text -//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance -//! | -//! +--> CaptureCompare32bitInstance -//! ``` -//! -//! Mapping: -//! -//! | trait | timer | -//! | :----------------------------------------: | ------------------------------------------------------------------------------------------------- | -//! | [BasicInstance] | Basic Timer | -//! | [CaptureCompare16bitInstance] | 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer | -//! | [CaptureCompare32bitInstance] | General Purpose 32-bit Timer | -//! | [ComplementaryCaptureCompare16bitInstance] | 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer | #[cfg(not(stm32l0))] pub mod complementary_pwm; +pub mod low_level; pub mod qei; pub mod simple_pwm; -use stm32_metapac::timer::vals; - use crate::interrupt; use crate::rcc::RccPeripheral; -use crate::time::Hertz; - -/// Low-level timer access. -#[cfg(feature = "unstable-pac")] -pub mod low_level { - pub use super::sealed::*; -} - -pub(crate) mod sealed { - use super::*; - - /// Virtual Core 16-bit timer instance. - pub trait CoreInstance: RccPeripheral { - /// Interrupt for this timer. - type Interrupt: interrupt::typelevel::Interrupt; - - /// Get access to the virutal core 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_core() -> crate::pac::timer::TimCore; - - /// Start the timer. - fn start(&self) { - Self::regs_core().cr1().modify(|r| r.set_cen(true)); - } - - /// Stop the timer. - fn stop(&self) { - Self::regs_core().cr1().modify(|r| r.set_cen(false)); - } - - /// Reset the counter value to 0 - fn reset(&self) { - Self::regs_core().cnt().write(|r| r.set_cnt(0)); - } - - /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. - /// - /// This means that in the default edge-aligned mode, - /// the timer counter will wrap around at the same frequency as is being set. - /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved - /// because it needs to count up and down. - fn set_frequency(&self, frequency: Hertz) { - let f = frequency.0; - let timer_f = Self::frequency().0; - assert!(f > 0); - let pclk_ticks_per_timer_period = timer_f / f; - let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); - let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1); - - // the timer counts `0..=arr`, we want it to count `0..divide_by` - let arr = unwrap!(u16::try_from(divide_by - 1)); - - let regs = Self::regs_core(); - regs.psc().write_value(psc); - regs.arr().write(|r| r.set_arr(arr)); - - regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); - regs.egr().write(|r| r.set_ug(true)); - regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); - } - - /// Clear update interrupt. - /// - /// Returns whether the update interrupt flag was set. - fn clear_update_interrupt(&self) -> bool { - let regs = Self::regs_core(); - let sr = regs.sr().read(); - if sr.uif() { - regs.sr().modify(|r| { - r.set_uif(false); - }); - true - } else { - false - } - } - - /// Enable/disable the update interrupt. - fn enable_update_interrupt(&self, enable: bool) { - Self::regs_core().dier().modify(|r| r.set_uie(enable)); - } - - /// Enable/disable autoreload preload. - fn set_autoreload_preload(&self, enable: bool) { - Self::regs_core().cr1().modify(|r| r.set_arpe(enable)); - } - - /// Get the timer frequency. - fn get_frequency(&self) -> Hertz { - let timer_f = Self::frequency(); - - let regs = Self::regs_core(); - let arr = regs.arr().read().arr(); - let psc = regs.psc().read(); - - timer_f / arr / (psc + 1) - } - } - - /// Virtual Basic without CR2 16-bit timer instance. - pub trait BasicNoCr2Instance: CoreInstance { - /// Get access to the Baisc 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2; - - /// Enable/disable the update dma. - fn enable_update_dma(&self, enable: bool) { - Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); - } - - /// Get the update dma enable/disable state. - fn get_update_dma_state(&self) -> bool { - Self::regs_basic_no_cr2().dier().read().ude() - } - } - - /// Basic 16-bit timer instance. - pub trait BasicInstance: BasicNoCr2Instance { - /// Get access to the Baisc 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_basic() -> crate::pac::timer::TimBasic; - } - - /// Gneral-purpose 1 channel 16-bit timer instance. - pub trait GeneralPurpose1ChannelInstance: CoreInstance { - /// Get access to the general purpose 1 channel 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_1ch() -> crate::pac::timer::Tim1ch; - - /// Set clock divider. - fn set_clock_division(&self, ckd: vals::Ckd) { - Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); - } - - /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. - fn get_max_compare_value(&self) -> u16 { - Self::regs_1ch().arr().read().arr() - } - } - - /// Gneral-purpose 1 channel 16-bit timer instance. - pub trait GeneralPurpose2ChannelInstance: GeneralPurpose1ChannelInstance { - /// Get access to the general purpose 2 channel 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_2ch() -> crate::pac::timer::Tim2ch; - } - - /// Gneral-purpose 16-bit timer instance. - pub trait GeneralPurpose16bitInstance: BasicInstance + GeneralPurpose2ChannelInstance { - /// Get access to the general purpose 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_gp16() -> crate::pac::timer::TimGp16; - - /// Set counting mode. - fn set_counting_mode(&self, mode: CountingMode) { - let (cms, dir) = mode.into(); - - let timer_enabled = Self::regs_core().cr1().read().cen(); - // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. - // Changing direction is discouraged while the timer is running. - assert!(!timer_enabled); - - Self::regs_gp16().cr1().modify(|r| r.set_dir(dir)); - Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) - } - - /// Get counting mode. - fn get_counting_mode(&self) -> CountingMode { - let cr1 = Self::regs_gp16().cr1().read(); - (cr1.cms(), cr1.dir()).into() - } - - /// Set input capture filter. - fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) { - let raw_channel = channel.index(); - Self::regs_gp16() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icf(raw_channel % 2, icf)); - } - - /// Clear input interrupt. - fn clear_input_interrupt(&self, channel: Channel) { - Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); - } - - /// Enable input interrupt. - fn enable_input_interrupt(&self, channel: Channel, enable: bool) { - Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); - } - - /// Set input capture prescaler. - fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) { - let raw_channel = channel.index(); - Self::regs_gp16() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icpsc(raw_channel % 2, factor)); - } - - /// Set input TI selection. - fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) { - let raw_channel = channel.index(); - Self::regs_gp16() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); - } - - /// Set input capture mode. - fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) { - Self::regs_gp16().ccer().modify(|r| match mode { - InputCaptureMode::Rising => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), false); - } - InputCaptureMode::Falling => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), true); - } - InputCaptureMode::BothEdges => { - r.set_ccnp(channel.index(), true); - r.set_ccp(channel.index(), true); - } - }); - } - - /// Set output compare mode. - fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) { - let raw_channel: usize = channel.index(); - Self::regs_gp16() - .ccmr_output(raw_channel / 2) - .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); - } - - /// Set output polarity. - fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { - Self::regs_gp16() - .ccer() - .modify(|w| w.set_ccp(channel.index(), polarity.into())); - } - - /// Enable/disable a channel. - fn enable_channel(&self, channel: Channel, enable: bool) { - Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); - } - - /// Get enable/disable state of a channel - fn get_channel_enable_state(&self, channel: Channel) -> bool { - Self::regs_gp16().ccer().read().cce(channel.index()) - } - - /// Set compare value for a channel. - fn set_compare_value(&self, channel: Channel, value: u16) { - Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); - } - - /// Get capture value for a channel. - fn get_capture_value(&self, channel: Channel) -> u16 { - Self::regs_gp16().ccr(channel.index()).read().ccr() - } - - /// Get compare value for a channel. - fn get_compare_value(&self, channel: Channel) -> u16 { - Self::regs_gp16().ccr(channel.index()).read().ccr() - } - - /// Set output compare preload. - fn set_output_compare_preload(&self, channel: Channel, preload: bool) { - let channel_index = channel.index(); - Self::regs_gp16() - .ccmr_output(channel_index / 2) - .modify(|w| w.set_ocpe(channel_index % 2, preload)); - } - - /// Get capture compare DMA selection - fn get_cc_dma_selection(&self) -> super::vals::Ccds { - Self::regs_gp16().cr2().read().ccds() - } - - /// Set capture compare DMA selection - fn set_cc_dma_selection(&self, ccds: super::vals::Ccds) { - Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) - } - - /// Get capture compare DMA enable state - fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { - Self::regs_gp16().dier().read().ccde(channel.index()) - } - - /// Set capture compare DMA enable state - fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { - Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) - } - } - - #[cfg(not(stm32l0))] - /// Gneral-purpose 32-bit timer instance. - pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { - /// Get access to the general purpose 32bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_gp32() -> crate::pac::timer::TimGp32; - - /// Set timer frequency. - fn set_frequency(&self, frequency: Hertz) { - let f = frequency.0; - assert!(f > 0); - let timer_f = Self::frequency().0; - let pclk_ticks_per_timer_period = (timer_f / f) as u64; - let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); - let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()); - - let regs = Self::regs_gp32(); - regs.psc().write_value(psc); - regs.arr().write_value(arr); - - regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); - regs.egr().write(|r| r.set_ug(true)); - regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); - } - - /// Get timer frequency. - fn get_frequency(&self) -> Hertz { - let timer_f = Self::frequency(); - - let regs = Self::regs_gp32(); - let arr = regs.arr().read(); - let psc = regs.psc().read(); - - timer_f / arr / (psc + 1) - } - - /// Set comapre value for a channel. - fn set_compare_value(&self, channel: Channel, value: u32) { - Self::regs_gp32().ccr(channel.index()).write_value(value); - } - - /// Get capture value for a channel. - fn get_capture_value(&self, channel: Channel) -> u32 { - Self::regs_gp32().ccr(channel.index()).read() - } - - /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. - fn get_max_compare_value(&self) -> u32 { - Self::regs_gp32().arr().read() - } - - /// Get compare value for a channel. - fn get_compare_value(&self, channel: Channel) -> u32 { - Self::regs_gp32().ccr(channel.index()).read() - } - } - - #[cfg(not(stm32l0))] - /// Gneral-purpose 1 channel with one complementary 16-bit timer instance. - pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance { - /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; - - /// Set clock divider for the dead time. - fn set_dead_time_clock_division(&self, value: vals::Ckd) { - Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); - } - - /// Set dead time, as a fraction of the max duty value. - fn set_dead_time_value(&self, value: u8) { - Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); - } - - /// Set state of MOE-bit in BDTR register to en-/disable output - fn set_moe(&self, enable: bool) { - Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); - } - } - - #[cfg(not(stm32l0))] - /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. - pub trait GeneralPurpose2ChannelComplementaryInstance: - BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance - { - /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. - /// - /// Note: This works even if the timer is more capable, because registers - /// for the less capable timers are a subset. This allows writing a driver - /// for a given set of capabilities, and having it transparently work with - /// more capable timers. - fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp; - } - - #[cfg(not(stm32l0))] - /// Advanced control timer instance. - pub trait AdvancedControlInstance: - GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance - { - /// Capture compare interrupt for this timer. - type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; - - /// Get access to the advanced timer registers. - fn regs_advanced() -> crate::pac::timer::TimAdv; - - /// Set complementary output polarity. - fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { - Self::regs_advanced() - .ccer() - .modify(|w| w.set_ccnp(channel.index(), polarity.into())); - } - - /// Enable/disable a complementary channel. - fn enable_complementary_channel(&self, channel: Channel, enable: bool) { - Self::regs_advanced() - .ccer() - .modify(|w| w.set_ccne(channel.index(), enable)); - } - } -} /// Timer channel. #[derive(Clone, Copy)] @@ -511,181 +34,44 @@ impl Channel { } } -/// Input capture mode. -#[derive(Clone, Copy)] -pub enum InputCaptureMode { - /// Rising edge only. - Rising, - /// Falling edge only. - Falling, - /// Both rising or falling edges. - BothEdges, +/// Amount of bits of a timer. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TimerBits { + /// 16 bits. + Bits16, + /// 32 bits. + #[cfg(not(stm32l0))] + Bits32, } -/// Input TI selection. -#[derive(Clone, Copy)] -pub enum InputTISelection { - /// Normal - Normal, - /// Alternate - Alternate, - /// TRC - TRC, -} +/// Core timer instance. +pub trait CoreInstance: RccPeripheral + 'static { + /// Interrupt for this timer. + type Interrupt: interrupt::typelevel::Interrupt; -impl From for stm32_metapac::timer::vals::CcmrInputCcs { - fn from(tisel: InputTISelection) -> Self { - match tisel { - InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, - InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, - InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, - } - } -} + /// Amount of bits this timer has. + const BITS: TimerBits; -/// Timer counting mode. -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub enum CountingMode { - #[default] - /// The timer counts up to the reload value and then resets back to 0. - EdgeAlignedUp, - /// The timer counts down to 0 and then resets back to the reload value. - EdgeAlignedDown, - /// The timer counts up to the reload value and then counts back to 0. + /// Registers for this timer. /// - /// The output compare interrupt flags of channels configured in output are - /// set when the counter is counting down. - CenterAlignedDownInterrupts, - /// The timer counts up to the reload value and then counts back to 0. - /// - /// The output compare interrupt flags of channels configured in output are - /// set when the counter is counting up. - CenterAlignedUpInterrupts, - /// The timer counts up to the reload value and then counts back to 0. - /// - /// The output compare interrupt flags of channels configured in output are - /// set when the counter is counting both up or down. - CenterAlignedBothInterrupts, + /// This is a raw pointer to the register block. The actual register block layout varies depending on the timer type. + fn regs() -> *mut (); } +/// Cut-down basic timer instance. +pub trait BasicNoCr2Instance: CoreInstance {} +/// Basic timer instance. +pub trait BasicInstance: BasicNoCr2Instance {} -impl CountingMode { - /// Return whether this mode is edge-aligned (up or down). - pub fn is_edge_aligned(&self) -> bool { - matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown) - } +/// General-purpose 16-bit timer with 1 channel instance. +pub trait GeneralInstance1Channel: CoreInstance {} - /// Return whether this mode is center-aligned. - pub fn is_center_aligned(&self) -> bool { - matches!( - self, - CountingMode::CenterAlignedDownInterrupts - | CountingMode::CenterAlignedUpInterrupts - | CountingMode::CenterAlignedBothInterrupts - ) - } -} +/// General-purpose 16-bit timer with 2 channels instance. +pub trait GeneralInstance2Channel: GeneralInstance1Channel {} -impl From for (vals::Cms, vals::Dir) { - fn from(value: CountingMode) -> Self { - match value { - CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), - CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), - CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), - CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), - CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), - } - } -} - -impl From<(vals::Cms, vals::Dir)> for CountingMode { - fn from(value: (vals::Cms, vals::Dir)) -> Self { - match value { - (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, - (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, - (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, - (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, - (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, - } - } -} - -/// Output compare mode. -#[derive(Clone, Copy)] -pub enum OutputCompareMode { - /// The comparison between the output compare register TIMx_CCRx and - /// the counter TIMx_CNT has no effect on the outputs. - /// (this mode is used to generate a timing base). - Frozen, - /// Set channel to active level on match. OCxREF signal is forced high when the - /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). - ActiveOnMatch, - /// Set channel to inactive level on match. OCxREF signal is forced low when the - /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). - InactiveOnMatch, - /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. - Toggle, - /// Force inactive level - OCxREF is forced low. - ForceInactive, - /// Force active level - OCxREF is forced high. - ForceActive, - /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNTTIMx_CCRx else active (OCxREF=1). - PwmMode1, - /// PWM mode 2 - In upcounting, channel is inactive as long as - /// TIMx_CNTTIMx_CCRx else inactive. - PwmMode2, - // TODO: there's more modes here depending on the chip family. -} - -impl From for stm32_metapac::timer::vals::Ocm { - fn from(mode: OutputCompareMode) -> Self { - match mode { - OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, - OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, - OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, - OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, - OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, - OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, - OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, - OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, - } - } -} - -/// Timer output pin polarity. -#[derive(Clone, Copy)] -pub enum OutputPolarity { - /// Active high (higher duty value makes the pin spend more time high). - ActiveHigh, - /// Active low (higher duty value makes the pin spend more time low). - ActiveLow, -} - -impl From for bool { - fn from(mode: OutputPolarity) -> Self { - match mode { - OutputPolarity::ActiveHigh => false, - OutputPolarity::ActiveLow => true, - } - } -} - -/// Basic 16-bit timer instance. -pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} - -// It's just a General-purpose 16-bit timer instance. -/// Capture Compare timer instance. -pub trait CaptureCompare16bitInstance: - BasicInstance - + sealed::GeneralPurpose2ChannelInstance - + sealed::GeneralPurpose1ChannelInstance - + sealed::GeneralPurpose16bitInstance - + 'static -{ - // SimplePwm<'d, T> is implemented for T: CaptureCompare16bitInstance +/// General-purpose 16-bit timer with 4 channels instance. +pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel { + // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel // Advanced timers implement this trait, but the output needs to be // enabled explicitly. // To support general-purpose and advanced timers, this function is added @@ -694,296 +80,149 @@ pub trait CaptureCompare16bitInstance: fn enable_outputs(&self) {} } -#[cfg(not(stm32l0))] -// It's just a General-purpose 32-bit timer instance. -/// Capture Compare 32-bit timer instance. -pub trait CaptureCompare32bitInstance: - CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static -{ +/// General-purpose 32-bit timer with 4 channels instance. +pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} + +/// Advanced 16-bit timer with 1 channel instance. +pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel { + /// Capture compare interrupt for this timer. + type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; } +/// Advanced 16-bit timer with 2 channels instance. -#[cfg(not(stm32l0))] -// It's just a Advanced Control timer instance. -/// Complementary Capture Compare 32-bit timer instance. -pub trait ComplementaryCaptureCompare16bitInstance: - CaptureCompare16bitInstance - + sealed::GeneralPurpose1ChannelComplementaryInstance - + sealed::GeneralPurpose2ChannelComplementaryInstance - + sealed::AdvancedControlInstance - + 'static -{ -} +pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {} -pin_trait!(Channel1Pin, CaptureCompare16bitInstance); -pin_trait!(Channel2Pin, CaptureCompare16bitInstance); -pin_trait!(Channel3Pin, CaptureCompare16bitInstance); -pin_trait!(Channel4Pin, CaptureCompare16bitInstance); -pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); +/// Advanced 16-bit timer with 4 channels instance. +pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} -cfg_if::cfg_if! { - if #[cfg(not(stm32l0))] { - pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); - pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); - pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); - pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +pin_trait!(Channel1Pin, GeneralInstance4Channel); +pin_trait!(Channel2Pin, GeneralInstance4Channel); +pin_trait!(Channel3Pin, GeneralInstance4Channel); +pin_trait!(Channel4Pin, GeneralInstance4Channel); +pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); - pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); - pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); +pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); +pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel); +pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel); +pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel); - pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); - pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); +pin_trait!(BreakInputPin, AdvancedInstance4Channel); +pin_trait!(BreakInput2Pin, AdvancedInstance4Channel); - pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); - pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); - } -} +pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); +pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel); + +pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); +pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); + +// Update Event trigger DMA for every timer +dma_trait!(UpDma, BasicInstance); + +dma_trait!(Ch1Dma, GeneralInstance4Channel); +dma_trait!(Ch2Dma, GeneralInstance4Channel); +dma_trait!(Ch3Dma, GeneralInstance4Channel); +dma_trait!(Ch4Dma, GeneralInstance4Channel); #[allow(unused)] macro_rules! impl_core_timer { - ($inst:ident, $irq:ident) => { - impl sealed::CoreInstance for crate::peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$irq; + ($inst:ident, $bits:expr) => { + impl CoreInstance for crate::peripherals::$inst { + type Interrupt = crate::_generated::peripheral_interrupts::$inst::UP; - fn regs_core() -> crate::pac::timer::TimCore { - unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - }; -} + const BITS: TimerBits = $bits; -#[allow(unused)] -macro_rules! impl_basic_no_cr2_timer { - ($inst:ident) => { - impl sealed::BasicNoCr2Instance for crate::peripherals::$inst { - fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 { - unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - }; -} - -#[allow(unused)] -macro_rules! impl_basic_timer { - ($inst:ident) => { - impl sealed::BasicInstance for crate::peripherals::$inst { - fn regs_basic() -> crate::pac::timer::TimBasic { - unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - }; -} - -#[allow(unused)] -macro_rules! impl_1ch_timer { - ($inst:ident) => { - impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst { - fn regs_1ch() -> crate::pac::timer::Tim1ch { - unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - }; -} - -#[allow(unused)] -macro_rules! impl_2ch_timer { - ($inst:ident) => { - impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst { - fn regs_2ch() -> crate::pac::timer::Tim2ch { - unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - }; -} - -#[allow(unused)] -macro_rules! impl_gp16_timer { - ($inst:ident) => { - impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { - fn regs_gp16() -> crate::pac::timer::TimGp16 { - unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - }; -} - -#[allow(unused)] -macro_rules! impl_gp32_timer { - ($inst:ident) => { - impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { - fn regs_gp32() -> crate::pac::timer::TimGp32 { - crate::pac::$inst - } - } - }; -} - -#[allow(unused)] -macro_rules! impl_1ch_cmp_timer { - ($inst:ident) => { - impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst { - fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp { - unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - }; -} - -#[allow(unused)] -macro_rules! impl_2ch_cmp_timer { - ($inst:ident) => { - impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst { - fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp { - unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) } - } - } - }; -} - -#[allow(unused)] -macro_rules! impl_adv_timer { - ($inst:ident, $irq:ident) => { - impl sealed::AdvancedControlInstance for crate::peripherals::$inst { - type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq; - - fn regs_advanced() -> crate::pac::timer::TimAdv { - unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } + fn regs() -> *mut () { + crate::pac::$inst.as_ptr() } } }; } foreach_interrupt! { - ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { - impl_core_timer!($inst, $irq); - impl_basic_no_cr2_timer!($inst); - impl_basic_timer!($inst); + impl_core_timer!($inst, TimerBits::Bits16); + impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { - impl_core_timer!($inst, $irq); - impl_basic_no_cr2_timer!($inst); - impl_basic_timer!($inst); - impl_1ch_timer!($inst); - impl_2ch_timer!($inst); - impl_gp16_timer!($inst); + impl_core_timer!($inst, TimerBits::Bits16); + impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralInstance1Channel for crate::peripherals::$inst {} + impl GeneralInstance2Channel for crate::peripherals::$inst {} + impl GeneralInstance4Channel for crate::peripherals::$inst {} }; - ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { - impl_core_timer!($inst, $irq); - impl_basic_no_cr2_timer!($inst); - impl_basic_timer!($inst); - impl_1ch_timer!($inst); - impl_2ch_timer!($inst); - impl_gp16_timer!($inst); + impl_core_timer!($inst, TimerBits::Bits16); + impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralInstance1Channel for crate::peripherals::$inst {} + impl GeneralInstance2Channel for crate::peripherals::$inst {} + impl GeneralInstance4Channel for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { - impl_core_timer!($inst, $irq); - impl_basic_no_cr2_timer!($inst); - impl_basic_timer!($inst); - impl_1ch_timer!($inst); - impl_2ch_timer!($inst); - impl_gp16_timer!($inst); + impl_core_timer!($inst, TimerBits::Bits16); + impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralInstance1Channel for crate::peripherals::$inst {} + impl GeneralInstance2Channel for crate::peripherals::$inst {} + impl GeneralInstance4Channel for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { - impl_core_timer!($inst, $irq); - impl_basic_no_cr2_timer!($inst); - impl_basic_timer!($inst); - impl_1ch_timer!($inst); - impl_2ch_timer!($inst); - impl_gp16_timer!($inst); - impl_gp32_timer!($inst); + impl_core_timer!($inst, TimerBits::Bits32); + impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} - impl CaptureCompare32bitInstance for crate::peripherals::$inst {} + impl GeneralInstance1Channel for crate::peripherals::$inst {} + impl GeneralInstance2Channel for crate::peripherals::$inst {} + impl GeneralInstance4Channel for crate::peripherals::$inst {} + impl GeneralInstance32bit4Channel for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { - impl_core_timer!($inst, $irq); - impl_basic_no_cr2_timer!($inst); - impl_basic_timer!($inst); - impl_1ch_timer!($inst); - impl_2ch_timer!($inst); - impl_gp16_timer!($inst); - impl_1ch_cmp_timer!($inst); - impl_2ch_cmp_timer!($inst); + impl_core_timer!($inst, TimerBits::Bits16); + impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst { - /// Enable timer outputs. - fn enable_outputs(&self) { - use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; - self.set_moe(true); - } - } - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralInstance1Channel for crate::peripherals::$inst {} + impl GeneralInstance2Channel for crate::peripherals::$inst {} + impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::() }} + impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } + impl AdvancedInstance2Channel for crate::peripherals::$inst {} + impl AdvancedInstance4Channel for crate::peripherals::$inst {} }; - ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => { - impl_adv_timer!($inst, $irq); - }; - ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { - impl_core_timer!($inst, $irq); - impl_basic_no_cr2_timer!($inst); - impl_basic_timer!($inst); - impl_1ch_timer!($inst); - impl_2ch_timer!($inst); - impl_gp16_timer!($inst); - impl_1ch_cmp_timer!($inst); - impl_2ch_cmp_timer!($inst); + impl_core_timer!($inst, TimerBits::Bits16); + impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst { - /// Enable timer outputs. - fn enable_outputs(&self) { - use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; - self.set_moe(true); - } - } - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralInstance1Channel for crate::peripherals::$inst {} + impl GeneralInstance2Channel for crate::peripherals::$inst {} + impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::() }} + impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } + impl AdvancedInstance2Channel for crate::peripherals::$inst {} + impl AdvancedInstance4Channel for crate::peripherals::$inst {} }; - ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => { - impl_adv_timer!($inst, $irq); - }; - ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { - impl_core_timer!($inst, $irq); - impl_basic_no_cr2_timer!($inst); - impl_basic_timer!($inst); - impl_1ch_timer!($inst); - impl_2ch_timer!($inst); - impl_gp16_timer!($inst); - impl_1ch_cmp_timer!($inst); - impl_2ch_cmp_timer!($inst); + impl_core_timer!($inst, TimerBits::Bits16); + impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst { - /// Enable timer outputs. - fn enable_outputs(&self) { - use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; - self.set_moe(true); - } - } - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} - }; - ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => { - impl_adv_timer!($inst, $irq); + impl GeneralInstance1Channel for crate::peripherals::$inst {} + impl GeneralInstance2Channel for crate::peripherals::$inst {} + impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::() }} + impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } + impl AdvancedInstance2Channel for crate::peripherals::$inst {} + impl AdvancedInstance4Channel for crate::peripherals::$inst {} }; } -// Update Event trigger DMA for every timer -dma_trait!(UpDma, BasicInstance); - -dma_trait!(Ch1Dma, CaptureCompare16bitInstance); -dma_trait!(Ch2Dma, CaptureCompare16bitInstance); -dma_trait!(Ch3Dma, CaptureCompare16bitInstance); -dma_trait!(Ch4Dma, CaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +#[allow(unused)] +fn set_moe() { + unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) } + .bdtr() + .modify(|w| w.set_moe(true)); +} diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 59efb72ba..b6ab939cc 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -3,8 +3,10 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; +use stm32_metapac::timer::vals; -use super::*; +use super::low_level::Timer; +use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; use crate::gpio::sealed::AFType; use crate::gpio::AnyPin; use crate::Peripheral; @@ -30,7 +32,7 @@ pub struct QeiPin<'d, T, Channel> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { + impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); @@ -53,29 +55,28 @@ channel_impl!(new_ch1, Ch1, Channel1Pin); channel_impl!(new_ch2, Ch2, Channel2Pin); /// Quadrature decoder driver. -pub struct Qei<'d, T> { - _inner: PeripheralRef<'d, T>, +pub struct Qei<'d, T: GeneralInstance4Channel> { + inner: Timer<'d, T>, } -impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { +impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { /// Create a new quadrature decoder driver. pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) } fn new_inner(tim: impl Peripheral

+ 'd) -> Self { - into_ref!(tim); - - T::enable_and_reset(); + let inner = Timer::new(tim); + let r = inner.regs_gp16(); // Configure TxC1 and TxC2 as captures - T::regs_gp16().ccmr_input(0).modify(|w| { + r.ccmr_input(0).modify(|w| { w.set_ccs(0, vals::CcmrInputCcs::TI4); w.set_ccs(1, vals::CcmrInputCcs::TI4); }); // enable and configure to capture on rising edge - T::regs_gp16().ccer().modify(|w| { + r.ccer().modify(|w| { w.set_cce(0, true); w.set_cce(1, true); @@ -83,19 +84,19 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { w.set_ccp(1, false); }); - T::regs_gp16().smcr().modify(|w| { + r.smcr().modify(|w| { w.set_sms(vals::Sms::ENCODER_MODE_3); }); - T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX)); - T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + r.arr().modify(|w| w.set_arr(u16::MAX)); + r.cr1().modify(|w| w.set_cen(true)); - Self { _inner: tim } + Self { inner } } /// Get direction. pub fn read_direction(&self) -> Direction { - match T::regs_gp16().cr1().read().dir() { + match self.inner.regs_gp16().cr1().read().dir() { vals::Dir::DOWN => Direction::Downcounting, vals::Dir::UP => Direction::Upcounting, } @@ -103,6 +104,6 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { /// Get count. pub fn count(&self) -> u16 { - T::regs_gp16().cnt().read().cnt() + self.inner.regs_gp16().cnt().read().cnt() } } diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 4669fc6cc..b54e9a0d6 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -4,10 +4,10 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; -use super::*; -#[allow(unused_imports)] -use crate::gpio::sealed::{AFType, Pin}; +use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; +use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; use crate::gpio::{AnyPin, OutputType}; +use crate::time::Hertz; use crate::Peripheral; /// Channel 1 marker type. @@ -29,7 +29,7 @@ pub struct PwmPin<'d, T, C> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { + impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); @@ -54,11 +54,11 @@ channel_impl!(new_ch3, Ch3, Channel3Pin); channel_impl!(new_ch4, Ch4, Channel4Pin); /// Simple PWM driver. -pub struct SimplePwm<'d, T> { - inner: PeripheralRef<'d, T>, +pub struct SimplePwm<'d, T: GeneralInstance4Channel> { + inner: Timer<'d, T>, } -impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { +impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, @@ -73,15 +73,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { } fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { - into_ref!(tim); - - T::enable_and_reset(); - - let mut this = Self { inner: tim }; + let mut this = Self { inner: Timer::new(tim) }; this.inner.set_counting_mode(counting_mode); this.set_frequency(freq); - this.inner.enable_outputs(); // Required for advanced timers, see CaptureCompare16bitInstance for details + this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details this.inner.start(); [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] @@ -126,14 +122,14 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Get max duty value. /// /// This value depends on the configured frequency and the timer's clock rate from RCC. - pub fn get_max_duty(&self) -> u16 { + pub fn get_max_duty(&self) -> u32 { self.inner.get_max_compare_value() + 1 } /// Set the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. - pub fn set_duty(&mut self, channel: Channel, duty: u16) { + pub fn set_duty(&mut self, channel: Channel, duty: u32) { assert!(duty <= self.get_max_duty()); self.inner.set_compare_value(channel, duty) } @@ -141,7 +137,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Get the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. - pub fn get_duty(&self, channel: Channel) -> u16 { + pub fn get_duty(&self, channel: Channel) -> u32 { self.inner.get_compare_value(channel) } @@ -165,8 +161,6 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { channel: Channel, duty: &[u16], ) { - assert!(duty.iter().all(|v| *v <= self.get_max_duty())); - into_ref!(dma); #[allow(clippy::let_unit_value)] // eg. stm32f334 @@ -201,7 +195,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { &mut dma, req, duty, - T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _, + self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut _, dma_transfer_option, ) .await @@ -227,22 +221,20 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { macro_rules! impl_waveform_chx { ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { - impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { + impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform /// /// Note: /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. pub async fn $fn_name(&mut self, dma: impl Peripheral

>, duty: &[u16]) { - use super::vals::Ccds; - - assert!(duty.iter().all(|v| *v <= self.get_max_duty())); + use crate::pac::timer::vals::Ccds; into_ref!(dma); #[allow(clippy::let_unit_value)] // eg. stm32f334 let req = dma.request(); - let cc_channel = super::Channel::$cc_ch; + let cc_channel = Channel::$cc_ch; let original_duty_state = self.get_duty(cc_channel); let original_enable_state = self.is_enabled(cc_channel); @@ -279,7 +271,7 @@ macro_rules! impl_waveform_chx { &mut dma, req, duty, - T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, dma_transfer_option, ) .await @@ -314,10 +306,10 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); -impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { +impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { type Channel = Channel; type Time = Hertz; - type Duty = u16; + type Duty = u32; fn disable(&mut self, channel: Self::Channel) { self.inner.enable_channel(channel, false); diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 6122cea2d..cbaff75fc 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -15,8 +15,9 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::low_level::CountingMode; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::{Channel, CountingMode}; +use embassy_stm32::timer::Channel; use embassy_time::{Duration, Ticker, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -60,7 +61,7 @@ async fn main(_spawner: Spawner) { // construct ws2812 non-return-to-zero (NRZ) code bit by bit // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low - let max_duty = ws2812_pwm.get_max_duty(); + let max_duty = ws2812_pwm.get_max_duty() as u16; let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing let n1 = 2 * n0; // ws2812 Bit 1 high level timing diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index feec28993..c45747f35 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms; use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; use embassy_stm32::rcc::low_level::RccPeripheral; use embassy_stm32::time::Hertz; -use embassy_stm32::timer::low_level::BasicInstance; +use embassy_stm32::timer::low_level::Timer; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -51,12 +51,12 @@ async fn main(spawner: Spawner) { // Obtain two independent channels (p.DAC1 can only be consumed once, though!) let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); - spawner.spawn(dac_task1(dac_ch1)).ok(); - spawner.spawn(dac_task2(dac_ch2)).ok(); + spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok(); + spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok(); } #[embassy_executor::task] -async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { +async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", TIM6::frequency()); @@ -74,10 +74,10 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { dac.set_triggering(true); dac.enable(); - TIM6::enable_and_reset(); - TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); - TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); - TIM6::regs_basic().cr1().modify(|w| { + let tim = Timer::new(tim); + tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); + tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + tim.regs_basic().cr1().modify(|w| { w.set_opm(false); w.set_cen(true); }); @@ -99,7 +99,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { } #[embassy_executor::task] -async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { +async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", TIM7::frequency()); @@ -111,10 +111,10 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { error!("Reload value {} below threshold!", reload); } - TIM7::enable_and_reset(); - TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); - TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); - TIM7::regs_basic().cr1().modify(|w| { + let tim = Timer::new(tim); + tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); + tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + tim.regs_basic().cr1().modify(|w| { w.set_opm(false); w.set_cen(true); }); diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 049d9967d..780fbc6f0 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -6,8 +6,9 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::low_level::AFType; use embassy_stm32::gpio::Speed; use embassy_stm32::time::{khz, Hertz}; -use embassy_stm32::timer::*; -use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; +use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; +use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel}; +use embassy_stm32::{into_ref, Config, Peripheral}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -56,11 +57,11 @@ async fn main(_spawner: Spawner) { Timer::after_millis(300).await; } } -pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { - inner: PeripheralRef<'d, T>, +pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> { + tim: LLTimer<'d, T>, } -impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { +impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { pub fn new( tim: impl Peripheral

+ 'd, ch1: impl Peripheral

> + 'd, @@ -69,9 +70,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { ch4: impl Peripheral

> + 'd, freq: Hertz, ) -> Self { - into_ref!(tim, ch1, ch2, ch3, ch4); - - T::enable_and_reset(); + into_ref!(ch1, ch2, ch3, ch4); ch1.set_speed(Speed::VeryHigh); ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); @@ -82,12 +81,12 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { ch4.set_speed(Speed::VeryHigh); ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); - let mut this = Self { inner: tim }; + let mut this = Self { tim: LLTimer::new(tim) }; this.set_frequency(freq); - this.inner.start(); + this.tim.start(); - let r = T::regs_gp32(); + let r = this.tim.regs_gp32(); r.ccmr_output(0) .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); r.ccmr_output(0) @@ -101,23 +100,26 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { } pub fn enable(&mut self, channel: Channel) { - T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); + self.tim.regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); } pub fn disable(&mut self, channel: Channel) { - T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false)); + self.tim + .regs_gp32() + .ccer() + .modify(|w| w.set_cce(channel.index(), false)); } pub fn set_frequency(&mut self, freq: Hertz) { - ::set_frequency(&mut self.inner, freq); + self.tim.set_frequency(freq); } pub fn get_max_duty(&self) -> u32 { - T::regs_gp32().arr().read() + self.tim.regs_gp32().arr().read() } pub fn set_duty(&mut self, channel: Channel, duty: u32) { defmt::assert!(duty < self.get_max_duty()); - T::regs_gp32().ccr(channel.index()).write_value(duty) + self.tim.regs_gp32().ccr(channel.index()).write_value(duty) } } diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index f227812cd..98edd39c0 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms; use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; use embassy_stm32::rcc::low_level::RccPeripheral; use embassy_stm32::time::Hertz; -use embassy_stm32::timer::low_level::BasicInstance; +use embassy_stm32::timer::low_level::Timer; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -22,12 +22,12 @@ async fn main(spawner: Spawner) { // Obtain two independent channels (p.DAC1 can only be consumed once, though!) let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); - spawner.spawn(dac_task1(dac_ch1)).ok(); - spawner.spawn(dac_task2(dac_ch2)).ok(); + spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok(); + spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok(); } #[embassy_executor::task] -async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { +async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", TIM6::frequency()); @@ -45,10 +45,10 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { dac.set_triggering(true); dac.enable(); - TIM6::enable_and_reset(); - TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); - TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); - TIM6::regs_basic().cr1().modify(|w| { + let tim = Timer::new(tim); + tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); + tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + tim.regs_basic().cr1().modify(|w| { w.set_opm(false); w.set_cen(true); }); @@ -70,7 +70,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { } #[embassy_executor::task] -async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { +async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", TIM7::frequency()); @@ -82,10 +82,10 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { error!("Reload value {} below threshold!", reload); } - TIM7::enable_and_reset(); - TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); - TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); - TIM7::regs_basic().cr1().modify(|w| { + let tim = Timer::new(tim); + tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); + tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + tim.regs_basic().cr1().modify(|w| { w.set_opm(false); w.set_cen(true); }); From 2bca875b5f72578cbd20404010d174795d263313 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Mar 2024 01:38:51 +0100 Subject: [PATCH 737/760] stm32: use private_bounds for sealed traits. --- embassy-stm32/build.rs | 4 +- embassy-stm32/src/adc/f1.rs | 4 +- embassy-stm32/src/adc/f3.rs | 6 +- embassy-stm32/src/adc/f3_v1_1.rs | 4 +- embassy-stm32/src/adc/mod.rs | 100 +++-- embassy-stm32/src/adc/v1.rs | 6 +- embassy-stm32/src/adc/v2.rs | 6 +- embassy-stm32/src/adc/v3.rs | 8 +- embassy-stm32/src/adc/v4.rs | 8 +- embassy-stm32/src/can/bxcan.rs | 54 ++- embassy-stm32/src/can/fd/peripheral.rs | 61 +-- embassy-stm32/src/can/fdcan.rs | 378 +++++++++--------- embassy-stm32/src/crc/v1.rs | 2 +- embassy-stm32/src/crc/v2v3.rs | 2 +- embassy-stm32/src/cryp/mod.rs | 13 +- embassy-stm32/src/dac/mod.rs | 17 +- embassy-stm32/src/dcmi.rs | 14 +- embassy-stm32/src/dma/dmamux.rs | 9 +- embassy-stm32/src/dma/mod.rs | 24 +- embassy-stm32/src/dma/word.rs | 9 +- embassy-stm32/src/eth/mod.rs | 11 +- embassy-stm32/src/eth/v1/mod.rs | 23 +- embassy-stm32/src/eth/v2/mod.rs | 29 +- embassy-stm32/src/exti.rs | 11 +- embassy-stm32/src/fmc.rs | 18 +- embassy-stm32/src/gpio.rs | 305 +++++++------- embassy-stm32/src/hash/mod.rs | 15 +- embassy-stm32/src/hrtim/mod.rs | 17 +- embassy-stm32/src/hrtim/traits.rs | 128 +++--- embassy-stm32/src/i2c/mod.rs | 42 +- embassy-stm32/src/i2s.rs | 3 +- embassy-stm32/src/ipcc.rs | 89 ++--- embassy-stm32/src/lib.rs | 2 +- embassy-stm32/src/opamp.rs | 58 +-- embassy-stm32/src/qspi/mod.rs | 16 +- embassy-stm32/src/rcc/hsi48.rs | 2 +- embassy-stm32/src/rcc/mco.rs | 27 +- embassy-stm32/src/rcc/mod.rs | 41 +- embassy-stm32/src/rng.rs | 13 +- embassy-stm32/src/rtc/datetime.rs | 2 +- embassy-stm32/src/rtc/mod.rs | 57 ++- embassy-stm32/src/rtc/v2.rs | 5 +- embassy-stm32/src/rtc/v3.rs | 6 +- embassy-stm32/src/sai/mod.rs | 41 +- embassy-stm32/src/sdmmc/mod.rs | 29 +- embassy-stm32/src/spi/mod.rs | 37 +- embassy-stm32/src/time_driver.rs | 4 +- embassy-stm32/src/timer/qei.rs | 3 +- embassy-stm32/src/ucpd.rs | 60 ++- embassy-stm32/src/usart/mod.rs | 90 ++--- embassy-stm32/src/usb/mod.rs | 4 +- embassy-stm32/src/usb/otg.rs | 27 +- embassy-stm32/src/usb/usb.rs | 17 +- embassy-stm32/src/wdg/mod.rs | 11 +- examples/stm32h7/src/bin/dac_dma.rs | 14 +- .../stm32h7/src/bin/low_level_timer_api.rs | 35 +- examples/stm32l4/src/bin/dac_dma.rs | 14 +- 57 files changed, 955 insertions(+), 1080 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ee224da67..15bb8ea62 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -584,7 +584,7 @@ fn main() { }; g.extend(quote! { - impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { + impl crate::rcc::SealedRccPeripheral for peripherals::#pname { fn frequency() -> crate::time::Hertz { #clock_frequency } @@ -1486,7 +1486,7 @@ fn main() { #[crate::interrupt] unsafe fn #irq () { #( - ::on_irq(); + ::on_irq(); )* } } diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index b27b99827..cecf67947 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -33,7 +33,7 @@ impl interrupt::typelevel::Handler for InterruptHandl pub struct Vref; impl AdcPin for Vref {} -impl super::sealed::AdcPin for Vref { +impl super::SealedAdcPin for Vref { fn channel(&self) -> u8 { 17 } @@ -41,7 +41,7 @@ impl super::sealed::AdcPin for Vref { pub struct Temperature; impl AdcPin for Temperature {} -impl super::sealed::AdcPin for Temperature { +impl super::SealedAdcPin for Temperature { fn channel(&self) -> u8 { 16 } diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index efade1f64..c5581dba1 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -33,7 +33,7 @@ impl interrupt::typelevel::Handler for InterruptHandl pub struct Vref; impl AdcPin for Vref {} -impl super::sealed::AdcPin for Vref { +impl super::SealedAdcPin for Vref { fn channel(&self) -> u8 { 18 } @@ -48,7 +48,7 @@ impl Vref { pub struct Temperature; impl AdcPin for Temperature {} -impl super::sealed::AdcPin for Temperature { +impl super::SealedAdcPin for Temperature { fn channel(&self) -> u8 { 16 } @@ -102,7 +102,7 @@ impl<'d, T: Instance> Adc<'d, T> { } fn freq() -> Hertz { - ::frequency() + ::frequency() } pub fn sample_time_for_us(&self, us: u32) -> SampleTime { diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index f842893fa..672ace04f 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -65,7 +65,7 @@ fn update_vref(op: i8) { pub struct Vref(core::marker::PhantomData); impl AdcPin for Vref {} -impl super::sealed::AdcPin for Vref { +impl super::SealedAdcPin for Vref { fn channel(&self) -> u8 { 17 } @@ -124,7 +124,7 @@ impl Drop for Vref { pub struct Temperature(core::marker::PhantomData); impl AdcPin for Temperature {} -impl super::sealed::AdcPin for Temperature { +impl super::SealedAdcPin for Temperature { fn channel(&self) -> u8 { 16 } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 0d0d40549..ead2357ce 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -17,6 +17,8 @@ mod _version; #[allow(unused)] #[cfg(not(adc_f3_v2))] pub use _version::*; +#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(adc_f1, adc_f3_v2)))] pub use crate::pac::adc::vals::Res as Resolution; @@ -31,63 +33,65 @@ pub struct Adc<'d, T: Instance> { sample_time: SampleTime, } -pub(crate) mod sealed { - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] - use embassy_sync::waitqueue::AtomicWaker; +#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +pub struct State { + pub waker: AtomicWaker, +} - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] - pub struct State { - pub waker: AtomicWaker, - } - - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] - impl State { - pub const fn new() -> Self { - Self { - waker: AtomicWaker::new(), - } +#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +impl State { + pub const fn new() -> Self { + Self { + waker: AtomicWaker::new(), } } +} - pub trait InterruptableInstance { - type Interrupt: crate::interrupt::typelevel::Interrupt; - } +trait SealedInstance { + #[allow(unused)] + fn regs() -> crate::pac::adc::Adc; + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] + fn common_regs() -> crate::pac::adccommon::AdcCommon; + #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] + fn state() -> &'static State; +} - pub trait Instance: InterruptableInstance { - fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] - fn common_regs() -> crate::pac::adccommon::AdcCommon; - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] - fn state() -> &'static State; - } +pub(crate) trait SealedAdcPin { + #[cfg(any(adc_v1, adc_l0, adc_v2))] + fn set_as_analog(&mut self) {} - pub trait AdcPin { - #[cfg(any(adc_v1, adc_l0, adc_v2))] - fn set_as_analog(&mut self) {} + #[allow(unused)] + fn channel(&self) -> u8; +} - fn channel(&self) -> u8; - } - - pub trait InternalChannel { - fn channel(&self) -> u8; - } +trait SealedInternalChannel { + #[allow(unused)] + fn channel(&self) -> u8; } /// 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)))] -pub trait Instance: sealed::Instance + crate::Peripheral

{} +#[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))] -pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} +#[allow(private_bounds)] +pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::RccPeripheral { + type Interrupt: crate::interrupt::typelevel::Interrupt; +} /// ADC pin. -pub trait AdcPin: sealed::AdcPin {} +#[allow(private_bounds)] +pub trait AdcPin: SealedAdcPin {} /// ADC internal channel. -pub trait InternalChannel: sealed::InternalChannel {} +#[allow(private_bounds)] +pub trait InternalChannel: SealedInternalChannel {} foreach_adc!( ($inst:ident, $common_inst:ident, $clock:ident) => { - impl crate::adc::sealed::Instance for peripherals::$inst { + impl crate::adc::SealedInstance for peripherals::$inst { fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } @@ -98,21 +102,15 @@ foreach_adc!( } #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] - fn state() -> &'static sealed::State { - static STATE: sealed::State = sealed::State::new(); + fn state() -> &'static State { + static STATE: State = State::new(); &STATE } } - foreach_interrupt!( - ($inst,adc,ADC,GLOBAL,$irq:ident) => { - impl sealed::InterruptableInstance for peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$irq; - } - }; - ); - - impl crate::adc::Instance for peripherals::$inst {} + impl crate::adc::Instance for peripherals::$inst { + type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL; + } }; ); @@ -120,10 +118,10 @@ macro_rules! impl_adc_pin { ($inst:ident, $pin:ident, $ch:expr) => { impl crate::adc::AdcPin for crate::peripherals::$pin {} - impl crate::adc::sealed::AdcPin for crate::peripherals::$pin { + impl crate::adc::SealedAdcPin for crate::peripherals::$pin { #[cfg(any(adc_v1, adc_l0, adc_v2))] fn set_as_analog(&mut self) { - ::set_as_analog(self); + ::set_as_analog(self); } fn channel(&self) -> u8 { diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index a8dc6ce98..e9b46be80 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -39,7 +39,7 @@ pub struct Vbat; impl AdcPin for Vbat {} #[cfg(not(adc_l0))] -impl super::sealed::AdcPin for Vbat { +impl super::SealedAdcPin for Vbat { fn channel(&self) -> u8 { 18 } @@ -47,7 +47,7 @@ impl super::sealed::AdcPin for Vbat { pub struct Vref; impl AdcPin for Vref {} -impl super::sealed::AdcPin for Vref { +impl super::SealedAdcPin for Vref { fn channel(&self) -> u8 { 17 } @@ -55,7 +55,7 @@ impl super::sealed::AdcPin for Vref { pub struct Temperature; impl AdcPin for Temperature {} -impl super::sealed::AdcPin for Temperature { +impl super::SealedAdcPin for Temperature { fn channel(&self) -> u8 { 16 } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index f6f7dbfcc..a43eb72db 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -16,7 +16,7 @@ pub const ADC_POWERUP_TIME_US: u32 = 3; pub struct VrefInt; impl AdcPin for VrefInt {} -impl super::sealed::AdcPin for VrefInt { +impl super::SealedAdcPin for VrefInt { fn channel(&self) -> u8 { 17 } @@ -31,7 +31,7 @@ impl VrefInt { pub struct Temperature; impl AdcPin for Temperature {} -impl super::sealed::AdcPin for Temperature { +impl super::SealedAdcPin for Temperature { fn channel(&self) -> u8 { cfg_if::cfg_if! { if #[cfg(any(stm32f2, stm32f40, stm32f41))] { @@ -52,7 +52,7 @@ impl Temperature { pub struct Vbat; impl AdcPin for Vbat {} -impl super::sealed::AdcPin for Vbat { +impl super::SealedAdcPin for Vbat { fn channel(&self) -> u8 { 18 } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 5f3512cad..8c9b47197 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -12,7 +12,7 @@ pub const VREF_CALIB_MV: u32 = 3000; pub struct VrefInt; impl AdcPin for VrefInt {} -impl super::sealed::AdcPin for VrefInt { +impl super::SealedAdcPin for VrefInt { fn channel(&self) -> u8 { cfg_if! { if #[cfg(adc_g0)] { @@ -29,7 +29,7 @@ impl super::sealed::AdcPin for VrefInt { pub struct Temperature; impl AdcPin for Temperature {} -impl super::sealed::AdcPin for Temperature { +impl super::SealedAdcPin for Temperature { fn channel(&self) -> u8 { cfg_if! { if #[cfg(adc_g0)] { @@ -46,7 +46,7 @@ impl super::sealed::AdcPin for Temperature { pub struct Vbat; impl AdcPin for Vbat {} -impl super::sealed::AdcPin for Vbat { +impl super::SealedAdcPin for Vbat { fn channel(&self) -> u8 { cfg_if! { if #[cfg(adc_g0)] { @@ -65,7 +65,7 @@ cfg_if! { if #[cfg(adc_h5)] { pub struct VddCore; impl AdcPin for VddCore {} - impl super::sealed::AdcPin for VddCore { + impl super::SealedAdcPin for VddCore { fn channel(&self) -> u8 { 6 } diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 3fd047375..1ae25bea2 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -35,7 +35,7 @@ const VBAT_CHANNEL: u8 = 17; /// Internal voltage reference channel. pub struct VrefInt; impl InternalChannel for VrefInt {} -impl super::sealed::InternalChannel for VrefInt { +impl super::SealedInternalChannel for VrefInt { fn channel(&self) -> u8 { VREF_CHANNEL } @@ -44,7 +44,7 @@ impl super::sealed::InternalChannel for VrefInt { /// Internal temperature channel. pub struct Temperature; impl InternalChannel for Temperature {} -impl super::sealed::InternalChannel for Temperature { +impl super::SealedInternalChannel for Temperature { fn channel(&self) -> u8 { TEMP_CHANNEL } @@ -53,7 +53,7 @@ impl super::sealed::InternalChannel for Temperature { /// Internal battery voltage channel. pub struct Vbat; impl InternalChannel for Vbat {} -impl super::sealed::InternalChannel for Vbat { +impl super::SealedInternalChannel for Vbat { fn channel(&self) -> u8 { VBAT_CHANNEL } @@ -276,7 +276,7 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn read

(&mut self, pin: &mut P) -> u16 where P: AdcPin, - P: crate::gpio::sealed::Pin, + P: crate::gpio::Pin, { pin.set_as_analog(); diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 1a625bdc4..017c5110d 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -7,9 +7,12 @@ pub mod bx; pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId}; use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::channel::Channel; +use embassy_sync::waitqueue::AtomicWaker; use futures::FutureExt; -use crate::gpio::sealed::AFType; +use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; use crate::pac::can::vals::{Ide, Lec}; use crate::rcc::RccPeripheral; @@ -485,37 +488,30 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> { } } -pub(crate) mod sealed { - use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; - use embassy_sync::channel::Channel; - use embassy_sync::waitqueue::AtomicWaker; +struct State { + pub tx_waker: AtomicWaker, + pub err_waker: AtomicWaker, + pub rx_queue: Channel, +} - use super::Envelope; - - pub struct State { - pub tx_waker: AtomicWaker, - pub err_waker: AtomicWaker, - pub rx_queue: Channel, - } - - impl State { - pub const fn new() -> Self { - Self { - tx_waker: AtomicWaker::new(), - err_waker: AtomicWaker::new(), - rx_queue: Channel::new(), - } +impl State { + pub const fn new() -> Self { + Self { + tx_waker: AtomicWaker::new(), + err_waker: AtomicWaker::new(), + rx_queue: Channel::new(), } } - - pub trait Instance { - fn regs() -> crate::pac::can::Can; - fn state() -> &'static State; - } +} + +trait SealedInstance { + fn regs() -> crate::pac::can::Can; + fn state() -> &'static State; } /// CAN instance trait. -pub trait Instance: sealed::Instance + RccPeripheral + 'static { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + 'static { /// TX interrupt for this instance. type TXInterrupt: crate::interrupt::typelevel::Interrupt; /// RX0 interrupt for this instance. @@ -533,14 +529,14 @@ unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> { foreach_peripheral!( (can, $inst:ident) => { - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { fn regs() -> crate::pac::can::Can { crate::pac::$inst } - fn state() -> &'static sealed::State { - static STATE: sealed::State = sealed::State::new(); + fn state() -> &'static State { + static STATE: State = State::new(); &STATE } } diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 682e13f4b..76b76afe1 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -325,17 +325,6 @@ impl Registers { */ } - /// Disables the CAN interface and returns back the raw peripheral it was created from. - #[inline] - pub fn free(mut self) { - //self.disable_interrupts(Interrupts::all()); - - //TODO check this! - self.enter_init_mode(); - self.set_power_down_mode(true); - //self.control.instance - } - /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] #[inline] pub fn apply_config(&mut self, config: FdCanConfig) { @@ -419,55 +408,6 @@ impl Registers { self.leave_init_mode(config); } - /// Moves out of ConfigMode and into InternalLoopbackMode - #[inline] - pub fn into_internal_loopback(mut self, config: FdCanConfig) { - self.set_loopback_mode(LoopbackMode::Internal); - self.leave_init_mode(config); - } - - /// Moves out of ConfigMode and into ExternalLoopbackMode - #[inline] - pub fn into_external_loopback(mut self, config: FdCanConfig) { - self.set_loopback_mode(LoopbackMode::External); - self.leave_init_mode(config); - } - - /// Moves out of ConfigMode and into RestrictedOperationMode - #[inline] - pub fn into_restricted(mut self, config: FdCanConfig) { - self.set_restricted_operations(true); - self.leave_init_mode(config); - } - - /// Moves out of ConfigMode and into NormalOperationMode - #[inline] - pub fn into_normal(mut self, config: FdCanConfig) { - self.set_normal_operations(true); - self.leave_init_mode(config); - } - - /// Moves out of ConfigMode and into BusMonitoringMode - #[inline] - pub fn into_bus_monitoring(mut self, config: FdCanConfig) { - self.set_bus_monitoring_mode(true); - self.leave_init_mode(config); - } - - /// Moves out of ConfigMode and into Testmode - #[inline] - pub fn into_test_mode(mut self, config: FdCanConfig) { - self.set_test_mode(true); - self.leave_init_mode(config); - } - - /// Moves out of ConfigMode and into PoweredDownmode - #[inline] - pub fn into_powered_down(mut self, config: FdCanConfig) { - self.set_power_down_mode(true); - self.leave_init_mode(config); - } - /// Configures the bit timings. /// /// You can use to calculate the `btr` parameter. Enter @@ -565,6 +505,7 @@ impl Registers { /// Configures and resets the timestamp counter #[inline] + #[allow(unused)] pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { #[cfg(stm32h7)] let (tcp, tss) = match select { diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 4c40f10e3..4ea036ab4 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -5,10 +5,11 @@ use core::task::Poll; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::channel::Channel; +use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; +use embassy_sync::waitqueue::AtomicWaker; use crate::can::fd::peripheral::Registers; -use crate::gpio::sealed::AFType; +use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals, Peripheral}; @@ -53,8 +54,8 @@ impl interrupt::typelevel::Handler for IT0Interrup } match &T::state().tx_mode { - sealed::TxMode::NonBuffered(waker) => waker.wake(), - sealed::TxMode::ClassicBuffered(buf) => { + TxMode::NonBuffered(waker) => waker.wake(), + TxMode::ClassicBuffered(buf) => { if !T::registers().tx_queue_is_full() { match buf.tx_receiver.try_receive() { Ok(frame) => { @@ -64,7 +65,7 @@ impl interrupt::typelevel::Handler for IT0Interrup } } } - sealed::TxMode::FdBuffered(buf) => { + TxMode::FdBuffered(buf) => { if !T::registers().tx_queue_is_full() { match buf.tx_receiver.try_receive() { Ok(frame) => { @@ -467,14 +468,14 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { - let rx_inner = sealed::ClassicBufferedRxInner { + let rx_inner = ClassicBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; - let tx_inner = sealed::ClassicBufferedTxInner { + let tx_inner = ClassicBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; - T::mut_state().rx_mode = sealed::RxMode::ClassicBuffered(rx_inner); - T::mut_state().tx_mode = sealed::TxMode::ClassicBuffered(tx_inner); + T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); + T::mut_state().tx_mode = TxMode::ClassicBuffered(tx_inner); }); self } @@ -509,8 +510,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr { fn drop(&mut self) { critical_section::with(|_| unsafe { - T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); }); } } @@ -585,14 +586,14 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { - let rx_inner = sealed::FdBufferedRxInner { + let rx_inner = FdBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; - let tx_inner = sealed::FdBufferedTxInner { + let tx_inner = FdBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; - T::mut_state().rx_mode = sealed::RxMode::FdBuffered(rx_inner); - T::mut_state().tx_mode = sealed::TxMode::FdBuffered(tx_inner); + T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); + T::mut_state().tx_mode = TxMode::FdBuffered(tx_inner); }); self } @@ -627,8 +628,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr { fn drop(&mut self) { critical_section::with(|_| unsafe { - T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); }); } } @@ -677,192 +678,180 @@ impl<'c, 'd, T: Instance> FdcanRx<'d, T> { } } -pub(crate) mod sealed { - use core::future::poll_fn; - use core::task::Poll; +struct ClassicBufferedRxInner { + rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, +} +struct ClassicBufferedTxInner { + tx_receiver: DynamicReceiver<'static, ClassicFrame>, +} - use embassy_sync::channel::{DynamicReceiver, DynamicSender}; - use embassy_sync::waitqueue::AtomicWaker; +struct FdBufferedRxInner { + rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, +} +struct FdBufferedTxInner { + tx_receiver: DynamicReceiver<'static, FdFrame>, +} - use super::CanHeader; - use crate::can::_version::{BusError, Timestamp}; - use crate::can::frame::{ClassicFrame, FdFrame}; +enum RxMode { + NonBuffered(AtomicWaker), + ClassicBuffered(ClassicBufferedRxInner), + FdBuffered(FdBufferedRxInner), +} - pub struct ClassicBufferedRxInner { - pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, - } - pub struct ClassicBufferedTxInner { - pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, - } - - pub struct FdBufferedRxInner { - pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, - } - pub struct FdBufferedTxInner { - pub tx_receiver: DynamicReceiver<'static, FdFrame>, - } - - pub enum RxMode { - NonBuffered(AtomicWaker), - ClassicBuffered(ClassicBufferedRxInner), - FdBuffered(FdBufferedRxInner), - } - - impl RxMode { - pub fn register(&self, arg: &core::task::Waker) { - match self { - RxMode::NonBuffered(waker) => waker.register(arg), - _ => { - panic!("Bad Mode") - } - } - } - - pub fn on_interrupt(&self, fifonr: usize) { - T::regs().ir().write(|w| w.set_rfn(fifonr, true)); - match self { - RxMode::NonBuffered(waker) => { - waker.wake(); - } - RxMode::ClassicBuffered(buf) => { - if let Some(result) = self.read::() { - let _ = buf.rx_sender.try_send(result); - } - } - RxMode::FdBuffered(buf) => { - if let Some(result) = self.read::() { - let _ = buf.rx_sender.try_send(result); - } - } - } - } - - fn read(&self) -> Option> { - if let Some((msg, ts)) = T::registers().read(0) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); - Some(Ok((msg, ts))) - } else if let Some((msg, ts)) = T::registers().read(1) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); - Some(Ok((msg, ts))) - } else if let Some(err) = T::registers().curr_error() { - // TODO: this is probably wrong - Some(Err(err)) - } else { - None - } - } - - async fn read_async(&self) -> Result<(F, Timestamp), BusError> { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - self.register(cx.waker()); - match self.read::() { - Some(result) => Poll::Ready(result), - None => Poll::Pending, - } - }) - .await - } - - pub async fn read_classic(&self) -> Result<(ClassicFrame, Timestamp), BusError> { - self.read_async::().await - } - - pub async fn read_fd(&self) -> Result<(FdFrame, Timestamp), BusError> { - self.read_async::().await - } - } - - pub enum TxMode { - NonBuffered(AtomicWaker), - ClassicBuffered(ClassicBufferedTxInner), - FdBuffered(FdBufferedTxInner), - } - - impl TxMode { - pub fn register(&self, arg: &core::task::Waker) { - match self { - TxMode::NonBuffered(waker) => { - waker.register(arg); - } - _ => { - panic!("Bad mode"); - } - } - } - - /// Queues the message to be sent but exerts backpressure. If a lower-priority - /// frame is dropped from the mailbox, it is returned. If no lower-priority frames - /// can be replaced, this call asynchronously waits for a frame to be successfully - /// transmitted, then tries again. - async fn write_generic(&self, frame: &F) -> Option { - poll_fn(|cx| { - self.register(cx.waker()); - - if let Ok(dropped) = T::registers().write(frame) { - return Poll::Ready(dropped); - } - - // Couldn't replace any lower priority frames. Need to wait for some mailboxes - // to clear. - Poll::Pending - }) - .await - } - - /// Queues the message to be sent but exerts backpressure. If a lower-priority - /// frame is dropped from the mailbox, it is returned. If no lower-priority frames - /// can be replaced, this call asynchronously waits for a frame to be successfully - /// transmitted, then tries again. - pub async fn write(&self, frame: &ClassicFrame) -> Option { - self.write_generic::(frame).await - } - - /// Queues the message to be sent but exerts backpressure. If a lower-priority - /// frame is dropped from the mailbox, it is returned. If no lower-priority frames - /// can be replaced, this call asynchronously waits for a frame to be successfully - /// transmitted, then tries again. - pub async fn write_fd(&self, frame: &FdFrame) -> Option { - self.write_generic::(frame).await - } - } - - pub struct State { - pub rx_mode: RxMode, - pub tx_mode: TxMode, - pub ns_per_timer_tick: u64, - - pub err_waker: AtomicWaker, - } - - impl State { - pub const fn new() -> Self { - Self { - rx_mode: RxMode::NonBuffered(AtomicWaker::new()), - tx_mode: TxMode::NonBuffered(AtomicWaker::new()), - ns_per_timer_tick: 0, - err_waker: AtomicWaker::new(), +impl RxMode { + fn register(&self, arg: &core::task::Waker) { + match self { + RxMode::NonBuffered(waker) => waker.register(arg), + _ => { + panic!("Bad Mode") } } } - pub trait Instance { - const MSG_RAM_OFFSET: usize; + fn on_interrupt(&self, fifonr: usize) { + T::regs().ir().write(|w| w.set_rfn(fifonr, true)); + match self { + RxMode::NonBuffered(waker) => { + waker.wake(); + } + RxMode::ClassicBuffered(buf) => { + if let Some(result) = self.read::() { + let _ = buf.rx_sender.try_send(result); + } + } + RxMode::FdBuffered(buf) => { + if let Some(result) = self.read::() { + let _ = buf.rx_sender.try_send(result); + } + } + } + } - fn regs() -> &'static crate::pac::can::Fdcan; - fn registers() -> crate::can::fd::peripheral::Registers; - fn ram() -> &'static crate::pac::fdcanram::Fdcanram; - fn state() -> &'static State; - unsafe fn mut_state() -> &'static mut State; - fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; + fn read(&self) -> Option> { + if let Some((msg, ts)) = T::registers().read(0) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + Some(Ok((msg, ts))) + } else if let Some((msg, ts)) = T::registers().read(1) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + Some(Ok((msg, ts))) + } else if let Some(err) = T::registers().curr_error() { + // TODO: this is probably wrong + Some(Err(err)) + } else { + None + } + } + + async fn read_async(&self) -> Result<(F, Timestamp), BusError> { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + self.register(cx.waker()); + match self.read::() { + Some(result) => Poll::Ready(result), + None => Poll::Pending, + } + }) + .await + } + + async fn read_classic(&self) -> Result<(ClassicFrame, Timestamp), BusError> { + self.read_async::().await + } + + async fn read_fd(&self) -> Result<(FdFrame, Timestamp), BusError> { + self.read_async::().await } } +enum TxMode { + NonBuffered(AtomicWaker), + ClassicBuffered(ClassicBufferedTxInner), + FdBuffered(FdBufferedTxInner), +} + +impl TxMode { + fn register(&self, arg: &core::task::Waker) { + match self { + TxMode::NonBuffered(waker) => { + waker.register(arg); + } + _ => { + panic!("Bad mode"); + } + } + } + + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + async fn write_generic(&self, frame: &F) -> Option { + poll_fn(|cx| { + self.register(cx.waker()); + + if let Ok(dropped) = T::registers().write(frame) { + return Poll::Ready(dropped); + } + + // Couldn't replace any lower priority frames. Need to wait for some mailboxes + // to clear. + Poll::Pending + }) + .await + } + + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + async fn write(&self, frame: &ClassicFrame) -> Option { + self.write_generic::(frame).await + } + + /// Queues the message to be sent but exerts backpressure. If a lower-priority + /// frame is dropped from the mailbox, it is returned. If no lower-priority frames + /// can be replaced, this call asynchronously waits for a frame to be successfully + /// transmitted, then tries again. + async fn write_fd(&self, frame: &FdFrame) -> Option { + self.write_generic::(frame).await + } +} + +struct State { + pub rx_mode: RxMode, + pub tx_mode: TxMode, + pub ns_per_timer_tick: u64, + + pub err_waker: AtomicWaker, +} + +impl State { + const fn new() -> Self { + Self { + rx_mode: RxMode::NonBuffered(AtomicWaker::new()), + tx_mode: TxMode::NonBuffered(AtomicWaker::new()), + ns_per_timer_tick: 0, + err_waker: AtomicWaker::new(), + } + } +} + +trait SealedInstance { + const MSG_RAM_OFFSET: usize; + + fn regs() -> &'static crate::pac::can::Fdcan; + fn registers() -> crate::can::fd::peripheral::Registers; + fn state() -> &'static State; + unsafe fn mut_state() -> &'static mut State; + fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; +} + /// Instance trait -pub trait Instance: sealed::Instance + RccPeripheral + 'static { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + 'static { /// Interrupt 0 type IT0Interrupt: crate::interrupt::typelevel::Interrupt; - /// Interrupt 0 + /// Interrupt 1 type IT1Interrupt: crate::interrupt::typelevel::Interrupt; } @@ -871,7 +860,7 @@ pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); macro_rules! impl_fdcan { ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { const MSG_RAM_OFFSET: usize = $msg_ram_offset; fn regs() -> &'static crate::pac::can::Fdcan { @@ -880,14 +869,11 @@ macro_rules! impl_fdcan { fn registers() -> Registers { Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} } - fn ram() -> &'static crate::pac::fdcanram::Fdcanram { - &crate::pac::$msg_ram_inst - } - unsafe fn mut_state() -> &'static mut sealed::State { - static mut STATE: sealed::State = sealed::State::new(); + unsafe fn mut_state() -> &'static mut State { + static mut STATE: State = State::new(); &mut *core::ptr::addr_of_mut!(STATE) } - fn state() -> &'static sealed::State { + fn state() -> &'static State { unsafe { peripherals::$inst::mut_state() } } diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index 0166ab819..f8909d438 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -2,7 +2,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::pac::CRC as PAC_CRC; use crate::peripherals::CRC; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; use crate::Peripheral; /// CRC driver. diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index 0c4ae55ce..46f5ea1be 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -3,7 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::pac::crc::vals; use crate::pac::CRC as PAC_CRC; use crate::peripherals::CRC; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; use crate::Peripheral; /// CRC driver. diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 74b095b6f..18b5ec918 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1885,16 +1885,13 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } } -pub(crate) mod sealed { - use super::*; - - pub trait Instance { - fn regs() -> pac::cryp::Cryp; - } +trait SealedInstance { + fn regs() -> pac::cryp::Cryp; } /// CRYP instance trait. -pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { /// Interrupt for this CRYP instance. type Interrupt: interrupt::typelevel::Interrupt; } @@ -1905,7 +1902,7 @@ foreach_interrupt!( type Interrupt = crate::interrupt::typelevel::$irq; } - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { fn regs() -> crate::pac::cryp::Cryp { crate::pac::$inst } diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 60f9404c2..acfed8356 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -127,7 +127,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn new( _peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - pin: impl Peripheral

+ crate::gpio::sealed::Pin> + 'd, + pin: impl Peripheral

+ crate::gpio::Pin> + 'd, ) -> Self { into_ref!(dma, pin); pin.set_as_analog(); @@ -392,8 +392,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { _peri: impl Peripheral

+ 'd, dma_ch1: impl Peripheral

+ 'd, dma_ch2: impl Peripheral

+ 'd, - pin_ch1: impl Peripheral

+ crate::gpio::sealed::Pin> + 'd, - pin_ch2: impl Peripheral

+ crate::gpio::sealed::Pin> + 'd, + pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, + pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, ) -> Self { into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); pin_ch1.set_as_analog(); @@ -488,14 +488,13 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { } } -pub(crate) mod sealed { - pub trait Instance { - fn regs() -> &'static crate::pac::dac::Dac; - } +trait SealedInstance { + fn regs() -> &'static crate::pac::dac::Dac; } /// DAC instance. -pub trait Instance: sealed::Instance + RccPeripheral + 'static {} +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + 'static {} dma_trait!(DacDma1, Instance); dma_trait!(DacDma2, Instance); @@ -504,7 +503,7 @@ pub trait DacPin: crate::gpio::Pin + 'static {} foreach_peripheral!( (dac, $inst:ident) => { - impl crate::dac::sealed::Instance for peripherals::$inst { + impl crate::dac::SealedInstance for peripherals::$inst { fn regs() -> &'static crate::pac::dac::Dac { &crate::pac::$inst } diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 826b04a4b..646ee2ce2 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -7,8 +7,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use crate::dma::Transfer; -use crate::gpio::sealed::AFType; -use crate::gpio::Speed; +use crate::gpio::{AFType, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::{interrupt, Peripheral}; @@ -431,14 +430,13 @@ where } } -mod sealed { - pub trait Instance: crate::rcc::RccPeripheral { - fn regs(&self) -> crate::pac::dcmi::Dcmi; - } +trait SealedInstance: crate::rcc::RccPeripheral { + fn regs(&self) -> crate::pac::dcmi::Dcmi; } /// DCMI instance. -pub trait Instance: sealed::Instance + 'static { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static { /// Interrupt for this instance. type Interrupt: interrupt::typelevel::Interrupt; } @@ -465,7 +463,7 @@ pin_trait!(PixClkPin, Instance); #[allow(unused)] macro_rules! impl_peripheral { ($inst:ident, $irq:ident) => { - impl sealed::Instance for crate::peripherals::$inst { + impl SealedInstance for crate::peripherals::$inst { fn regs(&self) -> crate::pac::dcmi::Dcmi { crate::pac::$inst } diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 1e9ab5944..dc7cd3a66 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -19,9 +19,7 @@ pub(crate) fn configure_dmamux(info: &DmamuxInfo, request: u8) { }); } -pub(crate) mod dmamux_sealed { - pub trait MuxChannel {} -} +pub(crate) trait SealedMuxChannel {} /// DMAMUX1 instance. pub struct DMAMUX1; @@ -30,14 +28,15 @@ pub struct DMAMUX1; pub struct DMAMUX2; /// DMAMUX channel trait. -pub trait MuxChannel: dmamux_sealed::MuxChannel { +#[allow(private_bounds)] +pub trait MuxChannel: SealedMuxChannel { /// DMAMUX instance this channel is on. type Mux; } macro_rules! dmamux_channel_impl { ($channel_peri:ident, $dmamux:ident) => { - impl crate::dma::dmamux_sealed::MuxChannel for crate::peripherals::$channel_peri {} + impl crate::dma::SealedMuxChannel for crate::peripherals::$channel_peri {} impl crate::dma::MuxChannel for crate::peripherals::$channel_peri { type Mux = crate::dma::$dmamux; } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 2f98b9857..7e3681469 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -39,18 +39,18 @@ pub type Request = u8; #[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] pub type Request = (); -pub(crate) mod sealed { - pub trait Channel { - fn id(&self) -> u8; - } - pub trait ChannelInterrupt { - #[cfg_attr(not(feature = "rt"), allow(unused))] - unsafe fn on_irq(); - } +pub(crate) trait SealedChannel { + fn id(&self) -> u8; +} + +pub(crate) trait ChannelInterrupt { + #[cfg_attr(not(feature = "rt"), allow(unused))] + unsafe fn on_irq(); } /// DMA channel. -pub trait Channel: sealed::Channel + Peripheral

+ Into + 'static { +#[allow(private_bounds)] +pub trait Channel: SealedChannel + Peripheral

+ Into + 'static { /// Type-erase (degrade) this pin into an `AnyChannel`. /// /// This converts DMA channel singletons (`DMA1_CH3`, `DMA2_CH1`, ...), which @@ -64,12 +64,12 @@ pub trait Channel: sealed::Channel + Peripheral

+ Into + ' macro_rules! dma_channel_impl { ($channel_peri:ident, $index:expr) => { - impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { + impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { fn id(&self) -> u8 { $index } } - impl crate::dma::sealed::ChannelInterrupt for crate::peripherals::$channel_peri { + impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri { unsafe fn on_irq() { crate::dma::AnyChannel { id: $index }.on_irq(); } @@ -97,7 +97,7 @@ impl AnyChannel { } } -impl sealed::Channel for AnyChannel { +impl SealedChannel for AnyChannel { fn id(&self) -> u8 { self.id } diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs index a72c4b7d9..fb1bde860 100644 --- a/embassy-stm32/src/dma/word.rs +++ b/embassy-stm32/src/dma/word.rs @@ -20,14 +20,13 @@ impl WordSize { } } -mod sealed { - pub trait Word {} -} +trait SealedWord {} /// DMA word trait. /// /// This is implemented for u8, u16, u32, etc. -pub trait Word: sealed::Word + Default + Copy + 'static { +#[allow(private_bounds)] +pub trait Word: SealedWord + Default + Copy + 'static { /// Word size fn size() -> WordSize; /// Amount of bits of this word size. @@ -36,7 +35,7 @@ pub trait Word: sealed::Word + Default + Copy + 'static { macro_rules! impl_word { (_, $T:ident, $bits:literal, $size:ident) => { - impl sealed::Word for $T {} + impl SealedWord for $T {} impl Word for $T { fn bits() -> usize { $bits diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 71fe09c3f..bfe8a60d6 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -177,16 +177,15 @@ pub unsafe trait PHY { fn poll_link(&mut self, sm: &mut S, cx: &mut Context) -> bool; } -pub(crate) mod sealed { - pub trait Instance { - fn regs() -> crate::pac::eth::Eth; - } +trait SealedInstance { + fn regs() -> crate::pac::eth::Eth; } /// Ethernet instance. -pub trait Instance: sealed::Instance + RccPeripheral + Send + 'static {} +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {} -impl sealed::Instance for crate::peripherals::ETH { +impl SealedInstance for crate::peripherals::ETH { fn regs() -> crate::pac::eth::Eth { crate::pac::ETH } diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index e5b7b0452..6f0174def 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -12,15 +12,14 @@ use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress pub(crate) use self::rx_desc::{RDes, RDesRing}; pub(crate) use self::tx_desc::{TDes, TDesRing}; use super::*; -use crate::gpio::sealed::{AFType, Pin as __GpioPin}; -use crate::gpio::AnyPin; +use crate::gpio::{AFType, AnyPin, SealedPin}; use crate::interrupt::InterruptExt; #[cfg(eth_v1a)] use crate::pac::AFIO; #[cfg(any(eth_v1b, eth_v1c))] use crate::pac::SYSCFG; use crate::pac::{ETH, RCC}; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; use crate::{interrupt, Peripheral}; /// Interrupt handler. @@ -149,8 +148,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { #[cfg(any(eth_v1b, eth_v1c))] config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); - let dma = ETH.ethernet_dma(); - let mac = ETH.ethernet_mac(); + let dma = T::regs().ethernet_dma(); + let mac = T::regs().ethernet_mac(); // Reset and wait dma.dmabmr().modify(|w| w.set_sr(true)); @@ -192,7 +191,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // TODO MTU size setting not found for v1 ethernet, check if correct - let hclk = ::frequency(); + let hclk = ::frequency(); let hclk_mhz = hclk.0 / 1_000_000; // Set the MDC clock frequency in the range 1MHz - 2.5MHz @@ -235,8 +234,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { fence(Ordering::SeqCst); - let mac = ETH.ethernet_mac(); - let dma = ETH.ethernet_dma(); + let mac = T::regs().ethernet_mac(); + let dma = T::regs().ethernet_dma(); mac.maccr().modify(|w| { w.set_re(true); @@ -275,7 +274,7 @@ pub struct EthernetStationManagement { unsafe impl StationManagement for EthernetStationManagement { fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { - let mac = ETH.ethernet_mac(); + let mac = T::regs().ethernet_mac(); mac.macmiiar().modify(|w| { w.set_pa(phy_addr); @@ -289,7 +288,7 @@ unsafe impl StationManagement for EthernetStationManagement { } fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { - let mac = ETH.ethernet_mac(); + let mac = T::regs().ethernet_mac(); mac.macmiidr().write(|w| w.set_md(val)); mac.macmiiar().modify(|w| { @@ -305,8 +304,8 @@ unsafe impl StationManagement for EthernetStationManagement { impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { fn drop(&mut self) { - let dma = ETH.ethernet_dma(); - let mac = ETH.ethernet_mac(); + let dma = T::regs().ethernet_dma(); + let mac = T::regs().ethernet_mac(); // Disable the TX DMA and wait for any previous transmissions to be completed dma.dmaomr().modify(|w| w.set_st(St::STOPPED)); diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 8d69561d4..c6e015022 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -7,11 +7,10 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; use super::*; -use crate::gpio::sealed::{AFType, Pin as _}; -use crate::gpio::{AnyPin, Speed}; +use crate::gpio::{AFType, AnyPin, SealedPin as _, Speed}; use crate::interrupt::InterruptExt; use crate::pac::ETH; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; use crate::{interrupt, Peripheral}; /// Interrupt handler. @@ -207,9 +206,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { phy: P, mac_addr: [u8; 6], ) -> Self { - let dma = ETH.ethernet_dma(); - let mac = ETH.ethernet_mac(); - let mtl = ETH.ethernet_mtl(); + let dma = T::regs().ethernet_dma(); + let mac = T::regs().ethernet_mac(); + let mtl = T::regs().ethernet_mtl(); // Reset and wait dma.dmamr().modify(|w| w.set_swr(true)); @@ -265,7 +264,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_rbsz(RX_BUFFER_SIZE as u16); }); - let hclk = ::frequency(); + let hclk = ::frequency(); let hclk_mhz = hclk.0 / 1_000_000; // Set the MDC clock frequency in the range 1MHz - 2.5MHz @@ -296,9 +295,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { fence(Ordering::SeqCst); - let mac = ETH.ethernet_mac(); - let mtl = ETH.ethernet_mtl(); - let dma = ETH.ethernet_dma(); + let mac = T::regs().ethernet_mac(); + let mtl = T::regs().ethernet_mtl(); + let dma = T::regs().ethernet_dma(); mac.maccr().modify(|w| { w.set_re(true); @@ -334,7 +333,7 @@ pub struct EthernetStationManagement { unsafe impl StationManagement for EthernetStationManagement { fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { - let mac = ETH.ethernet_mac(); + let mac = T::regs().ethernet_mac(); mac.macmdioar().modify(|w| { w.set_pa(phy_addr); @@ -348,7 +347,7 @@ unsafe impl StationManagement for EthernetStationManagement { } fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { - let mac = ETH.ethernet_mac(); + let mac = T::regs().ethernet_mac(); mac.macmdiodr().write(|w| w.set_md(val)); mac.macmdioar().modify(|w| { @@ -364,9 +363,9 @@ unsafe impl StationManagement for EthernetStationManagement { impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { fn drop(&mut self) { - let dma = ETH.ethernet_dma(); - let mac = ETH.ethernet_mac(); - let mtl = ETH.ethernet_mtl(); + let dma = T::regs().ethernet_dma(); + let mac = T::regs().ethernet_mac(); + let mtl = T::regs().ethernet_mtl(); // Disable the TX DMA and wait for any previous transmissions to be completed dma.dmactx_cr().modify(|w| w.set_st(false)); diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index bd10ba158..8d5dae436 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -330,12 +330,11 @@ macro_rules! impl_irq { foreach_exti_irq!(impl_irq); -pub(crate) mod sealed { - pub trait Channel {} -} +trait SealedChannel {} /// EXTI channel trait. -pub trait Channel: sealed::Channel + Sized { +#[allow(private_bounds)] +pub trait Channel: SealedChannel + Sized { /// Get the EXTI channel number. fn number(&self) -> u8; @@ -359,7 +358,7 @@ pub struct AnyChannel { } impl_peripheral!(AnyChannel); -impl sealed::Channel for AnyChannel {} +impl SealedChannel for AnyChannel {} impl Channel for AnyChannel { fn number(&self) -> u8 { self.number @@ -368,7 +367,7 @@ impl Channel for AnyChannel { macro_rules! impl_exti { ($type:ident, $number:expr) => { - impl sealed::Channel for peripherals::$type {} + impl SealedChannel for peripherals::$type {} impl Channel for peripherals::$type { fn number(&self) -> u8 { $number diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 9d731a512..aced69878 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -3,8 +3,7 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; -use crate::gpio::sealed::AFType; -use crate::gpio::{Pull, Speed}; +use crate::gpio::{AFType, Pull, Speed}; use crate::Peripheral; /// FMC driver @@ -44,7 +43,7 @@ where /// Get the kernel clock currently in use for this FMC instance. pub fn source_clock_hz(&self) -> u32 { - ::frequency().0 + ::frequency().0 } } @@ -69,7 +68,7 @@ where } fn source_clock_hz(&self) -> u32 { - ::frequency().0 + ::frequency().0 } } @@ -201,18 +200,17 @@ impl<'d, T: Instance> Fmc<'d, T> { )); } -pub(crate) mod sealed { - pub trait Instance: crate::rcc::sealed::RccPeripheral { - const REGS: crate::pac::fmc::Fmc; - } +trait SealedInstance: crate::rcc::SealedRccPeripheral { + const REGS: crate::pac::fmc::Fmc; } /// FMC instance trait. -pub trait Instance: sealed::Instance + 'static {} +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static {} foreach_peripheral!( (fmc, $inst:ident) => { - impl crate::fmc::sealed::Instance for crate::peripherals::$inst { + impl crate::fmc::SealedInstance for crate::peripherals::$inst { const REGS: crate::pac::fmc::Fmc = crate::pac::$inst; } impl crate::fmc::Instance for crate::peripherals::$inst {} diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 7cc28ff56..33f22f676 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -6,7 +6,6 @@ use core::convert::Infallible; use critical_section::CriticalSection; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; -use self::sealed::Pin as _; use crate::pac::gpio::{self, vals}; use crate::{pac, peripherals, Peripheral}; @@ -129,6 +128,18 @@ impl<'d> Flex<'d> { }); } + /// Put the pin into AF mode, unchecked. + /// + /// This puts the pin into the AF mode, with the requested number, pull and speed. This is + /// completely unchecked, it can attach the pin to literally any peripheral, so use with care. + #[inline] + pub fn set_as_af_unchecked(&mut self, af_num: u8, af_type: AFType, pull: Pull, speed: Speed) { + critical_section::with(|_| { + self.pin.set_as_af_pull(af_num, af_type, pull); + self.pin.set_speed(speed); + }); + } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -508,172 +519,168 @@ pub enum OutputType { OpenDrain, } -impl From for sealed::AFType { +impl From for AFType { fn from(value: OutputType) -> Self { match value { - OutputType::OpenDrain => sealed::AFType::OutputOpenDrain, - OutputType::PushPull => sealed::AFType::OutputPushPull, + OutputType::OpenDrain => AFType::OutputOpenDrain, + OutputType::PushPull => AFType::OutputPushPull, } } } -#[allow(missing_docs)] -pub(crate) mod sealed { - use super::*; +/// Alternate function type settings +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AFType { + /// Input + Input, + /// Output, drive the pin both high or low. + OutputPushPull, + /// Output, drive the pin low, or don't drive it at all if the output level is high. + OutputOpenDrain, +} - /// Alternate function type settings - #[derive(Debug, Copy, Clone)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum AFType { - /// Input - Input, - /// Output, drive the pin both high or low. - OutputPushPull, - /// Output, drive the pin low, or don't drive it at all if the output level is high. - OutputOpenDrain, +pub(crate) trait SealedPin { + fn pin_port(&self) -> u8; + + #[inline] + fn _pin(&self) -> u8 { + self.pin_port() % 16 + } + #[inline] + fn _port(&self) -> u8 { + self.pin_port() / 16 } - pub trait Pin { - fn pin_port(&self) -> u8; + #[inline] + fn block(&self) -> gpio::Gpio { + pac::GPIO(self._port() as _) + } - #[inline] - fn _pin(&self) -> u8 { - self.pin_port() % 16 - } - #[inline] - fn _port(&self) -> u8 { - self.pin_port() / 16 - } + /// Set the output as high. + #[inline] + fn set_high(&self) { + let n = self._pin() as _; + self.block().bsrr().write(|w| w.set_bs(n, true)); + } - #[inline] - fn block(&self) -> gpio::Gpio { - pac::GPIO(self._port() as _) - } + /// Set the output as low. + #[inline] + fn set_low(&self) { + let n = self._pin() as _; + self.block().bsrr().write(|w| w.set_br(n, true)); + } - /// Set the output as high. - #[inline] - fn set_high(&self) { - let n = self._pin() as _; - self.block().bsrr().write(|w| w.set_bs(n, true)); - } + #[inline] + fn set_as_af(&self, af_num: u8, af_type: AFType) { + self.set_as_af_pull(af_num, af_type, Pull::None); + } - /// Set the output as low. - #[inline] - fn set_low(&self) { - let n = self._pin() as _; - self.block().bsrr().write(|w| w.set_br(n, true)); - } + #[cfg(gpio_v1)] + #[inline] + fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { + // F1 uses the AFIO register for remapping. + // For now, this is not implemented, so af_num is ignored + // _af_num should be zero here, since it is not set by stm32-data + let r = self.block(); + let n = self._pin() as usize; + let crlh = if n < 8 { 0 } else { 1 }; + match af_type { + AFType::Input => { + let cnf = match pull { + Pull::Up => { + r.bsrr().write(|w| w.set_bs(n, true)); + vals::CnfIn::PULL + } + Pull::Down => { + r.bsrr().write(|w| w.set_br(n, true)); + vals::CnfIn::PULL + } + Pull::None => vals::CnfIn::FLOATING, + }; - #[inline] - fn set_as_af(&self, af_num: u8, af_type: AFType) { - self.set_as_af_pull(af_num, af_type, Pull::None); + r.cr(crlh).modify(|w| { + w.set_mode(n % 8, vals::Mode::INPUT); + w.set_cnf_in(n % 8, cnf); + }); + } + AFType::OutputPushPull => { + r.cr(crlh).modify(|w| { + w.set_mode(n % 8, vals::Mode::OUTPUT50MHZ); + w.set_cnf_out(n % 8, vals::CnfOut::ALTPUSHPULL); + }); + } + AFType::OutputOpenDrain => { + r.cr(crlh).modify(|w| { + w.set_mode(n % 8, vals::Mode::OUTPUT50MHZ); + w.set_cnf_out(n % 8, vals::CnfOut::ALTOPENDRAIN); + }); + } } + } + + #[cfg(gpio_v2)] + #[inline] + fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { + let pin = self._pin() as usize; + let block = self.block(); + block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); + match af_type { + AFType::Input => {} + AFType::OutputPushPull => block.otyper().modify(|w| w.set_ot(pin, vals::Ot::PUSHPULL)), + AFType::OutputOpenDrain => block.otyper().modify(|w| w.set_ot(pin, vals::Ot::OPENDRAIN)), + } + block.pupdr().modify(|w| w.set_pupdr(pin, pull.into())); + + block.moder().modify(|w| w.set_moder(pin, vals::Moder::ALTERNATE)); + } + + #[inline] + fn set_as_analog(&self) { + let pin = self._pin() as usize; + let block = self.block(); + #[cfg(gpio_v1)] + { + let crlh = if pin < 8 { 0 } else { 1 }; + block.cr(crlh).modify(|w| { + w.set_mode(pin % 8, vals::Mode::INPUT); + w.set_cnf_in(pin % 8, vals::CnfIn::ANALOG); + }); + } + #[cfg(gpio_v2)] + block.moder().modify(|w| w.set_moder(pin, vals::Moder::ANALOG)); + } + + /// Set the pin as "disconnected", ie doing nothing and consuming the lowest + /// amount of power possible. + /// + /// This is currently the same as set_as_analog but is semantically different really. + /// Drivers should set_as_disconnected pins when dropped. + #[inline] + fn set_as_disconnected(&self) { + self.set_as_analog(); + } + + #[inline] + fn set_speed(&self, speed: Speed) { + let pin = self._pin() as usize; #[cfg(gpio_v1)] - #[inline] - fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { - // F1 uses the AFIO register for remapping. - // For now, this is not implemented, so af_num is ignored - // _af_num should be zero here, since it is not set by stm32-data - let r = self.block(); - let n = self._pin() as usize; - let crlh = if n < 8 { 0 } else { 1 }; - match af_type { - AFType::Input => { - let cnf = match pull { - Pull::Up => { - r.bsrr().write(|w| w.set_bs(n, true)); - vals::CnfIn::PULL - } - Pull::Down => { - r.bsrr().write(|w| w.set_br(n, true)); - vals::CnfIn::PULL - } - Pull::None => vals::CnfIn::FLOATING, - }; - - r.cr(crlh).modify(|w| { - w.set_mode(n % 8, vals::Mode::INPUT); - w.set_cnf_in(n % 8, cnf); - }); - } - AFType::OutputPushPull => { - r.cr(crlh).modify(|w| { - w.set_mode(n % 8, vals::Mode::OUTPUT50MHZ); - w.set_cnf_out(n % 8, vals::CnfOut::ALTPUSHPULL); - }); - } - AFType::OutputOpenDrain => { - r.cr(crlh).modify(|w| { - w.set_mode(n % 8, vals::Mode::OUTPUT50MHZ); - w.set_cnf_out(n % 8, vals::CnfOut::ALTOPENDRAIN); - }); - } - } + { + let crlh = if pin < 8 { 0 } else { 1 }; + self.block().cr(crlh).modify(|w| { + w.set_mode(pin % 8, speed.into()); + }); } #[cfg(gpio_v2)] - #[inline] - fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { - let pin = self._pin() as usize; - let block = self.block(); - block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); - match af_type { - AFType::Input => {} - AFType::OutputPushPull => block.otyper().modify(|w| w.set_ot(pin, vals::Ot::PUSHPULL)), - AFType::OutputOpenDrain => block.otyper().modify(|w| w.set_ot(pin, vals::Ot::OPENDRAIN)), - } - block.pupdr().modify(|w| w.set_pupdr(pin, pull.into())); - - block.moder().modify(|w| w.set_moder(pin, vals::Moder::ALTERNATE)); - } - - #[inline] - fn set_as_analog(&self) { - let pin = self._pin() as usize; - let block = self.block(); - #[cfg(gpio_v1)] - { - let crlh = if pin < 8 { 0 } else { 1 }; - block.cr(crlh).modify(|w| { - w.set_mode(pin % 8, vals::Mode::INPUT); - w.set_cnf_in(pin % 8, vals::CnfIn::ANALOG); - }); - } - #[cfg(gpio_v2)] - block.moder().modify(|w| w.set_moder(pin, vals::Moder::ANALOG)); - } - - /// Set the pin as "disconnected", ie doing nothing and consuming the lowest - /// amount of power possible. - /// - /// This is currently the same as set_as_analog but is semantically different really. - /// Drivers should set_as_disconnected pins when dropped. - #[inline] - fn set_as_disconnected(&self) { - self.set_as_analog(); - } - - #[inline] - fn set_speed(&self, speed: Speed) { - let pin = self._pin() as usize; - - #[cfg(gpio_v1)] - { - let crlh = if pin < 8 { 0 } else { 1 }; - self.block().cr(crlh).modify(|w| { - w.set_mode(pin % 8, speed.into()); - }); - } - - #[cfg(gpio_v2)] - self.block().ospeedr().modify(|w| w.set_ospeedr(pin, speed.into())); - } + self.block().ospeedr().modify(|w| w.set_ospeedr(pin, speed.into())); } } /// GPIO pin trait. -pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'static { +#[allow(private_bounds)] +pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static { /// EXTI channel assigned to this pin. /// /// For example, PC4 uses EXTI4. @@ -737,7 +744,7 @@ impl Pin for AnyPin { #[cfg(feature = "exti")] type ExtiChannel = crate::exti::AnyChannel; } -impl sealed::Pin for AnyPin { +impl SealedPin for AnyPin { #[inline] fn pin_port(&self) -> u8 { self.pin_port @@ -752,7 +759,7 @@ foreach_pin!( #[cfg(feature = "exti")] type ExtiChannel = peripherals::$exti_ch; } - impl sealed::Pin for peripherals::$pin_name { + impl SealedPin for peripherals::$pin_name { #[inline] fn pin_port(&self) -> u8 { $port_num * 16 + $pin_num @@ -769,7 +776,7 @@ foreach_pin!( pub(crate) unsafe fn init(_cs: CriticalSection) { #[cfg(afio)] - ::enable_and_reset_with_cs(_cs); + ::enable_and_reset_with_cs(_cs); crate::_generated::init_gpio(); @@ -1061,9 +1068,3 @@ impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> { Ok((*self).is_set_low()) } } - -/// Low-level GPIO manipulation. -#[cfg(feature = "unstable-pac")] -pub mod low_level { - pub use super::sealed::*; -} diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index b47814f8b..787d5b1c9 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -17,7 +17,7 @@ use crate::dma::NoDma; use crate::dma::Transfer; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::HASH; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; use crate::{interrupt, pac, peripherals, Peripheral}; #[cfg(hash_v1)] @@ -561,16 +561,13 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { } } -pub(crate) mod sealed { - use super::*; - - pub trait Instance { - fn regs() -> pac::hash::Hash; - } +trait SealedInstance { + fn regs() -> pac::hash::Hash; } /// HASH instance trait. -pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { /// Interrupt for this HASH instance. type Interrupt: interrupt::typelevel::Interrupt; } @@ -581,7 +578,7 @@ foreach_interrupt!( type Interrupt = crate::interrupt::typelevel::$irq; } - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { fn regs() -> crate::pac::hash::Hash { crate::pac::$inst } diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 3ec646fc3..02e45819c 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -7,9 +7,7 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; pub use traits::Instance; -#[allow(unused_imports)] -use crate::gpio::sealed::{AFType, Pin}; -use crate::gpio::AnyPin; +use crate::gpio::{AFType, AnyPin}; use crate::time::Hertz; use crate::Peripheral; @@ -54,16 +52,13 @@ pub struct ChF { phantom: PhantomData, } -mod sealed { - use super::Instance; - - pub trait AdvancedChannel { - fn raw() -> usize; - } +trait SealedAdvancedChannel { + fn raw() -> usize; } /// Advanced channel instance trait. -pub trait AdvancedChannel: sealed::AdvancedChannel {} +#[allow(private_bounds)] +pub trait AdvancedChannel: SealedAdvancedChannel {} /// HRTIM PWM pin. pub struct PwmPin<'d, T, C> { @@ -113,7 +108,7 @@ macro_rules! advanced_channel_impl { } } - impl sealed::AdvancedChannel for $channel { + impl SealedAdvancedChannel for $channel { fn raw() -> usize { $ch_num } diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index dcc2b9ef4..75f9971e2 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -1,4 +1,4 @@ -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::RccPeripheral; use crate::time::Hertz; #[repr(u8)] @@ -72,94 +72,92 @@ impl Prescaler { } } -pub(crate) mod sealed { - use super::*; +pub(crate) trait SealedInstance: RccPeripheral { + fn regs() -> crate::pac::hrtim::Hrtim; - pub trait Instance: RccPeripheral { - fn regs() -> crate::pac::hrtim::Hrtim; + #[allow(unused)] + fn set_master_frequency(frequency: Hertz) { + let f = frequency.0; - fn set_master_frequency(frequency: Hertz) { - let f = frequency.0; + // TODO: wire up HRTIM to the RCC mux infra. + //#[cfg(stm32f334)] + //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; + //#[cfg(not(stm32f334))] + let timer_f = Self::frequency().0; - // TODO: wire up HRTIM to the RCC mux infra. - //#[cfg(stm32f334)] - //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; - //#[cfg(not(stm32f334))] - let timer_f = Self::frequency().0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); + let psc = if Self::regs().isr().read().dllrdy() { + Prescaler::compute_min_high_res(psc_min) + } else { + Prescaler::compute_min_low_res(psc_min) + }; - let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); - let psc = if Self::regs().isr().read().dllrdy() { - Prescaler::compute_min_high_res(psc_min) - } else { - Prescaler::compute_min_low_res(psc_min) - }; + let timer_f = 32 * (timer_f / psc as u32); + let per: u16 = (timer_f / f) as u16; - let timer_f = 32 * (timer_f / psc as u32); - let per: u16 = (timer_f / f) as u16; + let regs = Self::regs(); - let regs = Self::regs(); + regs.mcr().modify(|w| w.set_ckpsc(psc.into())); + regs.mper().modify(|w| w.set_mper(per)); + } - regs.mcr().modify(|w| w.set_ckpsc(psc.into())); - regs.mper().modify(|w| w.set_mper(per)); - } + fn set_channel_frequency(channel: usize, frequency: Hertz) { + let f = frequency.0; - fn set_channel_frequency(channel: usize, frequency: Hertz) { - let f = frequency.0; + // TODO: wire up HRTIM to the RCC mux infra. + //#[cfg(stm32f334)] + //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; + //#[cfg(not(stm32f334))] + let timer_f = Self::frequency().0; - // TODO: wire up HRTIM to the RCC mux infra. - //#[cfg(stm32f334)] - //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; - //#[cfg(not(stm32f334))] - let timer_f = Self::frequency().0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); + let psc = if Self::regs().isr().read().dllrdy() { + Prescaler::compute_min_high_res(psc_min) + } else { + Prescaler::compute_min_low_res(psc_min) + }; - let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); - let psc = if Self::regs().isr().read().dllrdy() { - Prescaler::compute_min_high_res(psc_min) - } else { - Prescaler::compute_min_low_res(psc_min) - }; + let timer_f = 32 * (timer_f / psc as u32); + let per: u16 = (timer_f / f) as u16; - let timer_f = 32 * (timer_f / psc as u32); - let per: u16 = (timer_f / f) as u16; + let regs = Self::regs(); - let regs = Self::regs(); + regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); + regs.tim(channel).per().modify(|w| w.set_per(per)); + } - regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); - regs.tim(channel).per().modify(|w| w.set_per(per)); - } + /// Set the dead time as a proportion of max_duty + fn set_channel_dead_time(channel: usize, dead_time: u16) { + let regs = Self::regs(); - /// Set the dead time as a proportion of max_duty - fn set_channel_dead_time(channel: usize, dead_time: u16) { - let regs = Self::regs(); + let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); - let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); + // The dead-time base clock runs 4 times slower than the hrtim base clock + // u9::MAX = 511 + let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); + let psc = if Self::regs().isr().read().dllrdy() { + Prescaler::compute_min_high_res(psc_min) + } else { + Prescaler::compute_min_low_res(psc_min) + }; - // The dead-time base clock runs 4 times slower than the hrtim base clock - // u9::MAX = 511 - let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); - let psc = if Self::regs().isr().read().dllrdy() { - Prescaler::compute_min_high_res(psc_min) - } else { - Prescaler::compute_min_low_res(psc_min) - }; + let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); - let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); - - regs.tim(channel).dt().modify(|w| { - w.set_dtprsc(psc.into()); - w.set_dtf(dt_val as u16); - w.set_dtr(dt_val as u16); - }); - } + regs.tim(channel).dt().modify(|w| { + w.set_dtprsc(psc.into()); + w.set_dtf(dt_val as u16); + w.set_dtr(dt_val as u16); + }); } } /// HRTIM instance trait. -pub trait Instance: sealed::Instance + 'static {} +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static {} foreach_interrupt! { ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { - impl sealed::Instance for crate::peripherals::$inst { + impl SealedInstance for crate::peripherals::$inst { fn regs() -> crate::pac::hrtim::Hrtim { crate::pac::$inst } diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 2c606c3c9..f1b11cc44 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -14,8 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker; use embassy_time::{Duration, Instant}; use crate::dma::NoDma; -use crate::gpio::sealed::AFType; -use crate::gpio::Pull; +use crate::gpio::{AFType, Pull}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; use crate::{interrupt, peripherals}; @@ -175,30 +174,27 @@ impl Timeout { } } -pub(crate) mod sealed { - use super::*; +struct State { + #[allow(unused)] + waker: AtomicWaker, +} - pub struct State { - #[allow(unused)] - pub waker: AtomicWaker, - } - - impl State { - pub const fn new() -> Self { - Self { - waker: AtomicWaker::new(), - } +impl State { + const fn new() -> Self { + Self { + waker: AtomicWaker::new(), } } - - pub trait Instance: crate::rcc::RccPeripheral { - fn regs() -> crate::pac::i2c::I2c; - fn state() -> &'static State; - } +} + +trait SealedInstance: crate::rcc::RccPeripheral { + fn regs() -> crate::pac::i2c::I2c; + fn state() -> &'static State; } /// I2C peripheral instance -pub trait Instance: sealed::Instance + 'static { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static { /// Event interrupt for this instance type EventInterrupt: interrupt::typelevel::Interrupt; /// Error interrupt for this instance @@ -234,13 +230,13 @@ impl interrupt::typelevel::Handler for ErrorInte foreach_peripheral!( (i2c, $inst:ident) => { - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { fn regs() -> crate::pac::i2c::I2c { crate::pac::$inst } - fn state() -> &'static sealed::State { - static STATE: sealed::State = sealed::State::new(); + fn state() -> &'static State { + static STATE: State = State::new(); &STATE } } diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index fa9ec0532..c5a606b21 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -1,8 +1,7 @@ //! Inter-IC Sound (I2S) use embassy_hal_internal::into_ref; -use crate::gpio::sealed::{AFType, Pin as _}; -use crate::gpio::AnyPin; +use crate::gpio::{AFType, AnyPin, SealedPin}; use crate::pac::spi::vals; use crate::spi::{Config as SpiConfig, *}; use crate::time::Hertz; diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 523719bb9..4d535cce2 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -4,11 +4,12 @@ use core::future::poll_fn; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; -use self::sealed::Instance; +use embassy_sync::waitqueue::AtomicWaker; + use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::IPCC; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; /// Interrupt handler. pub struct ReceiveInterruptHandler {} @@ -207,7 +208,7 @@ impl Ipcc { } } -impl sealed::Instance for crate::peripherals::IPCC { +impl SealedInstance for crate::peripherals::IPCC { fn regs() -> crate::pac::ipcc::Ipcc { crate::pac::IPCC } @@ -216,58 +217,52 @@ impl sealed::Instance for crate::peripherals::IPCC { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)); } - fn state() -> &'static self::sealed::State { - static STATE: self::sealed::State = self::sealed::State::new(); + fn state() -> &'static State { + static STATE: State = State::new(); &STATE } } -pub(crate) mod sealed { - use embassy_sync::waitqueue::AtomicWaker; +struct State { + rx_wakers: [AtomicWaker; 6], + tx_wakers: [AtomicWaker; 6], +} - use super::*; +impl State { + const fn new() -> Self { + const WAKER: AtomicWaker = AtomicWaker::new(); - pub struct State { - rx_wakers: [AtomicWaker; 6], - tx_wakers: [AtomicWaker; 6], - } - - impl State { - pub const fn new() -> Self { - const WAKER: AtomicWaker = AtomicWaker::new(); - - Self { - rx_wakers: [WAKER; 6], - tx_wakers: [WAKER; 6], - } - } - - pub const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { - match channel { - IpccChannel::Channel1 => &self.rx_wakers[0], - IpccChannel::Channel2 => &self.rx_wakers[1], - IpccChannel::Channel3 => &self.rx_wakers[2], - IpccChannel::Channel4 => &self.rx_wakers[3], - IpccChannel::Channel5 => &self.rx_wakers[4], - IpccChannel::Channel6 => &self.rx_wakers[5], - } - } - - pub const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { - match channel { - IpccChannel::Channel1 => &self.tx_wakers[0], - IpccChannel::Channel2 => &self.tx_wakers[1], - IpccChannel::Channel3 => &self.tx_wakers[2], - IpccChannel::Channel4 => &self.tx_wakers[3], - IpccChannel::Channel5 => &self.tx_wakers[4], - IpccChannel::Channel6 => &self.tx_wakers[5], - } + Self { + rx_wakers: [WAKER; 6], + tx_wakers: [WAKER; 6], } } - pub trait Instance: crate::rcc::RccPeripheral { - fn regs() -> crate::pac::ipcc::Ipcc; - fn set_cpu2(enabled: bool); - fn state() -> &'static State; + const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { + match channel { + IpccChannel::Channel1 => &self.rx_wakers[0], + IpccChannel::Channel2 => &self.rx_wakers[1], + IpccChannel::Channel3 => &self.rx_wakers[2], + IpccChannel::Channel4 => &self.rx_wakers[3], + IpccChannel::Channel5 => &self.rx_wakers[4], + IpccChannel::Channel6 => &self.rx_wakers[5], + } + } + + const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { + match channel { + IpccChannel::Channel1 => &self.tx_wakers[0], + IpccChannel::Channel2 => &self.tx_wakers[1], + IpccChannel::Channel3 => &self.tx_wakers[2], + IpccChannel::Channel4 => &self.tx_wakers[3], + IpccChannel::Channel5 => &self.tx_wakers[4], + IpccChannel::Channel6 => &self.tx_wakers[5], + } } } + +trait SealedInstance: crate::rcc::RccPeripheral { + fn regs() -> crate::pac::ipcc::Ipcc; + fn set_cpu2(enabled: bool); + fn state() -> &'static State; +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 9e26a3513..6a3d1c463 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -158,7 +158,7 @@ pub(crate) use stm32_metapac as pac; use crate::interrupt::Priority; #[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; /// `embassy-stm32` global configuration. #[non_exhaustive] diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index cf531e266..a3b4352c0 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -81,8 +81,8 @@ impl<'d, T: Instance> OpAmp<'d, T> { /// [`OpAmpOutput`] is dropped. pub fn buffer_ext( &'d mut self, - in_pin: impl Peripheral

+ crate::gpio::sealed::Pin>, - out_pin: impl Peripheral

+ crate::gpio::sealed::Pin> + 'd, + in_pin: impl Peripheral

+ crate::gpio::Pin>, + out_pin: impl Peripheral

+ crate::gpio::Pin> + 'd, gain: OpAmpGain, ) -> OpAmpOutput<'d, T> { into_ref!(in_pin); @@ -122,7 +122,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { #[cfg(opamp_g4)] pub fn buffer_int( &'d mut self, - pin: impl Peripheral

+ crate::gpio::sealed::Pin>, + pin: impl Peripheral

+ crate::gpio::Pin>, gain: OpAmpGain, ) -> OpAmpInternalOutput<'d, T> { into_ref!(pin); @@ -166,37 +166,39 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { } } -/// Opamp instance trait. -pub trait Instance: sealed::Instance + 'static {} - -pub(crate) mod sealed { - pub trait Instance { - fn regs() -> crate::pac::opamp::Opamp; - } - - pub trait NonInvertingPin { - fn channel(&self) -> u8; - } - - pub trait InvertingPin { - fn channel(&self) -> u8; - } - - pub trait OutputPin {} +pub(crate) trait SealedInstance { + fn regs() -> crate::pac::opamp::Opamp; } +pub(crate) trait SealedNonInvertingPin { + fn channel(&self) -> u8; +} + +pub(crate) trait SealedInvertingPin { + #[allow(unused)] + fn channel(&self) -> u8; +} + +pub(crate) trait SealedOutputPin {} + +/// Opamp instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static {} /// Non-inverting pin trait. -pub trait NonInvertingPin: sealed::NonInvertingPin {} +#[allow(private_bounds)] +pub trait NonInvertingPin: SealedNonInvertingPin {} /// Inverting pin trait. -pub trait InvertingPin: sealed::InvertingPin {} +#[allow(private_bounds)] +pub trait InvertingPin: SealedInvertingPin {} /// Output pin trait. -pub trait OutputPin: sealed::OutputPin {} +#[allow(private_bounds)] +pub trait OutputPin: SealedOutputPin {} macro_rules! impl_opamp_external_output { ($inst:ident, $adc:ident, $ch:expr) => { foreach_adc!( ($adc, $common_inst:ident, $adc_clock:ident) => { - impl<'d> crate::adc::sealed::AdcPin + impl<'d> crate::adc::SealedAdcPin for OpAmpOutput<'d, crate::peripherals::$inst> { fn channel(&self) -> u8 { @@ -242,7 +244,7 @@ macro_rules! impl_opamp_internal_output { ($inst:ident, $adc:ident, $ch:expr) => { foreach_adc!( ($adc, $common_inst:ident, $adc_clock:ident) => { - impl<'d> crate::adc::sealed::AdcPin + impl<'d> crate::adc::SealedAdcPin for OpAmpInternalOutput<'d, crate::peripherals::$inst> { fn channel(&self) -> u8 { @@ -291,7 +293,7 @@ foreach_peripheral!( foreach_peripheral! { (opamp, $inst:ident) => { - impl sealed::Instance for crate::peripherals::$inst { + impl SealedInstance for crate::peripherals::$inst { fn regs() -> crate::pac::opamp::Opamp { crate::pac::$inst } @@ -306,7 +308,7 @@ foreach_peripheral! { macro_rules! impl_opamp_vp_pin { ($inst:ident, $pin:ident, $ch:expr) => { impl crate::opamp::NonInvertingPin for crate::peripherals::$pin {} - impl crate::opamp::sealed::NonInvertingPin for crate::peripherals::$pin { + impl crate::opamp::SealedNonInvertingPin for crate::peripherals::$pin { fn channel(&self) -> u8 { $ch } @@ -318,6 +320,6 @@ macro_rules! impl_opamp_vp_pin { macro_rules! impl_opamp_vout_pin { ($inst:ident, $pin:ident) => { impl crate::opamp::OutputPin for crate::peripherals::$pin {} - impl crate::opamp::sealed::OutputPin for crate::peripherals::$pin {} + impl crate::opamp::SealedOutputPin for crate::peripherals::$pin {} }; } diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 8a709a89e..3c054e666 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -8,8 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use enums::*; use crate::dma::Transfer; -use crate::gpio::sealed::AFType; -use crate::gpio::{AnyPin, Pull}; +use crate::gpio::{AFType, AnyPin, Pull}; use crate::pac::quadspi::Quadspi as Regs; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -381,16 +380,13 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { } } -pub(crate) mod sealed { - use super::*; - - pub trait Instance { - const REGS: Regs; - } +trait SealedInstance { + const REGS: Regs; } /// QSPI instance trait. -pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} pin_trait!(SckPin, Instance); pin_trait!(BK1D0Pin, Instance); @@ -409,7 +405,7 @@ dma_trait!(QuadDma, Instance); foreach_peripheral!( (quadspi, $inst:ident) => { - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { const REGS: Regs = crate::pac::$inst; } diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs index 19a8c8cb9..6f0d7b379 100644 --- a/embassy-stm32/src/rcc/hsi48.rs +++ b/embassy-stm32/src/rcc/hsi48.rs @@ -2,7 +2,7 @@ use crate::pac::crs::vals::Syncsrc; use crate::pac::{CRS, RCC}; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; use crate::time::Hertz; /// HSI48 speed diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index 654943bc1..d8604e07e 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -2,8 +2,7 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; -use crate::gpio::sealed::AFType; -use crate::gpio::Speed; +use crate::gpio::{AFType, Speed}; #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; #[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] @@ -19,23 +18,25 @@ pub enum McoPrescaler { DIV1, } -pub(crate) mod sealed { - pub trait McoInstance { - type Source; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler); - } -} +pub(crate) trait SealedMcoInstance {} -pub trait McoInstance: sealed::McoInstance + 'static {} +#[allow(private_bounds)] +pub trait McoInstance: SealedMcoInstance + 'static { + type Source; + + #[doc(hidden)] + unsafe fn _apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler); +} pin_trait!(McoPin, McoInstance); macro_rules! impl_peri { ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { - impl sealed::McoInstance for peripherals::$peri { + impl SealedMcoInstance for peripherals::$peri {} + impl McoInstance for peripherals::$peri { type Source = $source; - unsafe fn apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { + unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { #[cfg(not(any(stm32u5, stm32wba)))] let r = RCC.cfgr(); #[cfg(any(stm32u5, stm32wba))] @@ -48,8 +49,6 @@ macro_rules! impl_peri { }); } } - - impl McoInstance for peripherals::$peri {} }; } @@ -79,7 +78,7 @@ impl<'d, T: McoInstance> Mco<'d, T> { into_ref!(pin); critical_section::with(|_| unsafe { - T::apply_clock_settings(source, prescaler); + T::_apply_clock_settings(source, prescaler); pin.set_as_af(pin.af_num(), AFType::OutputPushPull); pin.set_speed(Speed::VeryHigh); }); diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 910ebe205..d53d02203 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -10,6 +10,7 @@ pub use bd::*; #[cfg(any(mco, mco1, mco2))] mod mco; +use critical_section::CriticalSection; #[cfg(any(mco, mco1, mco2))] pub use mco::*; @@ -32,6 +33,7 @@ mod _version; pub use _version::*; pub use crate::_generated::{mux, Clocks}; +use crate::time::Hertz; #[cfg(feature = "low-power")] /// Must be written within a critical section @@ -63,29 +65,21 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { CLOCK_FREQS.assume_init_ref() } -#[cfg(feature = "unstable-pac")] -pub mod low_level { - pub use super::sealed::*; -} +pub(crate) trait SealedRccPeripheral { + fn frequency() -> crate::time::Hertz; + fn enable_and_reset_with_cs(cs: CriticalSection); + fn disable_with_cs(cs: CriticalSection); -pub(crate) mod sealed { - use critical_section::CriticalSection; - - pub trait RccPeripheral { - fn frequency() -> crate::time::Hertz; - fn enable_and_reset_with_cs(cs: CriticalSection); - fn disable_with_cs(cs: CriticalSection); - - fn enable_and_reset() { - critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) - } - fn disable() { - critical_section::with(|cs| Self::disable_with_cs(cs)) - } + fn enable_and_reset() { + critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) + } + fn disable() { + critical_section::with(|cs| Self::disable_with_cs(cs)) } } -pub trait RccPeripheral: sealed::RccPeripheral + 'static {} +#[allow(private_bounds)] +pub trait RccPeripheral: SealedRccPeripheral + 'static {} #[allow(unused)] mod util { @@ -116,3 +110,12 @@ mod util { Ok(Some(x)) } } + +/// Get the kernel clocok frequency of the peripheral `T`. +/// +/// # Panics +/// +/// Panics if the clock is not active. +pub fn frequency() -> Hertz { + T::frequency() +} diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index ca641f352..7a228e4a4 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -222,16 +222,13 @@ impl<'d, T: Instance> RngCore for Rng<'d, T> { impl<'d, T: Instance> CryptoRng for Rng<'d, T> {} -pub(crate) mod sealed { - use super::*; - - pub trait Instance { - fn regs() -> pac::rng::Rng; - } +trait SealedInstance { + fn regs() -> pac::rng::Rng; } /// RNG instance trait. -pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { /// Interrupt for this RNG instance. type Interrupt: interrupt::typelevel::Interrupt; } @@ -242,7 +239,7 @@ foreach_interrupt!( type Interrupt = crate::interrupt::typelevel::$irq; } - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { fn regs() -> crate::pac::rng::Rng { crate::pac::$inst } diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index 2bad79923..bab8cf4a3 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -4,7 +4,7 @@ use chrono::{Datelike, NaiveDate, Timelike, Weekday}; #[cfg(any(feature = "defmt", feature = "time"))] use crate::peripherals::RTC; #[cfg(any(feature = "defmt", feature = "time"))] -use crate::rtc::sealed::Instance; +use crate::rtc::SealedInstance; /// Represents an instant in time that can be substracted to compute a duration pub struct RtcInstant { diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 169505501..00abe9356 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -31,7 +31,6 @@ pub use _version::*; use embassy_hal_internal::Peripheral; use crate::peripherals::RTC; -use crate::rtc::sealed::Instance; #[allow(dead_code)] #[repr(u8)] @@ -212,7 +211,7 @@ impl Rtc { /// Create a new RTC instance. pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] - ::enable_and_reset(); + ::enable_and_reset(); let mut this = Self { #[cfg(feature = "low-power")] @@ -437,7 +436,7 @@ impl Rtc { .fpr(0) .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - ::WakeupInterrupt::unpend(); + ::WakeupInterrupt::unpend(); }); } @@ -449,8 +448,8 @@ impl Rtc { use crate::interrupt::typelevel::Interrupt; use crate::pac::EXTI; - ::WakeupInterrupt::unpend(); - unsafe { ::WakeupInterrupt::enable() }; + ::WakeupInterrupt::unpend(); + unsafe { ::WakeupInterrupt::enable() }; EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); @@ -477,34 +476,30 @@ pub(crate) fn bcd2_to_byte(bcd: (u8, u8)) -> u8 { tmp + (value & 0x0F) } -pub(crate) mod sealed { - use crate::pac::rtc::Rtc; +trait SealedInstance { + const BACKUP_REGISTER_COUNT: usize; - pub trait Instance { - const BACKUP_REGISTER_COUNT: usize; + #[cfg(feature = "low-power")] + const EXTI_WAKEUP_LINE: usize; - #[cfg(feature = "low-power")] - const EXTI_WAKEUP_LINE: usize; + #[cfg(feature = "low-power")] + type WakeupInterrupt: crate::interrupt::typelevel::Interrupt; - #[cfg(feature = "low-power")] - type WakeupInterrupt: crate::interrupt::typelevel::Interrupt; - - fn regs() -> Rtc { - crate::pac::RTC - } - - /// Read content of the backup register. - /// - /// The registers retain their values during wakes from standby mode or system resets. They also - /// retain their value when Vdd is switched off as long as V_BAT is powered. - fn read_backup_register(rtc: &Rtc, register: usize) -> Option; - - /// Set content of the backup register. - /// - /// The registers retain their values during wakes from standby mode or system resets. They also - /// retain their value when Vdd is switched off as long as V_BAT is powered. - fn write_backup_register(rtc: &Rtc, register: usize, value: u32); - - // fn apply_config(&mut self, rtc_config: RtcConfig); + fn regs() -> crate::pac::rtc::Rtc { + crate::pac::RTC } + + /// Read content of the backup register. + /// + /// The registers retain their values during wakes from standby mode or system resets. They also + /// retain their value when Vdd is switched off as long as V_BAT is powered. + fn read_backup_register(rtc: &crate::pac::rtc::Rtc, register: usize) -> Option; + + /// Set content of the backup register. + /// + /// The registers retain their values during wakes from standby mode or system resets. They also + /// retain their value when Vdd is switched off as long as V_BAT is powered. + fn write_backup_register(rtc: &crate::pac::rtc::Rtc, register: usize, value: u32); + + // fn apply_config(&mut self, rtc_config: RtcConfig); } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 1eda097a7..92f9de846 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,9 +1,8 @@ use stm32_metapac::rtc::vals::{Osel, Pol}; -use super::sealed; +use super::SealedInstance; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; -use crate::rtc::sealed::Instance; #[allow(dead_code)] impl super::Rtc { @@ -126,7 +125,7 @@ impl super::Rtc { } } -impl sealed::Instance for crate::peripherals::RTC { +impl SealedInstance for crate::peripherals::RTC { const BACKUP_REGISTER_COUNT: usize = 20; #[cfg(all(feature = "low-power", stm32f4))] diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 3d44a52ff..8a78d16e1 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,9 +1,9 @@ use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; -use super::{sealed, RtcCalibrationCyclePeriod}; +use super::RtcCalibrationCyclePeriod; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; -use crate::rtc::sealed::Instance; +use crate::rtc::SealedInstance; impl super::Rtc { /// Applies the RTC config @@ -126,7 +126,7 @@ impl super::Rtc { } } -impl sealed::Instance for crate::peripherals::RTC { +impl SealedInstance for crate::peripherals::RTC { const BACKUP_REGISTER_COUNT: usize = 32; #[cfg(all(feature = "low-power", stm32g4))] diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 294620031..54dd81524 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -6,12 +6,10 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; -use self::sealed::WhichSubBlock; pub use crate::dma::word; #[cfg(not(gpdma))] use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; -use crate::gpio::sealed::{AFType, Pin as _}; -use crate::gpio::AnyPin; +use crate::gpio::{AFType, AnyPin, SealedPin as _}; use crate::pac::sai::{vals, Sai as Regs}; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -1041,43 +1039,42 @@ impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> { } } -pub(crate) mod sealed { - use super::*; +trait SealedInstance { + const REGS: Regs; +} - pub trait Instance { - const REGS: Regs; - } +#[derive(Copy, Clone)] +enum WhichSubBlock { + A = 0, + B = 1, +} - #[derive(Copy, Clone)] - pub enum WhichSubBlock { - A = 0, - B = 1, - } - - pub trait SubBlock { - const WHICH: WhichSubBlock; - } +trait SealedSubBlock { + const WHICH: WhichSubBlock; } /// Sub-block instance trait. -pub trait SubBlockInstance: sealed::SubBlock {} +#[allow(private_bounds)] +pub trait SubBlockInstance: SealedSubBlock {} /// Sub-block A. pub enum A {} -impl sealed::SubBlock for A { +impl SealedSubBlock for A { const WHICH: WhichSubBlock = WhichSubBlock::A; } impl SubBlockInstance for A {} /// Sub-block B. pub enum B {} -impl sealed::SubBlock for B { +impl SealedSubBlock for B { const WHICH: WhichSubBlock = WhichSubBlock::B; } impl SubBlockInstance for B {} /// SAI instance trait. -pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} + pin_trait!(SckPin, Instance, SubBlockInstance); pin_trait!(FsPin, Instance, SubBlockInstance); pin_trait!(SdPin, Instance, SubBlockInstance); @@ -1087,7 +1084,7 @@ dma_trait!(Dma, Instance, SubBlockInstance); foreach_peripheral!( (sai, $inst:ident) => { - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { const REGS: Regs = crate::pac::$inst; } diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index c0b3a2183..f79a11606 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -13,8 +13,7 @@ use embassy_sync::waitqueue::AtomicWaker; use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; use crate::dma::NoDma; -use crate::gpio::sealed::{AFType, Pin}; -use crate::gpio::{AnyPin, Pull, Speed}; +use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::pac::sdmmc::Sdmmc as RegBlock; use crate::rcc::RccPeripheral; @@ -1418,19 +1417,17 @@ impl Cmd { ////////////////////////////////////////////////////// -pub(crate) mod sealed { - use super::*; - - pub trait Instance { - type Interrupt: interrupt::typelevel::Interrupt; - - fn regs() -> RegBlock; - fn state() -> &'static AtomicWaker; - } +trait SealedInstance { + fn regs() -> RegBlock; + fn state() -> &'static AtomicWaker; } /// SDMMC instance trait. -pub trait Instance: sealed::Instance + RccPeripheral + 'static {} +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + 'static { + /// Interrupt for this instance. + type Interrupt: interrupt::typelevel::Interrupt; +} pin_trait!(CkPin, Instance); pin_trait!(CmdPin, Instance); @@ -1457,9 +1454,7 @@ impl SdmmcDma for NoDma {} foreach_peripheral!( (sdmmc, $inst:ident) => { - impl sealed::Instance for peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$inst; - + impl SealedInstance for peripherals::$inst { fn regs() -> RegBlock { crate::pac::$inst } @@ -1470,6 +1465,8 @@ foreach_peripheral!( } } - impl Instance for peripherals::$inst {} + impl Instance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$inst; + } }; ); diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index b517f640a..0b38c4288 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -9,8 +9,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::dma::{slice_ptr_parts, word, Transfer}; -use crate::gpio::sealed::{AFType, Pin as _}; -use crate::gpio::{AnyPin, Pull}; +use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; use crate::pac::spi::{regs, vals, Spi as Regs}; use crate::rcc::RccPeripheral; use crate::time::Hertz; @@ -210,7 +209,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { // see RM0453 rev 1 section 7.2.13 page 291 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz. - let pclk3_freq = ::frequency().0; + let pclk3_freq = ::frequency().0; let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000)); let mut config = Config::default(); config.mode = MODE_0; @@ -271,13 +270,13 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { if mosi.is_none() { w.set_rxonly(vals::Rxonly::OUTPUTDISABLED); } - w.set_dff(::CONFIG) + w.set_dff(::CONFIG) }); } #[cfg(spi_v2)] { T::REGS.cr2().modify(|w| { - let (ds, frxth) = ::CONFIG; + let (ds, frxth) = ::CONFIG; w.set_frxth(frxth); w.set_ds(ds); w.set_ssoe(false); @@ -317,7 +316,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { T::REGS.cfg1().modify(|w| { w.set_crcen(false); w.set_mbr(br); - w.set_dsize(::CONFIG); + w.set_dsize(::CONFIG); w.set_fthlv(vals::Fthlv::ONEFRAME); }); T::REGS.cr2().modify(|w| { @@ -336,7 +335,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { miso, txdma, rxdma, - current_word_size: ::CONFIG, + current_word_size: ::CONFIG, } } @@ -975,24 +974,21 @@ impl<'d, T: Instance, Tx: TxDma, Rx: RxDma, W: Word> embedded_hal_async::s } } -pub(crate) mod sealed { - use super::*; +pub(crate) trait SealedInstance { + const REGS: Regs; +} - pub trait Instance { - const REGS: Regs; - } - - pub trait Word { - const CONFIG: word_impl::Config; - } +trait SealedWord { + const CONFIG: word_impl::Config; } /// Word sizes usable for SPI. -pub trait Word: word::Word + sealed::Word {} +#[allow(private_bounds)] +pub trait Word: word::Word + SealedWord {} macro_rules! impl_word { ($T:ty, $config:expr) => { - impl sealed::Word for $T { + impl SealedWord for $T { const CONFIG: Config = $config; } impl Word for $T {} @@ -1068,7 +1064,8 @@ mod word_impl { } /// SPI instance trait. -pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} pin_trait!(SckPin, Instance); pin_trait!(MosiPin, Instance); @@ -1082,7 +1079,7 @@ dma_trait!(TxDma, Instance); foreach_peripheral!( (spi, $inst:ident) => { - impl sealed::Instance for peripherals::$inst { + impl SealedInstance for peripherals::$inst { const REGS: Regs = crate::pac::$inst; } diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index c961fc14b..cc8161276 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -12,7 +12,7 @@ use stm32_metapac::timer::{regs, TimGp16}; use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; #[cfg(feature = "low-power")] use crate::rtc::Rtc; #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] @@ -277,7 +277,7 @@ impl RtcDriver { fn init(&'static self, cs: critical_section::CriticalSection) { let r = regs_gp16(); - ::enable_and_reset_with_cs(cs); + ::enable_and_reset_with_cs(cs); let timer_freq = T::frequency(); diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index b6ab939cc..ab9879be6 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -7,8 +7,7 @@ use stm32_metapac::timer::vals; use super::low_level::Timer; use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; -use crate::gpio::sealed::AFType; -use crate::gpio::AnyPin; +use crate::gpio::{AFType, AnyPin}; use crate::Peripheral; /// Counting direction diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 9c37d2c04..fe614b811 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -16,11 +16,12 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::Ordering; +use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; use crate::interrupt; @@ -555,50 +556,47 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -/// UCPD instance trait. -pub trait Instance: sealed::Instance + RccPeripheral {} +struct State { + waker: AtomicWaker, + // Inverted logic for a default state of 0 so that the data goes into the .bss section. + drop_not_ready: AtomicBool, +} -mod sealed { - use core::sync::atomic::AtomicBool; - - use embassy_sync::waitqueue::AtomicWaker; - - pub struct State { - pub waker: AtomicWaker, - // Inverted logic for a default state of 0 so that the data goes into the .bss section. - pub drop_not_ready: AtomicBool, - } - - impl State { - pub const fn new() -> Self { - Self { - waker: AtomicWaker::new(), - drop_not_ready: AtomicBool::new(false), - } +impl State { + pub const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + drop_not_ready: AtomicBool::new(false), } } +} - pub trait Instance { - type Interrupt: crate::interrupt::typelevel::Interrupt; - const REGS: crate::pac::ucpd::Ucpd; - fn state() -> &'static crate::ucpd::sealed::State; - } +trait SealedInstance { + const REGS: crate::pac::ucpd::Ucpd; + fn state() -> &'static State; +} + +/// UCPD instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral { + /// Interrupt for this instance. + type Interrupt: crate::interrupt::typelevel::Interrupt; } foreach_interrupt!( ($inst:ident, ucpd, UCPD, GLOBAL, $irq:ident) => { - impl sealed::Instance for crate::peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$irq; - + impl SealedInstance for crate::peripherals::$inst { const REGS: crate::pac::ucpd::Ucpd = crate::pac::$inst; - fn state() -> &'static crate::ucpd::sealed::State { - static STATE: crate::ucpd::sealed::State = crate::ucpd::sealed::State::new(); + fn state() -> &'static State { + static STATE: State = State::new(); &STATE } } - impl Instance for crate::peripherals::$inst {} + impl Instance for crate::peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } }; ); diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index ea727b010..7ab33043a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -10,10 +10,11 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; use futures::future::{select, Either}; use crate::dma::{NoDma, Transfer}; -use crate::gpio::sealed::AFType; +use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; #[allow(unused_imports)] #[cfg(not(any(usart_v1, usart_v2)))] @@ -1326,8 +1327,6 @@ mod ringbuffered; #[cfg(not(gpdma))] pub use ringbuffered::RingBufferedUartRx; -use self::sealed::Kind; - #[cfg(any(usart_v1, usart_v2))] fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { r.dr().as_ptr() as _ @@ -1370,52 +1369,50 @@ fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { r.icr().write(|w| *w = regs::Icr(sr.0)); } -pub(crate) mod sealed { - use embassy_sync::waitqueue::AtomicWaker; +#[derive(Clone, Copy, PartialEq, Eq)] +enum Kind { + Uart, + #[cfg(any(usart_v3, usart_v4))] + #[allow(unused)] + Lpuart, +} - use super::*; +struct State { + rx_waker: AtomicWaker, +} - #[derive(Clone, Copy, PartialEq, Eq)] - pub enum Kind { - Uart, - #[cfg(any(usart_v3, usart_v4))] - Lpuart, - } - - pub struct State { - pub rx_waker: AtomicWaker, - pub tx_waker: AtomicWaker, - } - - impl State { - pub const fn new() -> Self { - Self { - rx_waker: AtomicWaker::new(), - tx_waker: AtomicWaker::new(), - } +impl State { + const fn new() -> Self { + Self { + rx_waker: AtomicWaker::new(), } } - - pub trait BasicInstance: crate::rcc::RccPeripheral { - const KIND: Kind; - type Interrupt: interrupt::typelevel::Interrupt; - - fn regs() -> Regs; - fn state() -> &'static State; - - fn buffered_state() -> &'static buffered::State; - } - - pub trait FullInstance: BasicInstance { - fn regs_uart() -> crate::pac::usart::Usart; - } +} + +trait SealedBasicInstance: crate::rcc::RccPeripheral { + const KIND: Kind; + + fn regs() -> Regs; + fn state() -> &'static State; + + fn buffered_state() -> &'static buffered::State; +} + +trait SealedFullInstance: SealedBasicInstance { + #[allow(unused)] + fn regs_uart() -> crate::pac::usart::Usart; } /// Basic UART driver instance -pub trait BasicInstance: Peripheral

+ sealed::BasicInstance + 'static + Send {} +#[allow(private_bounds)] +pub trait BasicInstance: Peripheral

+ SealedBasicInstance + 'static + Send { + /// Interrupt for this instance. + type Interrupt: interrupt::typelevel::Interrupt; +} /// Full UART driver instance -pub trait FullInstance: sealed::FullInstance {} +#[allow(private_bounds)] +pub trait FullInstance: SealedFullInstance {} pin_trait!(RxPin, BasicInstance); pin_trait!(TxPin, BasicInstance); @@ -1429,16 +1426,15 @@ dma_trait!(RxDma, BasicInstance); macro_rules! impl_usart { ($inst:ident, $irq:ident, $kind:expr) => { - impl sealed::BasicInstance for crate::peripherals::$inst { + impl SealedBasicInstance for crate::peripherals::$inst { const KIND: Kind = $kind; - type Interrupt = crate::interrupt::typelevel::$irq; fn regs() -> Regs { unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) } } - fn state() -> &'static crate::usart::sealed::State { - static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new(); + fn state() -> &'static crate::usart::State { + static STATE: crate::usart::State = crate::usart::State::new(); &STATE } @@ -1448,7 +1444,9 @@ macro_rules! impl_usart { } } - impl BasicInstance for peripherals::$inst {} + impl BasicInstance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } }; } @@ -1460,7 +1458,7 @@ foreach_interrupt!( ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => { impl_usart!($inst, $irq, Kind::Uart); - impl sealed::FullInstance for peripherals::$inst { + impl SealedFullInstance for peripherals::$inst { fn regs_uart() -> crate::pac::usart::Usart { crate::pac::$inst } diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 788f61f16..1e3c44167 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -6,7 +6,7 @@ mod _version; pub use _version::*; use crate::interrupt::typelevel::Interrupt; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::SealedRccPeripheral; /// clock, power initialization stuff that's common for USB and OTG. fn common_init() { @@ -65,5 +65,5 @@ fn common_init() { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - ::enable_and_reset(); + ::enable_and_reset(); } diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index d4095b466..b0e7067bd 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -11,11 +11,11 @@ use embassy_usb_driver::{ }; use futures::future::poll_fn; -use crate::gpio::sealed::AFType; +use crate::gpio::AFType; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::otg::{regs, vals}; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::{RccPeripheral, SealedRccPeripheral}; use crate::time::Hertz; /// Interrupt handler. @@ -809,7 +809,7 @@ impl<'d, T: Instance> Bus<'d, T> { fn disable(&mut self) { T::Interrupt::disable(); - ::disable(); + ::disable(); #[cfg(stm32l4)] crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); @@ -1436,19 +1436,18 @@ fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool { // Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps const MAX_EP_COUNT: usize = 9; -pub(crate) mod sealed { - pub trait Instance { - const HIGH_SPEED: bool; - const FIFO_DEPTH_WORDS: u16; - const ENDPOINT_COUNT: usize; +trait SealedInstance { + const HIGH_SPEED: bool; + const FIFO_DEPTH_WORDS: u16; + const ENDPOINT_COUNT: usize; - fn regs() -> crate::pac::otg::Otg; - fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>; - } + fn regs() -> crate::pac::otg::Otg; + fn state() -> &'static super::State<{ MAX_EP_COUNT }>; } /// USB instance trait. -pub trait Instance: sealed::Instance + RccPeripheral + 'static { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + 'static { /// Interrupt for this USB instance. type Interrupt: interrupt::typelevel::Interrupt; } @@ -1473,7 +1472,7 @@ pin_trait!(UlpiD7Pin, Instance); foreach_interrupt!( (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => { - impl sealed::Instance for crate::peripherals::USB_OTG_FS { + impl SealedInstance for crate::peripherals::USB_OTG_FS { const HIGH_SPEED: bool = false; cfg_if::cfg_if! { @@ -1538,7 +1537,7 @@ foreach_interrupt!( }; (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => { - impl sealed::Instance for crate::peripherals::USB_OTG_HS { + impl SealedInstance for crate::peripherals::USB_OTG_HS { const HIGH_SPEED: bool = true; cfg_if::cfg_if! { diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index c4f9140da..f48808cb3 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -15,7 +15,7 @@ use embassy_usb_driver::{ use crate::pac::usb::regs; use crate::pac::usb::vals::{EpType, Stat}; use crate::pac::USBRAM; -use crate::rcc::sealed::RccPeripheral; +use crate::rcc::RccPeripheral; use crate::{interrupt, Peripheral}; /// Interrupt handler. @@ -277,8 +277,8 @@ impl<'d, T: Instance> Driver<'d, T> { #[cfg(not(stm32l1))] { - dp.set_as_af(dp.af_num(), crate::gpio::sealed::AFType::OutputPushPull); - dm.set_as_af(dm.af_num(), crate::gpio::sealed::AFType::OutputPushPull); + dp.set_as_af(dp.af_num(), crate::gpio::AFType::OutputPushPull); + dm.set_as_af(dm.af_num(), crate::gpio::AFType::OutputPushPull); } #[cfg(stm32l1)] let _ = (dp, dm); // suppress "unused" warnings. @@ -1037,14 +1037,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { } } -pub(crate) mod sealed { - pub trait Instance { - fn regs() -> crate::pac::usb::Usb; - } +trait SealedInstance { + fn regs() -> crate::pac::usb::Usb; } /// USB instance trait. -pub trait Instance: sealed::Instance + RccPeripheral + 'static { +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + 'static { /// Interrupt for this USB instance. type Interrupt: interrupt::typelevel::Interrupt; } @@ -1055,7 +1054,7 @@ pin_trait!(DmPin, Instance); foreach_interrupt!( ($inst:ident, usb, $block:ident, LP, $irq:ident) => { - impl sealed::Instance for crate::peripherals::$inst { + impl SealedInstance for crate::peripherals::$inst { fn regs() -> crate::pac::usb::Usb { crate::pac::$inst } diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 2ff0db09e..ab21c4b6b 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -80,18 +80,17 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { } } -mod sealed { - pub trait Instance { - fn regs() -> crate::pac::iwdg::Iwdg; - } +trait SealedInstance { + fn regs() -> crate::pac::iwdg::Iwdg; } /// IWDG instance trait. -pub trait Instance: sealed::Instance {} +#[allow(private_bounds)] +pub trait Instance: SealedInstance {} foreach_peripheral!( (iwdg, $inst:ident) => { - impl sealed::Instance for crate::peripherals::$inst { + impl SealedInstance for crate::peripherals::$inst { fn regs() -> crate::pac::iwdg::Iwdg { crate::pac::$inst } diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index c45747f35..3a9887e3c 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; use embassy_stm32::pac::timer::vals::Mms; use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; -use embassy_stm32::rcc::low_level::RccPeripheral; +use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; use micromath::F32Ext; @@ -59,11 +59,11 @@ async fn main(spawner: Spawner) { async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { let data: &[u8; 256] = &calculate_array::<256>(); - info!("TIM6 frequency is {}", TIM6::frequency()); + info!("TIM6 frequency is {}", frequency::()); const FREQUENCY: Hertz = Hertz::hz(200); // Compute the reload value such that we obtain the FREQUENCY for the sine - let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; + let reload: u32 = (frequency::().0 / FREQUENCY.0) / data.len() as u32; // Depends on your clock and on the specific chip used, you may need higher or lower values here if reload < 10 { @@ -84,7 +84,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { debug!( "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", - TIM6::frequency(), + frequency::(), FREQUENCY, reload, reload as u16, @@ -102,10 +102,10 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { let data: &[u8; 256] = &calculate_array::<256>(); - info!("TIM7 frequency is {}", TIM7::frequency()); + info!("TIM7 frequency is {}", frequency::()); const FREQUENCY: Hertz = Hertz::hz(600); - let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; + let reload: u32 = (frequency::().0 / FREQUENCY.0) / data.len() as u32; if reload < 10 { error!("Reload value {} below threshold!", reload); @@ -125,7 +125,7 @@ async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { debug!( "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", - TIM7::frequency(), + frequency::(), FREQUENCY, reload, reload as u16, diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 780fbc6f0..a95b44b74 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -3,8 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::low_level::AFType; -use embassy_stm32::gpio::Speed; +use embassy_stm32::gpio::{AFType, Flex, Pull, Speed}; use embassy_stm32::time::{khz, Hertz}; use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel}; @@ -59,6 +58,10 @@ async fn main(_spawner: Spawner) { } pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> { tim: LLTimer<'d, T>, + _ch1: Flex<'d>, + _ch2: Flex<'d>, + _ch3: Flex<'d>, + _ch4: Flex<'d>, } impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { @@ -72,16 +75,26 @@ impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { ) -> Self { into_ref!(ch1, ch2, ch3, ch4); - ch1.set_speed(Speed::VeryHigh); - ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); - ch2.set_speed(Speed::VeryHigh); - ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); - ch3.set_speed(Speed::VeryHigh); - ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); - ch4.set_speed(Speed::VeryHigh); - ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); + let af1 = ch1.af_num(); + let af2 = ch2.af_num(); + let af3 = ch3.af_num(); + let af4 = ch4.af_num(); + let mut ch1 = Flex::new(ch1); + let mut ch2 = Flex::new(ch2); + let mut ch3 = Flex::new(ch3); + let mut ch4 = Flex::new(ch4); + ch1.set_as_af_unchecked(af1, AFType::OutputPushPull, Pull::None, Speed::VeryHigh); + ch2.set_as_af_unchecked(af2, AFType::OutputPushPull, Pull::None, Speed::VeryHigh); + ch3.set_as_af_unchecked(af3, AFType::OutputPushPull, Pull::None, Speed::VeryHigh); + ch4.set_as_af_unchecked(af4, AFType::OutputPushPull, Pull::None, Speed::VeryHigh); - let mut this = Self { tim: LLTimer::new(tim) }; + let mut this = Self { + tim: LLTimer::new(tim), + _ch1: ch1, + _ch2: ch2, + _ch3: ch3, + _ch4: ch4, + }; this.set_frequency(freq); this.tim.start(); diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index 98edd39c0..d01b016c0 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; use embassy_stm32::pac::timer::vals::Mms; use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; -use embassy_stm32::rcc::low_level::RccPeripheral; +use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; use micromath::F32Ext; @@ -30,11 +30,11 @@ async fn main(spawner: Spawner) { async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { let data: &[u8; 256] = &calculate_array::<256>(); - info!("TIM6 frequency is {}", TIM6::frequency()); + info!("TIM6 frequency is {}", frequency::()); const FREQUENCY: Hertz = Hertz::hz(200); // Compute the reload value such that we obtain the FREQUENCY for the sine - let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; + let reload: u32 = (frequency::().0 / FREQUENCY.0) / data.len() as u32; // Depends on your clock and on the specific chip used, you may need higher or lower values here if reload < 10 { @@ -55,7 +55,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { debug!( "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", - TIM6::frequency(), + frequency::(), FREQUENCY, reload, reload as u16, @@ -73,10 +73,10 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { let data: &[u8; 256] = &calculate_array::<256>(); - info!("TIM7 frequency is {}", TIM7::frequency()); + info!("TIM7 frequency is {}", frequency::()); const FREQUENCY: Hertz = Hertz::hz(600); - let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; + let reload: u32 = (frequency::().0 / FREQUENCY.0) / data.len() as u32; if reload < 10 { error!("Reload value {} below threshold!", reload); @@ -96,7 +96,7 @@ async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { debug!( "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", - TIM7::frequency(), + frequency::(), FREQUENCY, reload, reload as u16, From 4aa4ea99c2c860d3c3012fee55db9b824d2ad2ef Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Mar 2024 01:44:46 +0100 Subject: [PATCH 738/760] use private_bounds for sealed traits. --- embassy-hal-internal/src/interrupt.rs | 8 ++-- embassy-net-wiznet/src/chip/mod.rs | 63 ++++++++++++--------------- embassy-net-wiznet/src/chip/w5100s.rs | 2 +- embassy-net-wiznet/src/chip/w5500.rs | 2 +- embassy-usb/src/msos.rs | 28 +++++------- 5 files changed, 44 insertions(+), 59 deletions(-) diff --git a/embassy-hal-internal/src/interrupt.rs b/embassy-hal-internal/src/interrupt.rs index 19dabcf6f..5e64dce9d 100644 --- a/embassy-hal-internal/src/interrupt.rs +++ b/embassy-hal-internal/src/interrupt.rs @@ -30,14 +30,12 @@ macro_rules! interrupt_mod { pub mod typelevel { use super::InterruptExt; - mod sealed { - pub trait Interrupt {} - } + trait SealedInterrupt {} /// Type-level interrupt. /// /// This trait is implemented for all typelevel interrupt types in this module. - pub trait Interrupt: sealed::Interrupt { + pub trait Interrupt: SealedInterrupt { /// Interrupt enum variant. /// @@ -105,7 +103,7 @@ macro_rules! interrupt_mod { #[doc=stringify!($irqs)] #[doc=" typelevel interrupt."] pub enum $irqs {} - impl sealed::Interrupt for $irqs{} + impl SealedInterrupt for $irqs{} impl Interrupt for $irqs { const IRQ: super::Interrupt = super::Interrupt::$irqs; } diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs index b987c2b36..e1f963d95 100644 --- a/embassy-net-wiznet/src/chip/mod.rs +++ b/embassy-net-wiznet/src/chip/mod.rs @@ -2,49 +2,40 @@ mod w5500; pub use w5500::W5500; mod w5100s; +use embedded_hal_async::spi::SpiDevice; pub use w5100s::W5100S; -pub(crate) mod sealed { - use embedded_hal_async::spi::SpiDevice; +pub(crate) trait SealedChip { + type Address; - pub trait Chip { - type Address; + const COMMON_MODE: Self::Address; + const COMMON_MAC: Self::Address; + const COMMON_SOCKET_INTR: Self::Address; + const COMMON_PHY_CFG: Self::Address; + const SOCKET_MODE: Self::Address; + const SOCKET_COMMAND: Self::Address; + const SOCKET_RXBUF_SIZE: Self::Address; + const SOCKET_TXBUF_SIZE: Self::Address; + const SOCKET_TX_FREE_SIZE: Self::Address; + const SOCKET_TX_DATA_WRITE_PTR: Self::Address; + const SOCKET_RECVD_SIZE: Self::Address; + const SOCKET_RX_DATA_READ_PTR: Self::Address; + const SOCKET_INTR_MASK: Self::Address; + const SOCKET_INTR: Self::Address; - const COMMON_MODE: Self::Address; - const COMMON_MAC: Self::Address; - const COMMON_SOCKET_INTR: Self::Address; - const COMMON_PHY_CFG: Self::Address; - const SOCKET_MODE: Self::Address; - const SOCKET_COMMAND: Self::Address; - const SOCKET_RXBUF_SIZE: Self::Address; - const SOCKET_TXBUF_SIZE: Self::Address; - const SOCKET_TX_FREE_SIZE: Self::Address; - const SOCKET_TX_DATA_WRITE_PTR: Self::Address; - const SOCKET_RECVD_SIZE: Self::Address; - const SOCKET_RX_DATA_READ_PTR: Self::Address; - const SOCKET_INTR_MASK: Self::Address; - const SOCKET_INTR: Self::Address; + const SOCKET_MODE_VALUE: u8; - const SOCKET_MODE_VALUE: u8; + const BUF_SIZE: u16; + const AUTO_WRAP: bool; - const BUF_SIZE: u16; - const AUTO_WRAP: bool; + fn rx_addr(addr: u16) -> Self::Address; + fn tx_addr(addr: u16) -> Self::Address; - fn rx_addr(addr: u16) -> Self::Address; - fn tx_addr(addr: u16) -> Self::Address; - - async fn bus_read( - spi: &mut SPI, - address: Self::Address, - data: &mut [u8], - ) -> Result<(), SPI::Error>; - async fn bus_write( - spi: &mut SPI, - address: Self::Address, - data: &[u8], - ) -> Result<(), SPI::Error>; - } + async fn bus_read(spi: &mut SPI, address: Self::Address, data: &mut [u8]) + -> Result<(), SPI::Error>; + async fn bus_write(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error>; } /// Trait for Wiznet chips. -pub trait Chip: sealed::Chip {} +#[allow(private_bounds)] +pub trait Chip: SealedChip {} diff --git a/embassy-net-wiznet/src/chip/w5100s.rs b/embassy-net-wiznet/src/chip/w5100s.rs index 7d328bce5..23ce3ed83 100644 --- a/embassy-net-wiznet/src/chip/w5100s.rs +++ b/embassy-net-wiznet/src/chip/w5100s.rs @@ -8,7 +8,7 @@ const RX_BASE: u16 = 0x6000; pub enum W5100S {} impl super::Chip for W5100S {} -impl super::sealed::Chip for W5100S { +impl super::SealedChip for W5100S { type Address = u16; const COMMON_MODE: Self::Address = 0x00; diff --git a/embassy-net-wiznet/src/chip/w5500.rs b/embassy-net-wiznet/src/chip/w5500.rs index 16236126d..12e610ea2 100644 --- a/embassy-net-wiznet/src/chip/w5500.rs +++ b/embassy-net-wiznet/src/chip/w5500.rs @@ -12,7 +12,7 @@ pub enum RegisterBlock { pub enum W5500 {} impl super::Chip for W5500 {} -impl super::sealed::Chip for W5500 { +impl super::SealedChip for W5500 { type Address = (RegisterBlock, u16); const COMMON_MODE: Self::Address = (RegisterBlock::Common, 0x00); diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs index a285a3ccd..25936d084 100644 --- a/embassy-usb/src/msos.rs +++ b/embassy-usb/src/msos.rs @@ -226,27 +226,21 @@ pub mod windows_version { pub const WIN10: u32 = 0x0A000000; } -mod sealed { - use core::mem::size_of; +/// A trait for descriptors +trait Descriptor: Sized { + const TYPE: DescriptorType; - /// A trait for descriptors - pub trait Descriptor: Sized { - const TYPE: super::DescriptorType; - - /// The size of the descriptor's header. - fn size(&self) -> usize { - size_of::() - } - - fn write_to(&self, buf: &mut [u8]); + /// The size of the descriptor's header. + fn size(&self) -> usize { + size_of::() } - pub trait DescriptorSet: Descriptor { - const LENGTH_OFFSET: usize; - } + fn write_to(&self, buf: &mut [u8]); } -use sealed::*; +trait DescriptorSet: Descriptor { + const LENGTH_OFFSET: usize; +} /// Copies the data of `t` into `buf`. /// @@ -412,9 +406,11 @@ impl DescriptorSet for FunctionSubsetHeader { // Feature Descriptors /// A marker trait for feature descriptors that are valid at the device level. +#[allow(private_bounds)] pub trait DeviceLevelDescriptor: Descriptor {} /// A marker trait for feature descriptors that are valid at the function level. +#[allow(private_bounds)] pub trait FunctionLevelDescriptor: Descriptor {} /// Table 13. Microsoft OS 2.0 compatible ID descriptor. From 8f1bed3d956c1e2fae2ab11b292c8fe73c7b6a2b Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sat, 23 Mar 2024 12:21:13 -0400 Subject: [PATCH 739/760] Allow changing Spi/I2cDeviceWithConfig's config at runtime --- embassy-embedded-hal/src/shared_bus/asynch/i2c.rs | 5 +++++ embassy-embedded-hal/src/shared_bus/asynch/spi.rs | 5 +++++ embassy-embedded-hal/src/shared_bus/blocking/i2c.rs | 5 +++++ embassy-embedded-hal/src/shared_bus/blocking/spi.rs | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs index 779c04263..71ce09def 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs @@ -106,6 +106,11 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> { pub fn new(bus: &'a Mutex, config: BUS::Config) -> Self { Self { bus, config } } + + /// Change the device's config at runtime + pub fn set_config(&mut self, config: BUS::Config) { + self.config = config; + } } impl<'a, M, BUS> i2c::ErrorType for I2cDeviceWithConfig<'a, M, BUS> diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs index 62b2c92a0..9890f218d 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs @@ -122,6 +122,11 @@ impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiDeviceWithConfig<'a, M, BUS, CS> { pub fn new(bus: &'a Mutex, cs: CS, config: BUS::Config) -> Self { Self { bus, cs, config } } + + /// Change the device's config at runtime + pub fn set_config(&mut self, config: BUS::Config) { + self.config = config; + } } impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS> diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index 1b08cb28e..627767c8a 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -132,6 +132,11 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> { pub fn new(bus: &'a Mutex>, config: BUS::Config) -> Self { Self { bus, config } } + + /// Change the device's config at runtime + pub fn set_config(&mut self, config: BUS::Config) { + self.config = config; + } } impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS> diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs index 59b65bfbd..801899f9f 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs @@ -147,6 +147,11 @@ impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiDeviceWithConfig<'a, M, BUS, CS> { pub fn new(bus: &'a Mutex>, cs: CS, config: BUS::Config) -> Self { Self { bus, cs, config } } + + /// Change the device's config at runtime + pub fn set_config(&mut self, config: BUS::Config) { + self.config = config; + } } impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS> From 9bc00e68fac8f41983ec64becc45648d4a05919c Mon Sep 17 00:00:00 2001 From: ZhangYong Date: Sun, 24 Mar 2024 18:25:04 +0800 Subject: [PATCH 740/760] update comments use 4/5/6 as new firmware for better understanding --- embassy-boot/src/boot_loader.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index ca1a1b10c..a38558056 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -183,29 +183,29 @@ impl BootLoader BootLoader Result { // Ensure we have enough progress pages to store copy progress From e139a4e076b2f61ddf0cdfa2ed5484ecb327afad Mon Sep 17 00:00:00 2001 From: Rafael Bachmann Date: Mon, 25 Mar 2024 15:09:41 +0100 Subject: [PATCH 741/760] fix: CI --- embassy-rp/src/clocks.rs | 2 ++ embassy-rp/src/pio/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index b02f3796f..b7f6aeac9 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1,4 +1,5 @@ //! Clock configuration for the RP2040 +use core::arch::asm; use core::marker::PhantomData; use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; @@ -7,6 +8,7 @@ use pac::clocks::vals::*; use crate::gpio::sealed::Pin; use crate::gpio::AnyPin; +use crate::pac::common::{Reg, RW}; use crate::{pac, reset, Peripheral}; // NOTE: all gpin handling is commented out for future reference. diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 804a7636d..7eca700ba 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -749,7 +749,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_set_count(1); }); // SET PINDIRS, (dir) - unsafe { sm.exec_instr(0b1110_0000_1000_0000 | dir as u16) }; + unsafe { sm.exec_instr(0b111_00000_100_00000 | dir as u16) }; } }); } @@ -764,7 +764,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_set_count(1); }); // SET PINS, (dir) - unsafe { sm.exec_instr(0b1110_0000_0000_0000 | level as u16) }; + unsafe { sm.exec_instr(0b11100_000_000_00000 | level as u16) }; } }); } From 64964bd61444838f2e6a99fcde7ef8fc39b1f0c8 Mon Sep 17 00:00:00 2001 From: Emilie Burgun Date: Tue, 26 Mar 2024 16:22:05 +0100 Subject: [PATCH 742/760] Add a config option to make the VDDIO2 supply line valid On STM32L4[7-A]xx, STM32L5xxx and STM32U5xxx chips, the GPIOG[2..15] pins are only available once the IOSV bit has been set in PWR->CR2 (U5 chips have the bit in a funkier register). This is meant to allow the user to have control over this power supply, so the GPIOG pins are initially insulated, until the user wishes to un-insulate them (or something like that?). For most applications, though, the VDDIO2 is connected to the VDD line, and this behavior only gets in the way and causes confusing issues. This submission adds an option in `embassy_stm32::Config`, called `enable_independent_io_supply`, which simply enables the IOSV bit. It is only available on chips for which I could find a mention of IOSV (STM32L4 and STM32L5) or IO2SV (STM32U5). --- embassy-stm32/src/lib.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 6a3d1c463..05b1ff045 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -172,6 +172,14 @@ pub struct Config { #[cfg(dbgmcu)] pub enable_debug_during_sleep: bool, + /// On low-power boards (eg. `stm32l4`, `stm32l5` and `stm32u5`), + /// some GPIO pins are powered by an auxiliary, independent power supply (`VDDIO2`), + /// which needs to be enabled before these pins can be used. + /// + /// May increase power consumption. Defaults to true. + #[cfg(any(stm32l4, stm32l5, stm32u5))] + pub enable_independent_io_supply: bool, + /// BDMA interrupt priority. /// /// Defaults to P0 (highest). @@ -209,6 +217,8 @@ impl Default for Config { rcc: Default::default(), #[cfg(dbgmcu)] enable_debug_during_sleep: true, + #[cfg(any(stm32l4, stm32l5, stm32u5))] + enable_independent_io_supply: true, #[cfg(bdma)] bdma_interrupt_priority: Priority::P0, #[cfg(dma)] @@ -270,6 +280,23 @@ pub fn init(config: Config) -> Peripherals { #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] peripherals::FLASH::enable_and_reset_with_cs(cs); + // Enable the VDDIO2 power supply on chips that have it. + // Note that this requires the PWR peripheral to be enabled first. + #[cfg(any(stm32l4, stm32l5))] + { + crate::pac::PWR.cr2().modify(|w| { + // The official documentation states that we should ideally enable VDDIO2 + // through the PVME2 bit, but it looks like this bit + w.set_iosv(config.enable_independent_io_supply); + }); + } + #[cfg(stm32u5)] + { + crate::pac::PWR.svmcr().modify(|w| { + w.set_io2sv(config.enable_independent_io_supply); + }); + } + // dead battery functionality is still present on these // chips despite them not having UCPD- disable it #[cfg(any(stm32g070, stm32g0b0))] From ca998c170f18c252e0d4c5a6aed1085113c27dd0 Mon Sep 17 00:00:00 2001 From: Emilie Burgun Date: Tue, 26 Mar 2024 16:33:41 +0100 Subject: [PATCH 743/760] Missing half of the implementation detail comment --- embassy-stm32/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 05b1ff045..ab6ef8ef4 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -286,7 +286,8 @@ pub fn init(config: Config) -> Peripherals { { crate::pac::PWR.cr2().modify(|w| { // The official documentation states that we should ideally enable VDDIO2 - // through the PVME2 bit, but it looks like this bit + // through the PVME2 bit, but it looks like this isn't required, + // and CubeMX itself skips this step. w.set_iosv(config.enable_independent_io_supply); }); } From 402def86ee6a1d8695fc0a4cf157d1ffca7550d9 Mon Sep 17 00:00:00 2001 From: Emilie Burgun Date: Tue, 26 Mar 2024 17:27:02 +0100 Subject: [PATCH 744/760] Remove ad-hoc fixes for setting the IOSV bit to true --- embassy-stm32/src/gpio.rs | 7 ------- examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 6 ------ tests/stm32/src/common.rs | 7 ------- 3 files changed, 20 deletions(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 33f22f676..214813a42 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -779,13 +779,6 @@ pub(crate) unsafe fn init(_cs: CriticalSection) { ::enable_and_reset_with_cs(_cs); crate::_generated::init_gpio(); - - // Setting this bit is mandatory to use PG[15:2]. - #[cfg(stm32u5)] - crate::pac::PWR.svmcr().modify(|w| { - w.set_io2sv(true); - w.set_io2vmen(true); - }); } impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 343e09e68..77aa929ab 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -93,12 +93,6 @@ async fn main(spawner: Spawner) { let dp = embassy_stm32::init(config); - // RM0432rev9, 5.1.2: Independent I/O supply rail - // After reset, the I/Os supplied by VDDIO2 are logically and electrically isolated and - // therefore are not available. The isolation must be removed before using any I/O from - // PG[15:2], by setting the IOSV bit in the PWR_CR2 register, once the VDDIO2 supply is present - pac::PWR.cr2().modify(|w| w.set_iosv(true)); - let reset_status = pac::RCC.bdcr().read().0; defmt::println!("bdcr before: 0x{:X}", reset_status); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index c379863a8..0e555efc8 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -251,13 +251,6 @@ define_peris!( ); pub fn config() -> Config { - // Setting this bit is mandatory to use PG[15:2]. - #[cfg(feature = "stm32u5a5zj")] - embassy_stm32::pac::PWR.svmcr().modify(|w| { - w.set_io2sv(true); - w.set_io2vmen(true); - }); - #[allow(unused_mut)] let mut config = Config::default(); From 1acc34bfaa43dfc3410396cb20e371128e693d1a Mon Sep 17 00:00:00 2001 From: Emilie Burgun Date: Tue, 26 Mar 2024 17:43:22 +0100 Subject: [PATCH 745/760] Remove the need for TxDma to be a DMA channel in the blocking UartTx impl --- embassy-stm32/src/usart/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 7ab33043a..62ea717b3 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1260,7 +1260,6 @@ where impl embedded_io::Write for Uart<'_, T, TxDma, RxDma> where T: BasicInstance, - TxDma: crate::usart::TxDma, { fn write(&mut self, buf: &[u8]) -> Result { self.blocking_write(buf)?; @@ -1275,7 +1274,6 @@ where impl embedded_io::Write for UartTx<'_, T, TxDma> where T: BasicInstance, - TxDma: crate::usart::TxDma, { fn write(&mut self, buf: &[u8]) -> Result { self.blocking_write(buf)?; From cf11d28d628f48e8f3b048deae76e7d18c0a2eec Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Wed, 27 Mar 2024 00:55:44 +0800 Subject: [PATCH 746/760] stm32 H5: LSE low drive mode is not functional --- embassy-stm32/src/rcc/bd.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 39407b28c..54d3c662b 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -24,6 +24,7 @@ pub struct LseConfig { #[allow(dead_code)] #[derive(Default, Clone, Copy)] pub enum LseDrive { + #[cfg(not(stm32h5))] // ES0565: LSE Low drive mode is not functional Low = 0, MediumLow = 0x01, #[default] @@ -38,6 +39,7 @@ impl From for crate::pac::rcc::vals::Lsedrv { use crate::pac::rcc::vals::Lsedrv; match value { + #[cfg(not(stm32h5))] // ES0565: LSE Low drive mode is not functional LseDrive::Low => Lsedrv::LOW, LseDrive::MediumLow => Lsedrv::MEDIUMLOW, LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, From e3ef7cd99faf2fe46463882b35d00ef0f2a34481 Mon Sep 17 00:00:00 2001 From: Emilie Burgun Date: Wed, 27 Mar 2024 11:10:16 +0100 Subject: [PATCH 747/760] Document why embedded_io::Read cannot be implemented for the base Uart --- embassy-stm32/src/usart/mod.rs | 44 +++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 62ea717b3..7c0523a25 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -209,7 +209,14 @@ enum ReadCompletionEvent { Idle(usize), } -/// Bidirectional UART Driver +/// Bidirectional UART Driver, which acts as a combination of [`UartTx`] and [`UartRx`]. +/// +/// ### Notes on [`embedded_io::Read`] +/// +/// `embedded_io::Read` requires guarantees that the base [`UartRx`] cannot provide. +/// +/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`] +/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`. pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { tx: UartTx<'d, T, TxDma>, rx: UartRx<'d, T, RxDma>, @@ -225,7 +232,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> } } -/// Tx-only UART Driver +/// Tx-only UART Driver. +/// +/// Can be obtained from [`Uart::split`], or can be constructed independently, +/// if you do not need the receiving half of the driver. pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { phantom: PhantomData<&'d mut T>, tx_dma: PeripheralRef<'d, TxDma>, @@ -240,7 +250,35 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { } } -/// Rx-only UART Driver +/// Rx-only UART Driver. +/// +/// Can be obtained from [`Uart::split`], or can be constructed independently, +/// if you do not need the transmitting half of the driver. +/// +/// ### Notes on [`embedded_io::Read`] +/// +/// `embedded_io::Read` requires guarantees that this struct cannot provide: +/// +/// - Any data received between calls to [`UartRx::read`] or [`UartRx::blocking_read`] +/// will be thrown away, as `UartRx` is unbuffered. +/// Users of `embedded_io::Read` are likely to not expect this behavior +/// (for instance if they read multiple small chunks in a row). +/// - [`UartRx::read`] and [`UartRx::blocking_read`] only return once the entire buffer has been +/// filled, whereas `embedded_io::Read` requires us to fill the buffer with what we already +/// received, and only block/wait until the first byte arrived. +///
+/// While [`UartRx::read_until_idle`] does return early, it will still eagerly wait for data until +/// the buffer is full or no data has been transmitted in a while, +/// which may not be what users of `embedded_io::Read` expect. +/// +/// [`UartRx::into_ring_buffered`] can be called to equip `UartRx` with a buffer, +/// that it can then use to store data received between calls to `read`, +/// provided you are using DMA already. +/// +/// Alternatively, you can use [`BufferedUartRx`], which is interrupt-based and which can also +/// store data received between calls. +/// +/// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043). pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { _peri: PeripheralRef<'d, T>, rx_dma: PeripheralRef<'d, RxDma>, From c0590626273f020893a8fedf7bffa1cb9a9a6d77 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 27 Mar 2024 15:39:44 +0100 Subject: [PATCH 748/760] embassy_stm32: Preseve the RTR flag in messages. --- embassy-stm32/src/can/bx/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index a369ae6fd..121da1bb2 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -776,13 +776,13 @@ where let mb = self.canregs.tx(idx); - let id = IdReg(mb.tir().read().0).id(); + let id = IdReg(mb.tir().read().0); let mut data = [0xff; 8]; data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); let len = mb.tdtr().read().dlc(); - Some(Frame::new(Header::new(id, len, false), &data).unwrap()) + Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) } else { // Abort request failed because the frame was already sent (or being sent) on // the bus. All mailboxes are now free. This can happen for small prescaler @@ -915,7 +915,7 @@ fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result nb::Result Date: Sun, 24 Mar 2024 07:19:00 +1000 Subject: [PATCH 749/760] CAN: Move some FDCAN definitions into a module to share with BXCAN. --- embassy-stm32/src/can/common.rs | 51 +++++++++++++++++++++++++++ embassy-stm32/src/can/fdcan.rs | 62 ++++++--------------------------- 2 files changed, 61 insertions(+), 52 deletions(-) create mode 100644 embassy-stm32/src/can/common.rs diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs new file mode 100644 index 000000000..1de54e5a1 --- /dev/null +++ b/embassy-stm32/src/can/common.rs @@ -0,0 +1,51 @@ +use embassy_sync::channel::{DynamicReceiver, DynamicSender}; + +use crate::can::_version::frame::*; +use crate::can::_version::Timestamp; +use crate::can::_version::enums::*; + +pub(crate) struct ClassicBufferedRxInner { + pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, +} +pub(crate) struct ClassicBufferedTxInner { + pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, +} + +pub(crate) struct FdBufferedRxInner { + pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, +} +pub(crate) struct FdBufferedTxInner { + pub tx_receiver: DynamicReceiver<'static, FdFrame>, +} + +/// Sender that can be used for sending CAN frames. +#[derive(Copy, Clone)] +pub struct BufferedCanSender { + pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>, + pub(crate) waker: fn(), +} + +impl BufferedCanSender { + /// Async write frame to TX buffer. + pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError> { + self.tx_buf.try_send(frame)?; + (self.waker)(); + Ok(()) + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: ClassicFrame) { + self.tx_buf.send(frame).await; + (self.waker)(); + } + + /// Allows a poll_fn to poll until the channel is ready to write + pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { + self.tx_buf.poll_ready_to_send(cx) + } +} + +/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. +pub type BufferedCanReceiver = + embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; + diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 4ea036ab4..c42c42853 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -14,6 +14,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals, Peripheral}; +mod common; pub mod enums; pub(crate) mod fd; pub mod frame; @@ -24,6 +25,7 @@ use fd::config::*; use fd::filter::*; pub use fd::{config, filter}; use frame::*; +pub use self::common::{BufferedCanSender, BufferedCanReceiver}; /// Timestamp for incoming packets. Use Embassy time when enabled. #[cfg(feature = "time")] @@ -414,36 +416,6 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S rx_buf: &'static RxBuf, } -/// Sender that can be used for sending CAN frames. -#[derive(Copy, Clone)] -pub struct BufferedCanSender { - tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>, - waker: fn(), -} - -impl BufferedCanSender { - /// Async write frame to TX buffer. - pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError> { - self.tx_buf.try_send(frame)?; - (self.waker)(); - Ok(()) - } - - /// Async write frame to TX buffer. - pub async fn write(&mut self, frame: ClassicFrame) { - self.tx_buf.send(frame).await; - (self.waker)(); - } - - /// Allows a poll_fn to poll until the channel is ready to write - pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { - self.tx_buf.poll_ready_to_send(cx) - } -} - -/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. -pub type BufferedCanReceiver = - embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> @@ -468,10 +440,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { - let rx_inner = ClassicBufferedRxInner { + let rx_inner = self::common::ClassicBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; - let tx_inner = ClassicBufferedTxInner { + let tx_inner = self::common::ClassicBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); @@ -586,10 +558,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { - let rx_inner = FdBufferedRxInner { + let rx_inner = self::common::FdBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; - let tx_inner = FdBufferedTxInner { + let tx_inner = self::common::FdBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); @@ -678,24 +650,10 @@ impl<'c, 'd, T: Instance> FdcanRx<'d, T> { } } -struct ClassicBufferedRxInner { - rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, -} -struct ClassicBufferedTxInner { - tx_receiver: DynamicReceiver<'static, ClassicFrame>, -} - -struct FdBufferedRxInner { - rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, -} -struct FdBufferedTxInner { - tx_receiver: DynamicReceiver<'static, FdFrame>, -} - enum RxMode { NonBuffered(AtomicWaker), - ClassicBuffered(ClassicBufferedRxInner), - FdBuffered(FdBufferedRxInner), + ClassicBuffered(self::common::ClassicBufferedRxInner), + FdBuffered(self::common::FdBufferedRxInner), } impl RxMode { @@ -765,8 +723,8 @@ impl RxMode { enum TxMode { NonBuffered(AtomicWaker), - ClassicBuffered(ClassicBufferedTxInner), - FdBuffered(FdBufferedTxInner), + ClassicBuffered(self::common::ClassicBufferedTxInner), + FdBuffered(self::common::FdBufferedTxInner), } impl TxMode { From 32065d7719e8dd2f5da7787d4b7edf3109c632ba Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 14 Mar 2024 21:13:19 +1000 Subject: [PATCH 750/760] BXCAN: Cut out more that wasn't required from BXCAN crate. --- embassy-stm32/src/can/bx/mod.rs | 123 +++----------------------------- embassy-stm32/src/can/bxcan.rs | 7 +- 2 files changed, 11 insertions(+), 119 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 121da1bb2..5ea0471c9 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -602,54 +602,14 @@ where unsafe { Tx::::conjure(self.canregs).abort(mailbox) } } - /// Returns a received frame if available. - /// - /// This will first check FIFO 0 for a message or error. If none are available, FIFO 1 is - /// checked. - /// - /// Returns `Err` when a frame was lost due to buffer overrun. - pub fn receive(&mut self) -> nb::Result { - // Safety: We have a `&mut self` and have unique access to the peripheral. - let mut rx0 = unsafe { Rx0::::conjure(self.canregs) }; - let mut rx1 = unsafe { Rx1::::conjure(self.canregs) }; - match rx0.receive() { - Err(nb::Error::WouldBlock) => rx1.receive(), - result => result, - } - } - - /// Returns a reference to the RX FIFO 0. - pub fn rx0(&mut self) -> Rx0 { - // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. - unsafe { Rx0::conjure(self.canregs) } - } - - /// Returns a reference to the RX FIFO 1. - pub fn rx1(&mut self) -> Rx1 { - // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. - unsafe { Rx1::conjure(self.canregs) } - } - - pub(crate) fn split_by_ref(&mut self) -> (Tx, Rx0, Rx1) { + pub(crate) fn split_by_ref(&mut self) -> (Tx, Rx) { // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. let tx = unsafe { Tx::conjure(self.canregs) }; - let rx0 = unsafe { Rx0::conjure(self.canregs) }; - let rx1 = unsafe { Rx1::conjure(self.canregs) }; - (tx, rx0, rx1) + let rx0 = unsafe { Rx::conjure() }; + (tx, rx0) } - /// Consumes this `Can` instance and splits it into transmitting and receiving halves. - pub fn split(self) -> (Tx, Rx0, Rx1) { - // Safety: `Self` is not `Copy` and is destroyed by moving it into this method. - unsafe { - ( - Tx::conjure(self.canregs), - Rx0::conjure(self.canregs), - Rx1::conjure(self.canregs), - ) - } - } } impl Can { @@ -662,7 +622,7 @@ impl Can { } } -/// Interface to the CAN transmitter part. +/// Marker for Tx half pub struct Tx { _can: PhantomData, canregs: crate::pac::can::Can, @@ -844,87 +804,20 @@ where } } -/// Interface to receiver FIFO 0. -pub struct Rx0 { +/// Marker for Rx half +pub struct Rx { _can: PhantomData, - canregs: crate::pac::can::Can, } -impl Rx0 +impl Rx where I: Instance, { - unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { + unsafe fn conjure() -> Self { Self { _can: PhantomData, - canregs, } } - - /// Returns a received frame if available. - /// - /// Returns `Err` when a frame was lost due to buffer overrun. - pub fn receive(&mut self) -> nb::Result { - receive_fifo(self.canregs, 0) - } -} - -/// Interface to receiver FIFO 1. -pub struct Rx1 { - _can: PhantomData, - canregs: crate::pac::can::Can, -} - -impl Rx1 -where - I: Instance, -{ - unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { - Self { - _can: PhantomData, - canregs, - } - } - - /// Returns a received frame if available. - /// - /// Returns `Err` when a frame was lost due to buffer overrun. - pub fn receive(&mut self) -> nb::Result { - receive_fifo(self.canregs, 1) - } -} - -fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result { - assert!(fifo_nr < 2); - let rfr = canregs.rfr(fifo_nr); - let rx = canregs.rx(fifo_nr); - - //let rfr = &can.rfr[fifo_nr]; - //let rx = &can.rx[fifo_nr]; - - // Check if a frame is available in the mailbox. - let rfr_read = rfr.read(); - if rfr_read.fmp() == 0 { - return Err(nb::Error::WouldBlock); - } - - // Check for RX FIFO overrun. - if rfr_read.fovr() { - rfr.write(|w| w.set_fovr(true)); - return Err(nb::Error::Other(OverrunError { _priv: () })); - } - - // Read the frame. - let id = IdReg(rx.rir().read().0); - let mut data = [0xff; 8]; - data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes()); - data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes()); - let len = rx.rdtr().read().dlc(); - - // Release the mailbox. - rfr.write(|w| w.set_rfom(true)); - - Ok(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) } /// Identifies one of the two receive FIFOs. diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 017c5110d..9d2b8797e 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -296,8 +296,8 @@ impl<'d, T: Instance> Can<'d, T> { /// /// Useful for doing separate transmit/receive tasks. pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { - let (tx, rx0, rx1) = self.can.split_by_ref(); - (CanTx { tx }, CanRx { rx0, rx1 }) + let (tx, rx) = self.can.split_by_ref(); + (CanTx { tx }, CanRx { rx}) } } @@ -401,8 +401,7 @@ impl<'d, T: Instance> CanTx<'d, T> { /// CAN driver, receive half. #[allow(dead_code)] pub struct CanRx<'d, T: Instance> { - rx0: crate::can::bx::Rx0>, - rx1: crate::can::bx::Rx1>, + rx: crate::can::bx::Rx>, } impl<'d, T: Instance> CanRx<'d, T> { From 3bdaad39e8955fe52e55c65a834dfc42dc54d676 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 24 Mar 2024 07:20:33 +1000 Subject: [PATCH 751/760] BXCAN: Register access into new Registers struct. --- embassy-stm32/src/can/bx/mod.rs | 753 +++++++++++++++++++------------- embassy-stm32/src/can/bxcan.rs | 76 +--- embassy-stm32/src/can/common.rs | 12 +- embassy-stm32/src/can/fdcan.rs | 4 +- 4 files changed, 465 insertions(+), 380 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 5ea0471c9..9b6ebf5a4 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -43,7 +43,35 @@ pub type Data = crate::can::frame::ClassicData; /// CAN Frame pub type Frame = crate::can::frame::ClassicFrame; +use crate::can::_version::Envelope; use crate::can::bx::filter::MasterFilters; +use crate::can::enums::BusError; +use crate::pac::can::vals::Lec; + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub(crate) enum RxFifo { + Fifo0, + Fifo1, +} + +trait IntoBusError { + fn into_bus_err(self) -> Option; +} + +impl IntoBusError for Lec { + fn into_bus_err(self) -> Option { + match self { + Lec::STUFF => Some(BusError::Stuff), + Lec::FORM => Some(BusError::Form), + Lec::ACK => Some(BusError::Acknowledge), + Lec::BITRECESSIVE => Some(BusError::BitRecessive), + Lec::BITDOMINANT => Some(BusError::BitDominant), + Lec::CRC => Some(BusError::Crc), + Lec::CUSTOM => Some(BusError::Software), + _ => None, + } + } +} /// A bxCAN peripheral instance. /// @@ -233,229 +261,36 @@ impl PartialOrd for IdReg { } } -/// Configuration proxy returned by [`Can::modify_config`]. -#[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] -pub struct CanConfig<'a, I: Instance> { - can: &'a mut Can, +pub(crate) struct Registers { + pub canregs: crate::pac::can::Can, } -impl CanConfig<'_, I> { - /// Configures the bit timings. - /// - /// You can use to calculate the `btr` parameter. Enter - /// parameters as follows: - /// - /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). - /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). - /// - *Sample Point*: Should normally be left at the default value of 87.5%. - /// - *SJW*: Should normally be left at the default value of 1. - /// - /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` - /// parameter to this method. - pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { - self.can.set_bit_timing(bt); - self - } - - /// Enables or disables loopback mode: Internally connects the TX and RX - /// signals together. - pub fn set_loopback(self, enabled: bool) -> Self { - self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); - self - } - - /// Enables or disables silent mode: Disconnects the TX signal from the pin. - pub fn set_silent(self, enabled: bool) -> Self { - let mode = match enabled { - false => stm32_metapac::can::vals::Silm::NORMAL, - true => stm32_metapac::can::vals::Silm::SILENT, - }; - self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); - self - } - - /// Enables or disables automatic retransmission of messages. - /// - /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame - /// until it can be sent. Otherwise, it will try only once to send each frame. - /// - /// Automatic retransmission is enabled by default. - pub fn set_automatic_retransmit(self, enabled: bool) -> Self { - self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); - self - } - - /// Leaves initialization mode and enables the peripheral. - /// - /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected - /// on the bus. - /// - /// If you want to finish configuration without enabling the peripheral, you can call - /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. - pub fn enable(mut self) { - self.leave_init_mode(); - - match nb::block!(self.can.enable_non_blocking()) { - Ok(()) => {} - Err(void) => match void {}, - } - - // Don't run the destructor. - mem::forget(self); - } - - /// Leaves initialization mode, but keeps the peripheral in sleep mode. - /// - /// Before the [`Can`] instance can be used, you have to enable it by calling - /// [`Can::enable_non_blocking`]. - pub fn leave_disabled(mut self) { - self.leave_init_mode(); - } - - /// Leaves initialization mode, enters sleep mode. - fn leave_init_mode(&mut self) { - self.can.canregs.mcr().modify(|reg| { - reg.set_sleep(true); - reg.set_inrq(false); - }); - loop { - let msr = self.can.canregs.msr().read(); - if msr.slak() && !msr.inak() { - break; - } - } - } -} - -impl Drop for CanConfig<'_, I> { - #[inline] - fn drop(&mut self) { - self.leave_init_mode(); - } -} - -/// Builder returned by [`Can::builder`]. -#[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"] -pub struct CanBuilder { - can: Can, -} - -impl CanBuilder { - /// Configures the bit timings. - /// - /// You can use to calculate the `btr` parameter. Enter - /// parameters as follows: - /// - /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). - /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). - /// - *Sample Point*: Should normally be left at the default value of 87.5%. - /// - *SJW*: Should normally be left at the default value of 1. - /// - /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` - /// parameter to this method. - pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { - self.can.set_bit_timing(bt); - self - } - /// Enables or disables loopback mode: Internally connects the TX and RX - /// signals together. - pub fn set_loopback(self, enabled: bool) -> Self { - self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); - self - } - - /// Enables or disables silent mode: Disconnects the TX signal from the pin. - pub fn set_silent(self, enabled: bool) -> Self { - let mode = match enabled { - false => stm32_metapac::can::vals::Silm::NORMAL, - true => stm32_metapac::can::vals::Silm::SILENT, - }; - self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); - self - } - - /// Enables or disables automatic retransmission of messages. - /// - /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame - /// until it can be sent. Otherwise, it will try only once to send each frame. - /// - /// Automatic retransmission is enabled by default. - pub fn set_automatic_retransmit(self, enabled: bool) -> Self { - self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); - self - } - - /// Leaves initialization mode and enables the peripheral. - /// - /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected - /// on the bus. - /// - /// If you want to finish configuration without enabling the peripheral, you can call - /// [`CanBuilder::leave_disabled`] instead. - pub fn enable(mut self) -> Can { - self.leave_init_mode(); - - match nb::block!(self.can.enable_non_blocking()) { - Ok(()) => self.can, - Err(void) => match void {}, - } - } - - /// Returns the [`Can`] interface without enabling it. - /// - /// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling - /// it. - /// - /// Before the [`Can`] instance can be used, you have to enable it by calling - /// [`Can::enable_non_blocking`]. - pub fn leave_disabled(mut self) -> Can { - self.leave_init_mode(); - self.can - } - - /// Leaves initialization mode, enters sleep mode. - fn leave_init_mode(&mut self) { - self.can.canregs.mcr().modify(|reg| { - reg.set_sleep(true); - reg.set_inrq(false); - }); - loop { - let msr = self.can.canregs.msr().read(); - if msr.slak() && !msr.inak() { - break; - } - } - } -} - -/// Interface to a bxCAN peripheral. -pub struct Can { - instance: I, - canregs: crate::pac::can::Can, -} - -impl Can -where - I: Instance, -{ - /// Creates a [`CanBuilder`] for constructing a CAN interface. - pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder { - let can_builder = CanBuilder { - can: Can { instance, canregs }, - }; - - canregs.mcr().modify(|reg| { +impl Registers { + fn enter_init_mode(&mut self) { + self.canregs.mcr().modify(|reg| { reg.set_sleep(false); reg.set_inrq(true); }); loop { - let msr = canregs.msr().read(); + let msr = self.canregs.msr().read(); if !msr.slak() && msr.inak() { break; } } + } - can_builder + // Leaves initialization mode, enters sleep mode. + fn leave_init_mode(&mut self) { + self.canregs.mcr().modify(|reg| { + reg.set_sleep(true); + reg.set_inrq(false); + }); + loop { + let msr = self.canregs.msr().read(); + if msr.slak() && !msr.inak() { + break; + } + } } fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { @@ -471,38 +306,29 @@ where }); } - /// Returns a reference to the peripheral instance. - /// - /// This allows accessing HAL-specific data stored in the instance type. - pub fn instance(&mut self) -> &mut I { - &mut self.instance + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + pub fn set_silent(&self, enabled: bool) { + let mode = match enabled { + false => stm32_metapac::can::vals::Silm::NORMAL, + true => stm32_metapac::can::vals::Silm::SILENT, + }; + self.canregs.btr().modify(|reg| reg.set_silm(mode)); } - /// Disables the CAN interface and returns back the raw peripheral it was created from. + /// Enables or disables automatic retransmission of messages. /// - /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to - /// enter sleep mode. - pub fn free(self) -> I { - self.canregs.mcr().write(|reg| reg.set_reset(true)); - self.instance + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// until it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + pub fn set_automatic_retransmit(&self, enabled: bool) { + self.canregs.mcr().modify(|reg| reg.set_nart(enabled)); } - /// Configure bit timings and silent/loop-back mode. - /// - /// Calling this method will enter initialization mode. - pub fn modify_config(&mut self) -> CanConfig<'_, I> { - self.canregs.mcr().modify(|reg| { - reg.set_sleep(false); - reg.set_inrq(true); - }); - loop { - let msr = self.canregs.msr().read(); - if !msr.slak() && msr.inak() { - break; - } - } - - CanConfig { can: self } + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + pub fn set_loopback(&self, enabled: bool) { + self.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); } /// Configures the automatic wake-up feature. @@ -512,6 +338,7 @@ where /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming /// frame. + #[allow(dead_code)] pub fn set_automatic_wakeup(&mut self, enabled: bool) { self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); } @@ -540,6 +367,7 @@ where /// Puts the peripheral in a sleep mode to save power. /// /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. + #[allow(dead_code)] pub fn sleep(&mut self) { self.canregs.mcr().modify(|reg| { reg.set_sleep(true); @@ -553,10 +381,19 @@ where } } + /// Disables the CAN interface. + /// + /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to + /// enter sleep mode. + pub fn reset(&self) { + self.canregs.mcr().write(|reg| reg.set_reset(true)); + } + /// Wakes up from sleep mode. /// /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN /// frame will cause that interrupt. + #[allow(dead_code)] pub fn wakeup(&mut self) { self.canregs.mcr().modify(|reg| { reg.set_sleep(false); @@ -569,74 +406,19 @@ where } } } - - /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. - /// - /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). - /// Transmit order is preserved for frames with identical priority. - /// - /// If all transmit mailboxes are full, and `frame` has a higher priority than the - /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is - /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as - /// [`TransmitStatus::dequeued_frame`]. - pub fn transmit(&mut self, frame: &Frame) -> nb::Result { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure(self.canregs).transmit(frame) } - } - - /// Returns `true` if no frame is pending for transmission. - pub fn is_transmitter_idle(&self) -> bool { - // Safety: Read-only operation. - unsafe { Tx::::conjure(self.canregs).is_idle() } - } - - /// Attempts to abort the sending of a frame that is pending in a mailbox. - /// - /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be - /// aborted, this function has no effect and returns `false`. - /// - /// If there is a frame in the provided mailbox, and it is canceled successfully, this function - /// returns `true`. - pub fn abort(&mut self, mailbox: Mailbox) -> bool { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure(self.canregs).abort(mailbox) } - } - - - pub(crate) fn split_by_ref(&mut self) -> (Tx, Rx) { - // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. - let tx = unsafe { Tx::conjure(self.canregs) }; - let rx0 = unsafe { Rx::conjure() }; - (tx, rx0) - } - -} - -impl Can { - /// Accesses the filter banks owned by this CAN peripheral. - /// - /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master - /// peripheral instead. - pub fn modify_filters(&mut self) -> MasterFilters<'_, I> { - unsafe { MasterFilters::new(self.canregs) } - } -} - -/// Marker for Tx half -pub struct Tx { - _can: PhantomData, - canregs: crate::pac::can::Can, -} - -impl Tx -where - I: Instance, -{ - unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { - Self { - _can: PhantomData, - canregs, + + pub fn curr_error(&self) -> Option { + let err = { self.canregs.esr().read() }; + if err.boff() { + return Some(BusError::BusOff); + } else if err.epvf() { + return Some(BusError::BusPassive); + } else if err.ewgf() { + return Some(BusError::BusWarning); + } else if let Some(err) = err.lec().into_bus_err() { + return Some(err); } + None } /// Puts a CAN frame in a transmit mailbox for transmission on the bus. @@ -802,6 +584,361 @@ where reg.set_rqcp(2, true); }); } + + pub fn receive_fifo(&self, fifo: crate::can::_version::bx::RxFifo) -> Option { + // Generate timestamp as early as possible + #[cfg(feature = "time")] + let ts = embassy_time::Instant::now(); + + use crate::pac::can::vals::Ide; + + let fifo_idx = match fifo { + crate::can::_version::bx::RxFifo::Fifo0 => 0usize, + crate::can::_version::bx::RxFifo::Fifo1 => 1usize, + }; + let rfr = self.canregs.rfr(fifo_idx); + let fifo = self.canregs.rx(fifo_idx); + + // If there are no pending messages, there is nothing to do + if rfr.read().fmp() == 0 { + return None; + } + + let rir = fifo.rir().read(); + let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { + embedded_can::StandardId::new(rir.stid()).unwrap().into() + } else { + let stid = (rir.stid() & 0x7FF) as u32; + let exid = rir.exid() & 0x3FFFF; + let id = (stid << 18) | (exid); + embedded_can::ExtendedId::new(id).unwrap().into() + }; + let data_len = fifo.rdtr().read().dlc(); + let mut data: [u8; 8] = [0; 8]; + data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); + data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); + + let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); + let envelope = Envelope { + #[cfg(feature = "time")] + ts, + frame, + }; + + rfr.modify(|v| v.set_rfom(true)); + + Some(envelope) + } +} + +/// Configuration proxy returned by [`Can::modify_config`]. +#[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] +pub struct CanConfig<'a, I: Instance> { + can: &'a mut Can, +} + +impl CanConfig<'_, I> { + /// Configures the bit timings. + /// + /// You can use to calculate the `btr` parameter. Enter + /// parameters as follows: + /// + /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). + /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). + /// - *Sample Point*: Should normally be left at the default value of 87.5%. + /// - *SJW*: Should normally be left at the default value of 1. + /// + /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` + /// parameter to this method. + pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { + self.can.registers.set_bit_timing(bt); + self + } + + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + pub fn set_loopback(self, enabled: bool) -> Self { + self.can.registers.set_loopback(enabled); + self + } + + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + pub fn set_silent(self, enabled: bool) -> Self { + self.can.registers.set_silent(enabled); + self + } + + /// Enables or disables automatic retransmission of messages. + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// until it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + pub fn set_automatic_retransmit(self, enabled: bool) -> Self { + self.can.registers.set_automatic_retransmit(enabled); + self + } + + /// Leaves initialization mode and enables the peripheral. + /// + /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected + /// on the bus. + /// + /// If you want to finish configuration without enabling the peripheral, you can call + /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. + pub fn enable(self) { + self.can.registers.leave_init_mode(); + + match nb::block!(self.can.registers.enable_non_blocking()) { + Ok(()) => {} + Err(void) => match void {}, + } + + // Don't run the destructor. + mem::forget(self); + } + + /// Leaves initialization mode, but keeps the peripheral in sleep mode. + /// + /// Before the [`Can`] instance can be used, you have to enable it by calling + /// [`Can::enable_non_blocking`]. + pub fn leave_disabled(self) { + self.can.registers.leave_init_mode(); + } +} + +impl Drop for CanConfig<'_, I> { + #[inline] + fn drop(&mut self) { + self.can.registers.leave_init_mode(); + } +} + +/// Builder returned by [`Can::builder`]. +#[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"] +pub struct CanBuilder { + can: Can, +} + +impl CanBuilder { + /// Configures the bit timings. + /// + /// You can use to calculate the `btr` parameter. Enter + /// parameters as follows: + /// + /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). + /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). + /// - *Sample Point*: Should normally be left at the default value of 87.5%. + /// - *SJW*: Should normally be left at the default value of 1. + /// + /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` + /// parameter to this method. + pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { + self.can.registers.set_bit_timing(bt); + self + } + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + pub fn set_loopback(self, enabled: bool) -> Self { + self.can.registers.set_loopback(enabled); + self + } + + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + pub fn set_silent(self, enabled: bool) -> Self { + self.can.registers.set_silent(enabled); + self + } + + /// Enables or disables automatic retransmission of messages. + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// until it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + pub fn set_automatic_retransmit(self, enabled: bool) -> Self { + self.can.registers.set_automatic_retransmit(enabled); + self + } + + /// Leaves initialization mode and enables the peripheral. + /// + /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected + /// on the bus. + /// + /// If you want to finish configuration without enabling the peripheral, you can call + /// [`CanBuilder::leave_disabled`] instead. + pub fn enable(mut self) -> Can { + self.leave_init_mode(); + + match nb::block!(self.can.registers.enable_non_blocking()) { + Ok(()) => self.can, + Err(void) => match void {}, + } + } + + /// Returns the [`Can`] interface without enabling it. + /// + /// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling + /// it. + /// + /// Before the [`Can`] instance can be used, you have to enable it by calling + /// [`Can::enable_non_blocking`]. + pub fn leave_disabled(mut self) -> Can { + self.leave_init_mode(); + self.can + } + + /// Leaves initialization mode, enters sleep mode. + fn leave_init_mode(&mut self) { + self.can.registers.leave_init_mode(); + } +} + +/// Interface to a bxCAN peripheral. +pub struct Can { + instance: I, + canregs: crate::pac::can::Can, + pub(crate) registers: Registers, +} + +impl Can +where + I: Instance, +{ + /// Creates a [`CanBuilder`] for constructing a CAN interface. + pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder { + let mut can_builder = CanBuilder { + can: Can { + instance, + canregs, + registers: Registers { canregs }, + }, + }; + + can_builder.can.registers.enter_init_mode(); + + can_builder + } + + /// Disables the CAN interface and returns back the raw peripheral it was created from. + /// + /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to + /// enter sleep mode. + pub fn free(self) -> I { + self.registers.reset(); + self.instance + } + + /// Configure bit timings and silent/loop-back mode. + /// + /// Calling this method will enter initialization mode. + pub fn modify_config(&mut self) -> CanConfig<'_, I> { + self.registers.enter_init_mode(); + + CanConfig { can: self } + } + + /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. + /// + /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). + /// Transmit order is preserved for frames with identical priority. + /// + /// If all transmit mailboxes are full, and `frame` has a higher priority than the + /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is + /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as + /// [`TransmitStatus::dequeued_frame`]. + pub fn transmit(&mut self, frame: &Frame) -> nb::Result { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure(self.canregs).transmit(frame) } + } + + /// Returns `true` if no frame is pending for transmission. + pub fn is_transmitter_idle(&self) -> bool { + // Safety: Read-only operation. + unsafe { Tx::::conjure(self.canregs).is_idle() } + } + + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// If there is a frame in the provided mailbox, and it is canceled successfully, this function + /// returns `true`. + pub fn abort(&mut self, mailbox: Mailbox) -> bool { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure(self.canregs).abort(mailbox) } + } + + pub(crate) fn split_by_ref(&mut self) -> (Tx, Rx) { + // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. + let tx = unsafe { Tx::conjure(self.canregs) }; + let rx0 = unsafe { Rx::conjure() }; + (tx, rx0) + } +} + +impl Can { + /// Accesses the filter banks owned by this CAN peripheral. + /// + /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master + /// peripheral instead. + pub fn modify_filters(&mut self) -> MasterFilters<'_, I> { + unsafe { MasterFilters::new(self.canregs) } + } +} + +/// Marker for Tx half +pub struct Tx { + _can: PhantomData, + pub(crate) registers: Registers, +} + +impl Tx +where + I: Instance, +{ + unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { + Self { + _can: PhantomData, + registers: Registers { canregs }, //canregs, + } + } + + /// Puts a CAN frame in a transmit mailbox for transmission on the bus. + /// + /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). + /// Transmit order is preserved for frames with identical priority. + /// + /// If all transmit mailboxes are full, and `frame` has a higher priority than the + /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is + /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as + /// [`TransmitStatus::dequeued_frame`]. + pub fn transmit(&mut self, frame: &Frame) -> nb::Result { + self.registers.transmit(frame) + } + + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// If there is a frame in the provided mailbox, and it is canceled successfully, this function + /// returns `true`. + pub fn abort(&mut self, mailbox: Mailbox) -> bool { + self.registers.abort(mailbox) + } + + /// Returns `true` if no frame is pending for transmission. + pub fn is_idle(&self) -> bool { + self.registers.is_idle() + } + + /// Clears the request complete flag for all mailboxes. + pub fn clear_interrupt_flags(&mut self) { + self.registers.clear_interrupt_flags() + } } /// Marker for Rx half @@ -814,9 +951,7 @@ where I: Instance, { unsafe fn conjure() -> Self { - Self { - _can: PhantomData, - } + Self { _can: PhantomData } } } diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 9d2b8797e..d865bbe7d 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -14,7 +14,6 @@ use futures::FutureExt; use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; -use crate::pac::can::vals::{Ide, Lec}; use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals, Peripheral}; @@ -185,7 +184,7 @@ impl<'d, T: Instance> Can<'d, T> { /// This will wait for 11 consecutive recessive bits (bus idle state). /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. pub async fn enable(&mut self) { - while self.enable_non_blocking().is_err() { + while self.registers.enable_non_blocking().is_err() { // SCE interrupt is only generated for entering sleep mode, but not leaving. // Yield to allow other tasks to execute while can bus is initializing. embassy_futures::yield_now().await; @@ -243,52 +242,17 @@ impl<'d, T: Instance> Can<'d, T> { } unsafe fn receive_fifo(fifo: RxFifo) { - // Generate timestamp as early as possible - #[cfg(feature = "time")] - let ts = embassy_time::Instant::now(); - let state = T::state(); - let regs = T::regs(); - let fifo_idx = match fifo { - RxFifo::Fifo0 => 0usize, - RxFifo::Fifo1 => 1usize, - }; - let rfr = regs.rfr(fifo_idx); - let fifo = regs.rx(fifo_idx); + let regsisters = crate::can::bx::Registers { canregs: T::regs() }; loop { - // If there are no pending messages, there is nothing to do - if rfr.read().fmp() == 0 { - return; - } - - let rir = fifo.rir().read(); - let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { - embedded_can::StandardId::new(rir.stid()).unwrap().into() - } else { - let stid = (rir.stid() & 0x7FF) as u32; - let exid = rir.exid() & 0x3FFFF; - let id = (stid << 18) | (exid); - embedded_can::ExtendedId::new(id).unwrap().into() + match regsisters.receive_fifo(fifo) { + Some(envelope) => { + // NOTE: consensus was reached that if rx_queue is full, packets should be dropped + let _ = state.rx_queue.try_send(envelope); + } + None => return, }; - let data_len = fifo.rdtr().read().dlc(); - let mut data: [u8; 8] = [0; 8]; - data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); - data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); - - let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); - let envelope = Envelope { - #[cfg(feature = "time")] - ts, - frame, - }; - - rfr.modify(|v| v.set_rfom(true)); - - /* - NOTE: consensus was reached that if rx_queue is full, packets should be dropped - */ - let _ = state.rx_queue.try_send(envelope); } } @@ -297,7 +261,7 @@ impl<'d, T: Instance> Can<'d, T> { /// Useful for doing separate transmit/receive tasks. pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { let (tx, rx) = self.can.split_by_ref(); - (CanTx { tx }, CanRx { rx}) + (CanTx { tx }, CanRx { rx }) } } @@ -459,10 +423,7 @@ impl<'d, T: Instance> CanRx<'d, T> { } } -enum RxFifo { - Fifo0, - Fifo1, -} +use crate::can::bx::RxFifo; impl<'d, T: Instance> Drop for Can<'d, T> { fn drop(&mut self) { @@ -601,21 +562,4 @@ impl Index for crate::can::bx::Mailbox { } } -trait IntoBusError { - fn into_bus_err(self) -> Option; -} -impl IntoBusError for Lec { - fn into_bus_err(self) -> Option { - match self { - Lec::STUFF => Some(BusError::Stuff), - Lec::FORM => Some(BusError::Form), - Lec::ACK => Some(BusError::Acknowledge), - Lec::BITRECESSIVE => Some(BusError::BitRecessive), - Lec::BITDOMINANT => Some(BusError::BitDominant), - Lec::CRC => Some(BusError::Crc), - Lec::CUSTOM => Some(BusError::Software), - _ => None, - } - } -} diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 1de54e5a1..8c9990798 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -1,8 +1,15 @@ use embassy_sync::channel::{DynamicReceiver, DynamicSender}; -use crate::can::_version::frame::*; -use crate::can::_version::Timestamp; use crate::can::_version::enums::*; +use crate::can::_version::frame::*; + +/// Timestamp for incoming packets. Use Embassy time when enabled. +#[cfg(feature = "time")] +pub type Timestamp = embassy_time::Instant; + +/// Timestamp for incoming packets. +#[cfg(not(feature = "time"))] +pub type Timestamp = u16; pub(crate) struct ClassicBufferedRxInner { pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, @@ -48,4 +55,3 @@ impl BufferedCanSender { /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; - diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index c42c42853..42c9bd9f6 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -25,7 +25,8 @@ use fd::config::*; use fd::filter::*; pub use fd::{config, filter}; use frame::*; -pub use self::common::{BufferedCanSender, BufferedCanReceiver}; + +pub use self::common::{BufferedCanReceiver, BufferedCanSender}; /// Timestamp for incoming packets. Use Embassy time when enabled. #[cfg(feature = "time")] @@ -416,7 +417,6 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S rx_buf: &'static RxBuf, } - impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { From 26c739c2f93252e9dc476d69f591a84d44491787 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 24 Mar 2024 07:27:29 +1000 Subject: [PATCH 752/760] BXCAN: Create RxMode enum and move reader methods into it, laying foundations for different Rx buffering modes. --- embassy-stm32/src/can/bx/mod.rs | 12 +- embassy-stm32/src/can/bxcan.rs | 264 +++++++++++++++++++++++--------- embassy-stm32/src/can/common.rs | 4 + embassy-stm32/src/can/enums.rs | 10 ++ 4 files changed, 218 insertions(+), 72 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 9b6ebf5a4..c508ef2fe 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -406,7 +406,7 @@ impl Registers { } } } - + pub fn curr_error(&self) -> Option { let err = { self.canregs.esr().read() }; if err.boff() { @@ -585,6 +585,16 @@ impl Registers { }); } + pub fn receive_frame_available(&self) -> bool { + if self.canregs.rfr(0).read().fmp() != 0 { + true + } else if self.canregs.rfr(1).read().fmp() != 0 { + true + } else { + false + } + } + pub fn receive_fifo(&self, fifo: crate::can::_version::bx::RxFifo) -> Option { // Generate timestamp as early as possible #[cfg(feature = "time")] diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index d865bbe7d..66f6e7067 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -10,7 +10,6 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; -use futures::FutureExt; use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; @@ -22,6 +21,9 @@ use enums::*; pub mod frame; pub mod util; +mod common; +pub use self::common::{BufferedCanReceiver, BufferedCanSender, Timestamp}; + /// Contains CAN frame and additional metadata. /// /// Timestamp is available if `time` feature is enabled. @@ -59,8 +61,7 @@ pub struct Rx0InterruptHandler { impl interrupt::typelevel::Handler for Rx0InterruptHandler { unsafe fn on_interrupt() { - // info!("rx0 irq"); - Can::::receive_fifo(RxFifo::Fifo0); + T::state().rx_mode.on_interrupt::(RxFifo::Fifo0); } } @@ -71,8 +72,7 @@ pub struct Rx1InterruptHandler { impl interrupt::typelevel::Handler for Rx1InterruptHandler { unsafe fn on_interrupt() { - // info!("rx1 irq"); - Can::::receive_fifo(RxFifo::Fifo1); + T::state().rx_mode.on_interrupt::(RxFifo::Fifo1); } } @@ -99,16 +99,6 @@ pub struct Can<'d, T: Instance> { can: crate::can::bx::Can>, } -/// Error returned by `try_read` -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum TryReadError { - /// Bus error - BusError(BusError), - /// Receive buffer is empty - Empty, -} - /// Error returned by `try_write` #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -226,34 +216,19 @@ impl<'d, T: Instance> Can<'d, T> { /// /// Returns a tuple of the time the message was received and the message frame pub async fn read(&mut self) -> Result { - self.split().1.read().await + T::state().rx_mode.read::().await } /// Attempts to read a CAN frame without blocking. /// /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. pub fn try_read(&mut self) -> Result { - self.split().1.try_read() + T::state().rx_mode.try_read::() } /// Waits while receive queue is empty. pub async fn wait_not_empty(&mut self) { - self.split().1.wait_not_empty().await - } - - unsafe fn receive_fifo(fifo: RxFifo) { - let state = T::state(); - let regsisters = crate::can::bx::Registers { canregs: T::regs() }; - - loop { - match regsisters.receive_fifo(fifo) { - Some(envelope) => { - // NOTE: consensus was reached that if rx_queue is full, packets should be dropped - let _ = state.rx_queue.try_send(envelope); - } - None => return, - }; - } + T::state().rx_mode.wait_not_empty::().await } /// Split the CAN driver into transmit and receive halves. @@ -375,51 +350,95 @@ impl<'d, T: Instance> CanRx<'d, T> { /// /// Returns a tuple of the time the message was received and the message frame pub async fn read(&mut self) -> Result { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) { - return Poll::Ready(Ok(envelope)); - } else if let Some(err) = self.curr_error() { - return Poll::Ready(Err(err)); - } - - Poll::Pending - }) - .await + T::state().rx_mode.read::().await } /// Attempts to read a CAN frame without blocking. /// /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. pub fn try_read(&mut self) -> Result { - if let Ok(envelope) = T::state().rx_queue.try_receive() { - return Ok(envelope); - } - - if let Some(err) = self.curr_error() { - return Err(TryReadError::BusError(err)); - } - - Err(TryReadError::Empty) + T::state().rx_mode.try_read::() } /// Waits while receive queue is empty. pub async fn wait_not_empty(&mut self) { - poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await + T::state().rx_mode.wait_not_empty::().await } - fn curr_error(&self) -> Option { - let err = { T::regs().esr().read() }; - if err.boff() { - return Some(BusError::BusOff); - } else if err.epvf() { - return Some(BusError::BusPassive); - } else if err.ewgf() { - return Some(BusError::BusWarning); - } else if let Some(err) = err.lec().into_bus_err() { - return Some(err); + /// Return a buffered instance of driver without CAN FD support. User must supply Buffers + pub fn buffered( + self, + rxb: &'static mut RxBuf, + ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { + BufferedCanRx::new(self.rx, rxb) + } +} + +/// User supplied buffer for RX Buffering +pub type RxBuf = + Channel, BUF_SIZE>; + +/// CAN driver, receive half in Buffered mode. +pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { + _rx: crate::can::bx::Rx>, + rx_buf: &'static RxBuf, +} + +impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { + fn new(_rx: crate::can::bx::Rx>, rx_buf: &'static RxBuf) -> Self { + BufferedCanRx { _rx, rx_buf }.setup() + } + + fn setup(self) -> Self { + // We don't want interrupts being processed while we change modes. + critical_section::with(|_| unsafe { + let rx_inner = self::common::ClassicBufferedRxInner { + rx_sender: self.rx_buf.sender().into(), + }; + T::mut_state().rx_mode = RxMode::Buffered(rx_inner); + }); + self + } + + /// Async read frame from RX buffer. + pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> { + self.rx_buf.receive().await + } + + /// Attempts to read a CAN frame without blocking. + /// + /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. + pub fn try_read(&mut self) -> Result { + match &T::state().rx_mode { + RxMode::Buffered(_) => { + if let Ok(result) = self.rx_buf.try_receive() { + match result { + Ok((frame, ts)) => Ok(Envelope { ts, frame }), + Err(e) => Err(TryReadError::BusError(e)), + } + } else { + let registers = crate::can::bx::Registers { canregs: T::regs() }; + if let Some(err) = registers.curr_error() { + return Err(TryReadError::BusError(err)); + } else { + Err(TryReadError::Empty) + } + } + } + _ => { + panic!("Bad Mode") + } } - None + } + + /// Waits while receive queue is empty. + pub async fn wait_not_empty(&mut self) { + poll_fn(|cx| self.rx_buf.poll_ready_to_receive(cx)).await + } + + /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. + pub fn reader(&self) -> BufferedCanReceiver { + self.rx_buf.receiver().into() } } @@ -448,10 +467,111 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> { } } +use crate::can::enums::{BusError, TryReadError}; + +pub(crate) enum RxMode { + NonBuffered(AtomicWaker), + Buffered(crate::can::_version::common::ClassicBufferedRxInner), +} + +impl RxMode { + pub fn on_interrupt(&self, fifo: crate::can::_version::bx::RxFifo) { + match self { + Self::NonBuffered(waker) => { + // Disable interrupts until read + let fifo_idx = match fifo { + crate::can::_version::bx::RxFifo::Fifo0 => 0usize, + crate::can::_version::bx::RxFifo::Fifo1 => 1usize, + }; + T::regs().ier().write(|w| { + w.set_fmpie(fifo_idx, false); + }); + waker.wake(); + } + Self::Buffered(buf) => { + let regsisters = crate::can::bx::Registers { canregs: T::regs() }; + + loop { + match regsisters.receive_fifo(fifo) { + Some(envelope) => { + // NOTE: consensus was reached that if rx_queue is full, packets should be dropped + let _ = buf.rx_sender.try_send(Ok((envelope.frame, envelope.ts))); + } + None => return, + }; + } + } + } + } + + pub async fn read(&self) -> Result { + match self { + Self::NonBuffered(waker) => { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + waker.register(cx.waker()); + match self.try_read::() { + Ok(result) => Poll::Ready(Ok(result)), + Err(TryReadError::Empty) => Poll::Pending, + Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), + } + }) + .await + } + _ => { + panic!("Bad Mode") + } + } + } + pub fn try_read(&self) -> Result { + match self { + Self::NonBuffered(_) => { + let registers = crate::can::bx::Registers { canregs: T::regs() }; + if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo0) { + T::regs().ier().write(|w| { + w.set_fmpie(0, true); + }); + Ok(msg) + } else if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo1) { + T::regs().ier().write(|w| { + w.set_fmpie(1, true); + }); + Ok(msg) + } else if let Some(err) = registers.curr_error() { + Err(TryReadError::BusError(err)) + } else { + Err(TryReadError::Empty) + } + } + _ => { + panic!("Bad Mode") + } + } + } + pub async fn wait_not_empty(&self) { + match &T::state().rx_mode { + Self::NonBuffered(waker) => { + poll_fn(|cx| { + waker.register(cx.waker()); + let registers = crate::can::bx::Registers { canregs: T::regs() }; + if registers.receive_frame_available() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await + } + _ => { + panic!("Bad Mode") + } + } + } +} struct State { pub tx_waker: AtomicWaker, pub err_waker: AtomicWaker, - pub rx_queue: Channel, + pub(crate) rx_mode: RxMode, } impl State { @@ -459,7 +579,7 @@ impl State { Self { tx_waker: AtomicWaker::new(), err_waker: AtomicWaker::new(), - rx_queue: Channel::new(), + rx_mode: RxMode::NonBuffered(AtomicWaker::new()), } } } @@ -467,6 +587,7 @@ impl State { trait SealedInstance { fn regs() -> crate::pac::can::Can; fn state() -> &'static State; + unsafe fn mut_state() -> &'static mut State; } /// CAN instance trait. @@ -495,9 +616,12 @@ foreach_peripheral!( crate::pac::$inst } + unsafe fn mut_state() -> & 'static mut State { + static mut STATE: State = State::new(); + &mut *core::ptr::addr_of_mut!(STATE) + } fn state() -> &'static State { - static STATE: State = State::new(); - &STATE + unsafe { peripherals::$inst::mut_state() } } } @@ -561,5 +685,3 @@ impl Index for crate::can::bx::Mailbox { } } } - - diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 8c9990798..b0d177a6d 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -18,9 +18,13 @@ pub(crate) struct ClassicBufferedTxInner { pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, } +#[cfg(any(can_fdcan_v1, can_fdcan_h7))] + pub(crate) struct FdBufferedRxInner { pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, } + +#[cfg(any(can_fdcan_v1, can_fdcan_h7))] pub(crate) struct FdBufferedTxInner { pub tx_receiver: DynamicReceiver<'static, FdFrame>, } diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 651de9194..4d89c84d1 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs @@ -40,3 +40,13 @@ pub enum FrameCreateError { /// Invalid ID. InvalidCanId, } + +/// Error returned by `try_read` +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TryReadError { + /// Bus error + BusError(BusError), + /// Receive buffer is empty + Empty, +} From 41b7e4a434c0d1fe1fc5d93afe76f8058aa411db Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 24 Mar 2024 08:08:12 +1000 Subject: [PATCH 753/760] BXCAN: Create TxMode in order to support buffered TX. --- embassy-stm32/src/can/bxcan.rs | 130 ++++++++++++++++++++++++++++++--- embassy-stm32/src/can/fdcan.rs | 5 +- 2 files changed, 120 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 66f6e7067..45a3836c0 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -17,7 +17,6 @@ use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals, Peripheral}; pub mod enums; -use enums::*; pub mod frame; pub mod util; @@ -49,8 +48,7 @@ impl interrupt::typelevel::Handler for TxInterruptH v.set_rqcp(1, true); v.set_rqcp(2, true); }); - - T::state().tx_waker.wake(); + T::state().tx_mode.on_interrupt::(); } } @@ -258,7 +256,7 @@ impl<'d, T: Instance> CanTx<'d, T> { /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); + T::state().tx_mode.register(cx.waker()); if let Ok(status) = self.tx.transmit(frame) { return Poll::Ready(status); } @@ -277,7 +275,7 @@ impl<'d, T: Instance> CanTx<'d, T> { async fn flush_inner(mb: crate::can::bx::Mailbox) { poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); + T::state().tx_mode.register(cx.waker()); if T::regs().tsr().read().tme(mb.index()) { return Poll::Ready(()); } @@ -294,7 +292,7 @@ impl<'d, T: Instance> CanTx<'d, T> { async fn flush_any_inner() { poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); + T::state().tx_mode.register(cx.waker()); let tsr = T::regs().tsr().read(); if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) @@ -316,7 +314,7 @@ impl<'d, T: Instance> CanTx<'d, T> { async fn flush_all_inner() { poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); + T::state().tx_mode.register(cx.waker()); let tsr = T::regs().tsr().read(); if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) @@ -335,6 +333,62 @@ impl<'d, T: Instance> CanTx<'d, T> { pub async fn flush_all(&self) { Self::flush_all_inner().await } + + /// Return a buffered instance of driver. User must supply Buffers + pub fn buffered( + self, + txb: &'static mut TxBuf, + ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { + BufferedCanTx::new(self.tx, txb) + } +} + +/// User supplied buffer for TX buffering +pub type TxBuf = Channel; + +/// CAN driver, transmit half. +pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { + _tx: crate::can::bx::Tx>, + tx_buf: &'static TxBuf, +} + +impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { + fn new(_tx: crate::can::bx::Tx>, tx_buf: &'static TxBuf) -> Self { + Self { _tx, tx_buf }.setup() + } + + fn setup(self) -> Self { + // We don't want interrupts being processed while we change modes. + critical_section::with(|_| unsafe { + let tx_inner = self::common::ClassicBufferedTxInner { + tx_receiver: self.tx_buf.receiver().into(), + }; + T::mut_state().tx_mode = TxMode::Buffered(tx_inner); + }); + self + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: &Frame) { + self.tx_buf.send(*frame).await; + T::TXInterrupt::pend(); // Wake for Tx + } + + /// Returns a sender that can be used for sending CAN frames. + pub fn writer(&self) -> BufferedCanSender { + BufferedCanSender { + tx_buf: self.tx_buf.sender().into(), + waker: T::TXInterrupt::pend, + } + } +} + +impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { + fn drop(&mut self) { + critical_section::with(|_| unsafe { + T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + }); + } } /// CAN driver, receive half. @@ -365,7 +419,7 @@ impl<'d, T: Instance> CanRx<'d, T> { T::state().rx_mode.wait_not_empty::().await } - /// Return a buffered instance of driver without CAN FD support. User must supply Buffers + /// Return a buffered instance of driver. User must supply Buffers pub fn buffered( self, rxb: &'static mut RxBuf, @@ -442,6 +496,14 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE } } +impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { + fn drop(&mut self) { + critical_section::with(|_| unsafe { + T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + }); + } +} + use crate::can::bx::RxFifo; impl<'d, T: Instance> Drop for Can<'d, T> { @@ -568,18 +630,62 @@ impl RxMode { } } } + +enum TxMode { + NonBuffered(AtomicWaker), + Buffered(self::common::ClassicBufferedTxInner), +} + +impl TxMode { + pub fn buffer_free(&self) -> bool { + let tsr = T::regs().tsr().read(); + tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) + || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) + || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) + } + pub fn on_interrupt(&self) { + match &T::state().tx_mode { + TxMode::NonBuffered(waker) => waker.wake(), + TxMode::Buffered(buf) => { + while self.buffer_free::() { + match buf.tx_receiver.try_receive() { + Ok(frame) => { + let mut registers = crate::can::bx::Registers { canregs: T::regs() }; + _ = registers.transmit(&frame); + } + Err(_) => { + break; + } + } + } + } + } + } + + fn register(&self, arg: &core::task::Waker) { + match self { + TxMode::NonBuffered(waker) => { + waker.register(arg); + } + _ => { + panic!("Bad mode"); + } + } + } +} + struct State { - pub tx_waker: AtomicWaker, - pub err_waker: AtomicWaker, pub(crate) rx_mode: RxMode, + pub(crate) tx_mode: TxMode, + pub err_waker: AtomicWaker, } impl State { pub const fn new() -> Self { Self { - tx_waker: AtomicWaker::new(), - err_waker: AtomicWaker::new(), rx_mode: RxMode::NonBuffered(AtomicWaker::new()), + tx_mode: TxMode::NonBuffered(AtomicWaker::new()), + err_waker: AtomicWaker::new(), } } } diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 42c9bd9f6..e58d8c0ec 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -507,7 +507,7 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF /// Sender that can be used for sending CAN frames. #[derive(Copy, Clone)] pub struct BufferedFdCanSender { - tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>, + tx_buf: DynamicSender<'static, FdFrame>, waker: fn(), } @@ -532,8 +532,7 @@ impl BufferedFdCanSender { } /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. -pub type BufferedFdCanReceiver = - embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>; +pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>; impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> From f5daa50a7baceb44f2aad44bf6ce055bccb08433 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 24 Mar 2024 14:15:46 +1000 Subject: [PATCH 754/760] BXCAN: Add struct that combines Buffered RX and Buffered TX. --- embassy-stm32/src/can/bxcan.rs | 55 +++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 45a3836c0..be2e34963 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -236,6 +236,19 @@ impl<'d, T: Instance> Can<'d, T> { let (tx, rx) = self.can.split_by_ref(); (CanTx { tx }, CanRx { rx }) } + + /// Return a buffered instance of driver. User must supply Buffers + pub fn buffered<'c, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( + &'c mut self, + txb: &'static mut TxBuf, + rxb: &'static mut RxBuf, + ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { + let (tx, rx) = self.split(); + BufferedCan { + tx: tx.buffered(txb), + rx: rx.buffered(rxb), + } + } } impl<'d, T: Instance> AsMut>> for Can<'d, T> { @@ -245,6 +258,46 @@ impl<'d, T: Instance> AsMut>> for Can<' } } +/// Buffered CAN driver. +pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { + tx: BufferedCanTx<'d, T, TX_BUF_SIZE>, + rx: BufferedCanRx<'d, T, RX_BUF_SIZE>, +} + +impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: &Frame) { + self.tx.write(frame).await + } + + /// Returns a sender that can be used for sending CAN frames. + pub fn writer(&self) -> BufferedCanSender { + self.tx.writer() + } + + /// Async read frame from RX buffer. + pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> { + self.rx.read().await + } + + /// Attempts to read a CAN frame without blocking. + /// + /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. + pub fn try_read(&mut self) -> Result { + self.rx.try_read() + } + + /// Waits while receive queue is empty. + pub async fn wait_not_empty(&mut self) { + self.rx.wait_not_empty().await + } + + /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. + pub fn reader(&self) -> BufferedCanReceiver { + self.rx.reader() + } +} + /// CAN driver, transmit half. pub struct CanTx<'d, T: Instance> { tx: crate::can::bx::Tx>, @@ -346,7 +399,7 @@ impl<'d, T: Instance> CanTx<'d, T> { /// User supplied buffer for TX buffering pub type TxBuf = Channel; -/// CAN driver, transmit half. +/// Buffered CAN driver, transmit half. pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { _tx: crate::can::bx::Tx>, tx_buf: &'static TxBuf, From 2217b802781b5f2188b4da659aca47f9d89ee032 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 24 Mar 2024 15:13:55 +1000 Subject: [PATCH 755/760] CAN: Unify API's between BXCAN and FDCAN. Use Envelope for all read methods instead of a tuple sometimes. --- embassy-stm32/src/can/bx/mod.rs | 5 +- embassy-stm32/src/can/bxcan.rs | 27 ++--- embassy-stm32/src/can/common.rs | 23 ++-- embassy-stm32/src/can/fd/peripheral.rs | 12 +-- embassy-stm32/src/can/fdcan.rs | 140 ++++++++++++++++--------- embassy-stm32/src/can/frame.rs | 60 +++++++++-- examples/stm32f1/Cargo.toml | 1 + examples/stm32f1/src/bin/can.rs | 100 +++++++++++++++--- examples/stm32g4/src/bin/can.rs | 29 ++--- examples/stm32h5/src/bin/can.rs | 12 ++- examples/stm32h7/src/bin/can.rs | 12 ++- tests/stm32/src/bin/fdcan.rs | 24 ++--- 12 files changed, 294 insertions(+), 151 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index c508ef2fe..253bcee13 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -40,12 +40,11 @@ pub type Header = crate::can::frame::Header; /// Data for a CAN Frame pub type Data = crate::can::frame::ClassicData; -/// CAN Frame -pub type Frame = crate::can::frame::ClassicFrame; - use crate::can::_version::Envelope; use crate::can::bx::filter::MasterFilters; use crate::can::enums::BusError; +/// CAN Frame +pub use crate::can::frame::Frame; use crate::pac::can::vals::Lec; #[derive(Debug, Copy, Clone, Eq, PartialEq)] diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index be2e34963..fd6a79092 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -19,22 +19,10 @@ use crate::{interrupt, peripherals, Peripheral}; pub mod enums; pub mod frame; pub mod util; +pub use frame::Envelope; mod common; -pub use self::common::{BufferedCanReceiver, BufferedCanSender, Timestamp}; - -/// Contains CAN frame and additional metadata. -/// -/// Timestamp is available if `time` feature is enabled. -#[derive(Debug, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Envelope { - /// Reception time. - #[cfg(feature = "time")] - pub ts: embassy_time::Instant, - /// The actual CAN frame. - pub frame: Frame, -} +pub use self::common::{BufferedCanReceiver, BufferedCanSender}; /// Interrupt handler. pub struct TxInterruptHandler { @@ -276,7 +264,7 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer } /// Async read frame from RX buffer. - pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> { + pub async fn read(&mut self) -> Result { self.rx.read().await } @@ -482,8 +470,7 @@ impl<'d, T: Instance> CanRx<'d, T> { } /// User supplied buffer for RX Buffering -pub type RxBuf = - Channel, BUF_SIZE>; +pub type RxBuf = Channel, BUF_SIZE>; /// CAN driver, receive half in Buffered mode. pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { @@ -508,7 +495,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE } /// Async read frame from RX buffer. - pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> { + pub async fn read(&mut self) -> Result { self.rx_buf.receive().await } @@ -520,7 +507,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE RxMode::Buffered(_) => { if let Ok(result) = self.rx_buf.try_receive() { match result { - Ok((frame, ts)) => Ok(Envelope { ts, frame }), + Ok(envelope) => Ok(envelope), Err(e) => Err(TryReadError::BusError(e)), } } else { @@ -610,7 +597,7 @@ impl RxMode { match regsisters.receive_fifo(fifo) { Some(envelope) => { // NOTE: consensus was reached that if rx_queue is full, packets should be dropped - let _ = buf.rx_sender.try_send(Ok((envelope.frame, envelope.ts))); + let _ = buf.rx_sender.try_send(Ok(envelope)); } None => return, }; diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index b0d177a6d..570761b19 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -3,25 +3,17 @@ use embassy_sync::channel::{DynamicReceiver, DynamicSender}; use crate::can::_version::enums::*; use crate::can::_version::frame::*; -/// Timestamp for incoming packets. Use Embassy time when enabled. -#[cfg(feature = "time")] -pub type Timestamp = embassy_time::Instant; - -/// Timestamp for incoming packets. -#[cfg(not(feature = "time"))] -pub type Timestamp = u16; - pub(crate) struct ClassicBufferedRxInner { - pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, + pub rx_sender: DynamicSender<'static, Result>, } pub(crate) struct ClassicBufferedTxInner { - pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, + pub tx_receiver: DynamicReceiver<'static, Frame>, } #[cfg(any(can_fdcan_v1, can_fdcan_h7))] pub(crate) struct FdBufferedRxInner { - pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, + pub rx_sender: DynamicSender<'static, Result>, } #[cfg(any(can_fdcan_v1, can_fdcan_h7))] @@ -32,20 +24,20 @@ pub(crate) struct FdBufferedTxInner { /// Sender that can be used for sending CAN frames. #[derive(Copy, Clone)] pub struct BufferedCanSender { - pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>, + pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>, pub(crate) waker: fn(), } impl BufferedCanSender { /// Async write frame to TX buffer. - pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError> { + pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError> { self.tx_buf.try_send(frame)?; (self.waker)(); Ok(()) } /// Async write frame to TX buffer. - pub async fn write(&mut self, frame: ClassicFrame) { + pub async fn write(&mut self, frame: Frame) { self.tx_buf.send(frame).await; (self.waker)(); } @@ -57,5 +49,4 @@ impl BufferedCanSender { } /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. -pub type BufferedCanReceiver = - embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; +pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result>; diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 76b76afe1..e32f19d91 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -397,13 +397,13 @@ impl Registers { /// Moves out of ConfigMode and into specified mode #[inline] - pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) { + pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) { match mode { - crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), - crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), - crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true), - crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), - crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), + crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), + crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), + crate::can::OperatingMode::NormalOperationMode => self.set_normal_operations(true), + crate::can::OperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), + crate::can::OperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), } self.leave_init_mode(config); } diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index e58d8c0ec..2ccf4b093 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -110,7 +110,7 @@ impl interrupt::typelevel::Handler for IT1Interrup #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// Different operating modes -pub enum FdcanOperatingMode { +pub enum OperatingMode { //PoweredDownMode, //ConfigMode, /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without @@ -148,7 +148,7 @@ pub enum FdcanOperatingMode { /// FDCAN Configuration instance instance /// Create instance of this first -pub struct FdcanConfigurator<'d, T: Instance> { +pub struct CanConfigurator<'d, T: Instance> { config: crate::can::fd::config::FdCanConfig, /// Reference to internals. instance: FdcanInstance<'d, T>, @@ -169,7 +169,7 @@ fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransm } } -impl<'d, T: Instance> FdcanConfigurator<'d, T> { +impl<'d, T: Instance> CanConfigurator<'d, T> { /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. /// You must call [Fdcan::enable_non_blocking] to use the peripheral. pub fn new( @@ -179,7 +179,7 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { _irqs: impl interrupt::typelevel::Binding> + interrupt::typelevel::Binding> + 'd, - ) -> FdcanConfigurator<'d, T> { + ) -> CanConfigurator<'d, T> { into_ref!(peri, rx, tx); rx.set_as_af(rx.af_num(), AFType::Input); @@ -273,13 +273,13 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { } /// Start in mode. - pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> { + pub fn start(self, mode: OperatingMode) -> Can<'d, T> { let ns_per_timer_tick = calc_ns_per_timer_tick::(self.config.frame_transmit); critical_section::with(|_| unsafe { T::mut_state().ns_per_timer_tick = ns_per_timer_tick; }); T::registers().into_mode(self.config, mode); - let ret = Fdcan { + let ret = Can { config: self.config, instance: self.instance, _mode: mode, @@ -288,30 +288,30 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { } /// Start, entering mode. Does same as start(mode) - pub fn into_normal_mode(self) -> Fdcan<'d, T> { - self.start(FdcanOperatingMode::NormalOperationMode) + pub fn into_normal_mode(self) -> Can<'d, T> { + self.start(OperatingMode::NormalOperationMode) } /// Start, entering mode. Does same as start(mode) - pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> { - self.start(FdcanOperatingMode::InternalLoopbackMode) + pub fn into_internal_loopback_mode(self) -> Can<'d, T> { + self.start(OperatingMode::InternalLoopbackMode) } /// Start, entering mode. Does same as start(mode) - pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> { - self.start(FdcanOperatingMode::ExternalLoopbackMode) + pub fn into_external_loopback_mode(self) -> Can<'d, T> { + self.start(OperatingMode::ExternalLoopbackMode) } } /// FDCAN Instance -pub struct Fdcan<'d, T: Instance> { +pub struct Can<'d, T: Instance> { config: crate::can::fd::config::FdCanConfig, /// Reference to internals. instance: FdcanInstance<'d, T>, - _mode: FdcanOperatingMode, + _mode: OperatingMode, } -impl<'d, T: Instance> Fdcan<'d, T> { +impl<'d, T: Instance> Can<'d, T> { /// Flush one of the TX mailboxes. pub async fn flush(&self, idx: usize) { poll_fn(|cx| { @@ -334,12 +334,12 @@ impl<'d, T: Instance> Fdcan<'d, T> { /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. - pub async fn write(&mut self, frame: &ClassicFrame) -> Option { + pub async fn write(&mut self, frame: &Frame) -> Option { T::state().tx_mode.write::(frame).await } /// Returns the next received message frame - pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { + pub async fn read(&mut self) -> Result { T::state().rx_mode.read_classic::().await } @@ -352,19 +352,19 @@ impl<'d, T: Instance> Fdcan<'d, T> { } /// Returns the next received message frame - pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { + pub async fn read_fd(&mut self) -> Result { T::state().rx_mode.read_fd::().await } /// Split instance into separate Tx(write) and Rx(read) portions - pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) { + pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) { ( - FdcanTx { + CanTx { config: self.config, _instance: self.instance, _mode: self._mode, }, - FdcanRx { + CanRx { _instance1: PhantomData::, _instance2: T::regs(), _mode: self._mode, @@ -373,8 +373,8 @@ impl<'d, T: Instance> Fdcan<'d, T> { } /// Join split rx and tx portions back together - pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self { - Fdcan { + pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self { + Can { config: tx.config, //_instance2: T::regs(), instance: tx._instance, @@ -402,17 +402,16 @@ impl<'d, T: Instance> Fdcan<'d, T> { } /// User supplied buffer for RX Buffering -pub type RxBuf = - Channel, BUF_SIZE>; +pub type RxBuf = Channel, BUF_SIZE>; /// User supplied buffer for TX buffering -pub type TxBuf = Channel; +pub type TxBuf = Channel; /// Buffered FDCAN Instance pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: FdcanOperatingMode, + _mode: OperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, } @@ -423,7 +422,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> fn new( _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: FdcanOperatingMode, + _mode: OperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, ) -> Self { @@ -453,13 +452,13 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> } /// Async write frame to TX buffer. - pub async fn write(&mut self, frame: ClassicFrame) { + pub async fn write(&mut self, frame: Frame) { self.tx_buf.send(frame).await; T::IT0Interrupt::pend(); // Wake for Tx } /// Async read frame from RX buffer. - pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { + pub async fn read(&mut self) -> Result { self.rx_buf.receive().await } @@ -489,8 +488,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr } /// User supplied buffer for RX Buffering -pub type RxFdBuf = - Channel, BUF_SIZE>; +pub type RxFdBuf = Channel, BUF_SIZE>; /// User supplied buffer for TX buffering pub type TxFdBuf = Channel; @@ -499,7 +497,7 @@ pub type TxFdBuf = Channel { _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: FdcanOperatingMode, + _mode: OperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, } @@ -532,7 +530,7 @@ impl BufferedFdCanSender { } /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. -pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>; +pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result>; impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> @@ -540,7 +538,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> fn new( _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: FdcanOperatingMode, + _mode: OperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, ) -> Self { @@ -576,7 +574,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> } /// Async read frame from RX buffer. - pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> { + pub async fn read(&mut self) -> Result { self.rx_buf.receive().await } @@ -606,25 +604,25 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr } /// FDCAN Rx only Instance -pub struct FdcanRx<'d, T: Instance> { +pub struct CanRx<'d, T: Instance> { _instance1: PhantomData, _instance2: &'d crate::pac::can::Fdcan, - _mode: FdcanOperatingMode, + _mode: OperatingMode, } /// FDCAN Tx only Instance -pub struct FdcanTx<'d, T: Instance> { +pub struct CanTx<'d, T: Instance> { config: crate::can::fd::config::FdCanConfig, _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); - _mode: FdcanOperatingMode, + _mode: OperatingMode, } -impl<'c, 'd, T: Instance> FdcanTx<'d, T> { +impl<'c, 'd, T: Instance> CanTx<'d, T> { /// Queues the message to be sent but exerts backpressure. If a lower-priority /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. - pub async fn write(&mut self, frame: &ClassicFrame) -> Option { + pub async fn write(&mut self, frame: &Frame) -> Option { T::state().tx_mode.write::(frame).await } @@ -637,14 +635,14 @@ impl<'c, 'd, T: Instance> FdcanTx<'d, T> { } } -impl<'c, 'd, T: Instance> FdcanRx<'d, T> { +impl<'c, 'd, T: Instance> CanRx<'d, T> { /// Returns the next received message frame - pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { + pub async fn read(&mut self) -> Result { T::state().rx_mode.read_classic::().await } /// Returns the next received message frame - pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { + pub async fn read_fd(&mut self) -> Result { T::state().rx_mode.read_fd::().await } } @@ -672,18 +670,50 @@ impl RxMode { waker.wake(); } RxMode::ClassicBuffered(buf) => { - if let Some(result) = self.read::() { + if let Some(result) = self.try_read::() { let _ = buf.rx_sender.try_send(result); } } RxMode::FdBuffered(buf) => { - if let Some(result) = self.read::() { + if let Some(result) = self.try_read_fd::() { let _ = buf.rx_sender.try_send(result); } } } } + //async fn read_classic(&self) -> Result { + fn try_read(&self) -> Option> { + if let Some((frame, ts)) = T::registers().read(0) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + Some(Ok(Envelope { ts, frame })) + } else if let Some((frame, ts)) = T::registers().read(1) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + Some(Ok(Envelope { ts, frame })) + } else if let Some(err) = T::registers().curr_error() { + // TODO: this is probably wrong + Some(Err(err)) + } else { + None + } + } + + //async fn read_classic(&self) -> Result { + fn try_read_fd(&self) -> Option> { + if let Some((frame, ts)) = T::registers().read(0) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + Some(Ok(FdEnvelope { ts, frame })) + } else if let Some((frame, ts)) = T::registers().read(1) { + let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + Some(Ok(FdEnvelope { ts, frame })) + } else if let Some(err) = T::registers().curr_error() { + // TODO: this is probably wrong + Some(Err(err)) + } else { + None + } + } + fn read(&self) -> Option> { if let Some((msg, ts)) = T::registers().read(0) { let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); @@ -711,12 +741,18 @@ impl RxMode { .await } - async fn read_classic(&self) -> Result<(ClassicFrame, Timestamp), BusError> { - self.read_async::().await + async fn read_classic(&self) -> Result { + match self.read_async::().await { + Ok((frame, ts)) => Ok(Envelope { ts, frame }), + Err(e) => Err(e), + } } - async fn read_fd(&self) -> Result<(FdFrame, Timestamp), BusError> { - self.read_async::().await + async fn read_fd(&self) -> Result { + match self.read_async::().await { + Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }), + Err(e) => Err(e), + } } } @@ -761,7 +797,7 @@ impl TxMode { /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. - async fn write(&self, frame: &ClassicFrame) -> Option { + async fn write(&self, frame: &Frame) -> Option { self.write_generic::(frame).await } diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index 14fc32c51..fb032aee2 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -136,19 +136,20 @@ impl ClassicData { } } -/// Frame with up to 8 bytes of data payload as per Classic CAN +/// Frame with up to 8 bytes of data payload as per Classic(non-FD) CAN +/// For CAN-FD support use FdFrame #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ClassicFrame { +pub struct Frame { can_header: Header, data: ClassicData, } -impl ClassicFrame { +impl Frame { /// Create a new CAN classic Frame pub fn new(can_header: Header, raw_data: &[u8]) -> Result { let data = ClassicData::new(raw_data)?; - Ok(ClassicFrame { can_header, data: data }) + Ok(Frame { can_header, data: data }) } /// Creates a new data frame. @@ -206,9 +207,9 @@ impl ClassicFrame { } } -impl embedded_can::Frame for ClassicFrame { +impl embedded_can::Frame for Frame { fn new(id: impl Into, raw_data: &[u8]) -> Option { - let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data); + let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data); match frameopt { Ok(frame) => Some(frame), Err(_) => None, @@ -216,7 +217,7 @@ impl embedded_can::Frame for ClassicFrame { } fn new_remote(id: impl Into, len: usize) -> Option { if len <= 8 { - let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]); + let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]); match frameopt { Ok(frame) => Some(frame), Err(_) => None, @@ -245,7 +246,7 @@ impl embedded_can::Frame for ClassicFrame { } } -impl CanHeader for ClassicFrame { +impl CanHeader for Frame { fn from_header(header: Header, data: &[u8]) -> Result { Self::new(header, data) } @@ -255,10 +256,32 @@ impl CanHeader for ClassicFrame { } } +/// Contains CAN frame and additional metadata. +/// +/// Timestamp is available if `time` feature is enabled. +/// For CAN-FD support use FdEnvelope +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Envelope { + /// Reception time. + #[cfg(feature = "time")] + pub ts: embassy_time::Instant, + /// The actual CAN frame. + pub frame: Frame, +} + +impl Envelope { + /// Convert into a tuple + pub fn parts(self) -> (Frame, embassy_time::Instant) { + (self.frame, self.ts) + } +} + /// Payload of a (FD)CAN data frame. /// /// Contains 0 to 64 Bytes of data. #[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FdData { pub(crate) bytes: [u8; 64], } @@ -308,6 +331,7 @@ impl FdData { /// Frame with up to 8 bytes of data payload as per Fd CAN #[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FdFrame { can_header: Header, data: FdData, @@ -410,3 +434,23 @@ impl CanHeader for FdFrame { self.header() } } + +/// Contains CAN FD frame and additional metadata. +/// +/// Timestamp is available if `time` feature is enabled. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct FdEnvelope { + /// Reception time. + #[cfg(feature = "time")] + pub ts: embassy_time::Instant, + /// The actual CAN frame. + pub frame: FdFrame, +} + +impl FdEnvelope { + /// Convert into a tuple + pub fn parts(self) -> (FdFrame, embassy_time::Instant) { + (self.frame, self.ts) + } +} diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index df5d32f70..4f282f326 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -23,6 +23,7 @@ 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 } nb = "1.0.0" +static_cell = "2.0.0" [profile.dev] opt-level = "s" diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index ac337e8a0..90cb9e46b 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -4,11 +4,12 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::can::{ - filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, + filter, Can, Envelope, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler, }; use embassy_stm32::peripherals::CAN; use embassy_stm32::{bind_interrupts, Config}; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -21,6 +22,27 @@ bind_interrupts!(struct Irqs { // This example is configured to work with real CAN transceivers on B8/B9. // See other examples for loopback. +fn handle_frame(env: Envelope, read_mode: &str) { + match env.frame.id() { + Id::Extended(id) => { + defmt::println!( + "{} Extended Frame id={:x} {:02x}", + read_mode, + id.as_raw(), + env.frame.data() + ); + } + Id::Standard(id) => { + defmt::println!( + "{} Standard Frame id={:x} {:02x}", + read_mode, + id.as_raw(), + env.frame.data() + ); + } + } +} + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Config::default()); @@ -28,6 +50,9 @@ async fn main(_spawner: Spawner) { // Set alternate pin mapping to B8/B9 embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); + static RX_BUF: StaticCell> = StaticCell::new(); + static TX_BUF: StaticCell> = StaticCell::new(); + let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); can.as_mut() @@ -43,21 +68,72 @@ async fn main(_spawner: Spawner) { can.set_bitrate(250_000); can.enable().await; - let mut i: u8 = 0; + + /* + // Example for using buffered Tx and Rx without needing to + // split first as is done below. + let mut can = can.buffered( + TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()), + RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new())); + loop { + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); + can.write(&tx_frame).await; + + match can.read().await { + Ok((frame, ts)) => { + handle_frame(Envelope { ts, frame }, "Buf"); + } + Err(err) => { + defmt::println!("Error {}", err); + } + } + i += 1; + } + + */ + let (mut tx, mut rx) = can.split(); + + // This example shows using the wait_not_empty API before try read + while i < 3 { + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); + tx.write(&tx_frame).await; + + rx.wait_not_empty().await; + let env = rx.try_read().unwrap(); + handle_frame(env, "Wait"); + i += 1; + } + + // This example shows using the full async non-buffered API + while i < 6 { + let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); + tx.write(&tx_frame).await; + + match rx.read().await { + Ok(env) => { + handle_frame(env, "NoBuf"); + } + Err(err) => { + defmt::println!("Error {}", err); + } + } + i += 1; + } + + // This example shows using buffered RX and TX. User passes in desired buffer (size) + // It's possible this way to have just RX or TX buffered. + let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new())); + let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new())); + loop { let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); - can.write(&tx_frame).await; + tx.write(&tx_frame).await; - match can.read().await { - Ok(env) => match env.frame.id() { - Id::Extended(id) => { - defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data()); - } - Id::Standard(id) => { - defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data()); - } - }, + match rx.read().await { + Ok(envelope) => { + handle_frame(envelope, "Buf"); + } Err(err) => { defmt::println!("Error {}", err); } diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 4373a89a8..2ed632a93 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) { } let peripherals = embassy_stm32::init(config); - let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); can.set_extended_filter( can::filter::ExtendedFilterSlot::_0, @@ -56,21 +56,22 @@ async fn main(_spawner: Spawner) { info!("Configured"); let mut can = can.start(match use_fd { - true => can::FdcanOperatingMode::InternalLoopbackMode, - false => can::FdcanOperatingMode::NormalOperationMode, + true => can::OperatingMode::InternalLoopbackMode, + false => can::OperatingMode::NormalOperationMode, }); let mut i = 0; let mut last_read_ts = embassy_time::Instant::now(); loop { - let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); _ = can.write(&frame).await; match can.read().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (ts, rx_frame) = (envelope.ts, envelope.frame); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( @@ -105,7 +106,8 @@ async fn main(_spawner: Spawner) { } match can.read_fd().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (ts, rx_frame) = (envelope.ts, envelope.frame); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( @@ -129,12 +131,13 @@ async fn main(_spawner: Spawner) { let (mut tx, mut rx) = can.split(); // With split loop { - let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); _ = tx.write(&frame).await; match rx.read().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (ts, rx_frame) = (envelope.ts, envelope.frame); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( @@ -156,7 +159,7 @@ async fn main(_spawner: Spawner) { } } - let can = can::Fdcan::join(tx, rx); + let can = can::Can::join(tx, rx); info!("\n\n\nBuffered\n"); if use_fd { @@ -173,7 +176,8 @@ async fn main(_spawner: Spawner) { _ = can.write(frame).await; match can.read().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (ts, rx_frame) = (envelope.ts, envelope.frame); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( @@ -198,7 +202,7 @@ async fn main(_spawner: Spawner) { RX_BUF.init(can::RxBuf::<10>::new()), ); loop { - let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); // You can use any of these approaches to send. The writer makes it @@ -208,7 +212,8 @@ async fn main(_spawner: Spawner) { can.writer().write(frame).await; match can.read().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (ts, rx_frame) = (envelope.ts, envelope.frame); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index 643df27f9..dd625c90a 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { let peripherals = embassy_stm32::init(config); - let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); // 250k bps can.set_bitrate(250_000); @@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) { let mut last_read_ts = embassy_time::Instant::now(); loop { - let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); _ = can.write(&frame).await; match can.read().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (rx_frame, ts) = envelope.parts(); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( @@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) { let (mut tx, mut rx) = can.split(); // With split loop { - let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); _ = tx.write(&frame).await; match rx.read().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (rx_frame, ts) = envelope.parts(); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 13a6a5051..22cb27481 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { let peripherals = embassy_stm32::init(config); - let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); // 250k bps can.set_bitrate(250_000); @@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) { let mut last_read_ts = embassy_time::Instant::now(); loop { - let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); _ = can.write(&frame).await; match can.read().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (rx_frame, ts) = envelope.parts(); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( @@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) { let (mut tx, mut rx) = can.split(); // With split loop { - let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); _ = tx.write(&frame).await; match rx.read().await { - Ok((rx_frame, ts)) => { + Ok(envelope) => { + let (rx_frame, ts) = envelope.parts(); let delta = (ts - last_read_ts).as_millis(); last_read_ts = ts; info!( diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index c7373e294..bddfa7684 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -79,8 +79,8 @@ async fn main(_spawner: Spawner) { let options = options(); let peripherals = embassy_stm32::init(options.config); - let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); - let mut can2 = can::FdcanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); + let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); + let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); // 250k bps can.set_bitrate(250_000); @@ -102,13 +102,13 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); + let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); info!("Transmitting frame..."); let tx_ts = Instant::now(); can.write(&tx_frame).await; - let (frame, timestamp) = can.read().await.unwrap(); + let (frame, timestamp) = can.read().await.unwrap().parts(); info!("Frame received!"); // Check data. @@ -139,13 +139,13 @@ async fn main(_spawner: Spawner) { let mut i: u8 = 0; loop { - let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); + let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); info!("Transmitting frame..."); let tx_ts = Instant::now(); can2.write(&tx_frame).await; - let (frame, timestamp) = can2.read().await.unwrap(); + let (frame, timestamp) = can2.read().await.unwrap().parts(); info!("Frame received!"); //print_regs().await; @@ -182,20 +182,20 @@ async fn main(_spawner: Spawner) { // in each FIFO so make sure we write enough to fill them both up before reading. for i in 0..3 { // Try filling up the RX FIFO0 buffers with standard packets - let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); + let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); info!("Transmitting frame {}", i); can.write(&tx_frame).await; } for i in 3..max_buffered { // Try filling up the RX FIFO0 buffers with extended packets - let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); + let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap(); info!("Transmitting frame {}", i); can.write(&tx_frame).await; } // Try and receive all 6 packets for i in 0..max_buffered { - let (frame, _ts) = can.read().await.unwrap(); + let (frame, _ts) = can.read().await.unwrap().parts(); match frame.id() { embedded_can::Id::Extended(id) => { info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); @@ -210,20 +210,20 @@ async fn main(_spawner: Spawner) { let (mut tx, mut rx) = can.split(); for i in 0..3 { // Try filling up the RX FIFO0 buffers with standard packets - let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); + let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); info!("Transmitting frame {}", i); tx.write(&tx_frame).await; } for i in 3..max_buffered { // Try filling up the RX FIFO0 buffers with extended packets - let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); + let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap(); info!("Transmitting frame {}", i); tx.write(&tx_frame).await; } // Try and receive all 6 packets for i in 0..max_buffered { - let (frame, _ts) = rx.read().await.unwrap(); + let (frame, _ts) = rx.read().await.unwrap().parts(); match frame.id() { embedded_can::Id::Extended(id) => { info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); From 8d43fb4da4712dd9bb5a2ae343168e536c2b3129 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Wed, 27 Mar 2024 19:43:19 +1000 Subject: [PATCH 756/760] CAN: Use the same testing code for BXCAN and FDCAN h/w. --- tests/stm32/src/bin/can.rs | 50 +++----- tests/stm32/src/bin/can_common.rs | 112 +++++++++++++++++ tests/stm32/src/bin/fdcan.rs | 195 ++++++------------------------ 3 files changed, 163 insertions(+), 194 deletions(-) create mode 100644 tests/stm32/src/bin/can_common.rs diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index c08c69a3b..74d84c42f 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -6,17 +6,19 @@ #[path = "../common.rs"] mod common; use common::*; -use defmt::assert; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::can::bx::filter::Mask32; -use embassy_stm32::can::bx::{Fifo, Frame, StandardId}; +use embassy_stm32::can::bx::Fifo; use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN1; -use embassy_time::{Duration, Instant}; +use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; +mod can_common; +use can_common::*; + bind_interrupts!(struct Irqs { CAN1_RX0 => Rx0InterruptHandler; CAN1_RX1 => Rx1InterruptHandler; @@ -29,6 +31,11 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config()); info!("Hello World!"); + let options = TestOptions { + max_latency: Duration::from_micros(1200), + max_buffered: 2, + }; + let can = peri!(p, CAN); let tx = peri!(p, CAN_TX); let mut rx = peri!(p, CAN_RX); @@ -58,40 +65,13 @@ async fn main(_spawner: Spawner) { info!("Can configured"); - let mut i: u8 = 0; - loop { - let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap(); + run_can_tests(&mut can, &options).await; - info!("Transmitting frame..."); - let tx_ts = Instant::now(); - can.write(&tx_frame).await; - - let envelope = can.read().await.unwrap(); - info!("Frame received!"); - - info!("loopback time {}", envelope.ts); - info!("loopback frame {=u8}", envelope.frame.data()[0]); - - let latency = envelope.ts.saturating_duration_since(tx_ts); - info!("loopback latency {} us", latency.as_micros()); - - // Theoretical minimum latency is 55us, actual is usually ~80us - const MIN_LATENCY: Duration = Duration::from_micros(50); - const MAX_LATENCY: Duration = Duration::from_micros(150); - assert!( - MIN_LATENCY <= latency && latency <= MAX_LATENCY, - "{} <= {} <= {}", - MIN_LATENCY, - latency, - MAX_LATENCY - ); - - i += 1; - if i > 10 { - break; - } - } + // Test again with a split + let (mut tx, mut rx) = can.split(); + run_split_can_tests(&mut tx, &mut rx, &options).await; info!("Test OK"); + cortex_m::asm::bkpt(); } diff --git a/tests/stm32/src/bin/can_common.rs b/tests/stm32/src/bin/can_common.rs new file mode 100644 index 000000000..4b39269cc --- /dev/null +++ b/tests/stm32/src/bin/can_common.rs @@ -0,0 +1,112 @@ +use defmt::{assert, *}; +use embassy_stm32::can; +use embassy_time::{Duration, Instant}; + +#[derive(Clone, Copy, Debug)] +pub struct TestOptions { + pub max_latency: Duration, + pub max_buffered: u8, +} + +pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) { + let mut i: u8 = 0; + loop { + //let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap(); + let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); + + //info!("Transmitting frame..."); + let tx_ts = Instant::now(); + can.write(&tx_frame).await; + + let (frame, timestamp) = can.read().await.unwrap().parts(); + //info!("Frame received!"); + + // Check data. + assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); + + //info!("loopback time {}", timestamp); + //info!("loopback frame {=u8}", frame.data()[0]); + let latency = timestamp.saturating_duration_since(tx_ts); + info!("loopback latency {} us", latency.as_micros()); + + // Theoretical minimum latency is 55us, actual is usually ~80us + const MIN_LATENCY: Duration = Duration::from_micros(50); + // Was failing at 150 but we are not getting a real time stamp. I'm not + // sure if there are other delays + assert!( + MIN_LATENCY <= latency && latency <= options.max_latency, + "{} <= {} <= {}", + MIN_LATENCY, + latency, + options.max_latency + ); + + i += 1; + if i > 5 { + break; + } + } + + // Below here, check that we can receive from both FIFO0 and FIFO1 + // Above we configured FIFO1 for extended ID packets. There are only 3 slots + // in each FIFO so make sure we write enough to fill them both up before reading. + for i in 0..options.max_buffered { + // Try filling up the RX FIFO0 buffers + //let tx_frame = if 0 != (i & 0x01) { + let tx_frame = if i < options.max_buffered / 2 { + info!("Transmitting standard frame {}", i); + can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap() + } else { + info!("Transmitting extended frame {}", i); + can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap() + }; + can.write(&tx_frame).await; + } + + // Try and receive all 6 packets + for _i in 0..options.max_buffered { + let (frame, _ts) = can.read().await.unwrap().parts(); + match frame.id() { + embedded_can::Id::Extended(_id) => { + info!("Extended received! {}", frame.data()[0]); + //info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); + } + embedded_can::Id::Standard(_id) => { + info!("Standard received! {}", frame.data()[0]); + //info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); + } + } + } +} + +pub async fn run_split_can_tests<'d, T: can::Instance>( + tx: &mut can::CanTx<'d, T>, + rx: &mut can::CanRx<'d, T>, + options: &TestOptions, +) { + for i in 0..options.max_buffered { + // Try filling up the RX FIFO0 buffers + //let tx_frame = if 0 != (i & 0x01) { + let tx_frame = if i < options.max_buffered / 2 { + info!("Transmitting standard frame {}", i); + can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap() + } else { + info!("Transmitting extended frame {}", i); + can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap() + }; + tx.write(&tx_frame).await; + } + + // Try and receive all 6 packets + for _i in 0..options.max_buffered { + let (frame, _ts) = rx.read().await.unwrap().parts(); + match frame.id() { + embedded_can::Id::Extended(_id) => { + info!("Extended received! {}", frame.data()[0]); + } + embedded_can::Id::Standard(_id) => { + info!("Standard received! {}", frame.data()[0]); + } + } + } +} diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index bddfa7684..27bdd038a 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -6,13 +6,15 @@ #[path = "../common.rs"] mod common; use common::*; -use defmt::assert; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; use embassy_stm32::{bind_interrupts, can, Config}; -use embassy_time::{Duration, Instant}; +use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; +mod can_common; +use can_common::*; + bind_interrupts!(struct Irqs2 { FDCAN2_IT0 => can::IT0InterruptHandler; FDCAN2_IT1 => can::IT1InterruptHandler; @@ -22,14 +24,8 @@ bind_interrupts!(struct Irqs1 { FDCAN1_IT1 => can::IT1InterruptHandler; }); -struct TestOptions { - config: Config, - max_latency: Duration, - second_fifo_working: bool, -} - #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] -fn options() -> TestOptions { +fn options() -> (Config, TestOptions) { use embassy_stm32::rcc; info!("H75 config"); let mut c = config(); @@ -38,15 +34,17 @@ fn options() -> TestOptions { mode: rcc::HseMode::Oscillator, }); c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; - TestOptions { - config: c, - max_latency: Duration::from_micros(1200), - second_fifo_working: false, - } + ( + c, + TestOptions { + max_latency: Duration::from_micros(1200), + max_buffered: 3, + }, + ) } #[cfg(any(feature = "stm32h7a3zi"))] -fn options() -> TestOptions { +fn options() -> (Config, TestOptions) { use embassy_stm32::rcc; info!("H7a config"); let mut c = config(); @@ -55,29 +53,33 @@ fn options() -> TestOptions { mode: rcc::HseMode::Oscillator, }); c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; - TestOptions { - config: c, - max_latency: Duration::from_micros(1200), - second_fifo_working: false, - } + ( + c, + TestOptions { + max_latency: Duration::from_micros(1200), + max_buffered: 3, + }, + ) } #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] -fn options() -> TestOptions { +fn options() -> (Config, TestOptions) { info!("G4 config"); - TestOptions { - config: config(), - max_latency: Duration::from_micros(500), - second_fifo_working: true, - } + ( + config(), + TestOptions { + max_latency: Duration::from_micros(500), + max_buffered: 6, + }, + ) } #[embassy_executor::main] async fn main(_spawner: Spawner) { //let peripherals = embassy_stm32::init(config()); - let options = options(); - let peripherals = embassy_stm32::init(options.config); + let (config, options) = options(); + let peripherals = embassy_stm32::init(config); let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); @@ -98,141 +100,16 @@ async fn main(_spawner: Spawner) { let mut can = can.into_internal_loopback_mode(); let mut can2 = can2.into_internal_loopback_mode(); + run_can_tests(&mut can, &options).await; + run_can_tests(&mut can2, &options).await; + info!("CAN Configured"); - let mut i: u8 = 0; - loop { - let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); - - info!("Transmitting frame..."); - let tx_ts = Instant::now(); - can.write(&tx_frame).await; - - let (frame, timestamp) = can.read().await.unwrap().parts(); - info!("Frame received!"); - - // Check data. - assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); - - info!("loopback time {}", timestamp); - info!("loopback frame {=u8}", frame.data()[0]); - let latency = timestamp.saturating_duration_since(tx_ts); - info!("loopback latency {} us", latency.as_micros()); - - // Theoretical minimum latency is 55us, actual is usually ~80us - const MIN_LATENCY: Duration = Duration::from_micros(50); - // Was failing at 150 but we are not getting a real time stamp. I'm not - // sure if there are other delays - assert!( - MIN_LATENCY <= latency && latency <= options.max_latency, - "{} <= {} <= {}", - MIN_LATENCY, - latency, - options.max_latency - ); - - i += 1; - if i > 10 { - break; - } - } - - let mut i: u8 = 0; - loop { - let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); - - info!("Transmitting frame..."); - let tx_ts = Instant::now(); - can2.write(&tx_frame).await; - - let (frame, timestamp) = can2.read().await.unwrap().parts(); - info!("Frame received!"); - - //print_regs().await; - // Check data. - assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); - - info!("loopback time {}", timestamp); - info!("loopback frame {=u8}", frame.data()[0]); - let latency = timestamp.saturating_duration_since(tx_ts); - info!("loopback latency {} us", latency.as_micros()); - - // Theoretical minimum latency is 55us, actual is usually ~80us - const MIN_LATENCY: Duration = Duration::from_micros(50); - // Was failing at 150 but we are not getting a real time stamp. I'm not - // sure if there are other delays - assert!( - MIN_LATENCY <= latency && latency <= options.max_latency, - "{} <= {} <= {}", - MIN_LATENCY, - latency, - options.max_latency - ); - - i += 1; - if i > 10 { - break; - } - } - - let max_buffered = if options.second_fifo_working { 6 } else { 3 }; - - // Below here, check that we can receive from both FIFO0 and FIFO0 - // Above we configured FIFO1 for extended ID packets. There are only 3 slots - // in each FIFO so make sure we write enough to fill them both up before reading. - for i in 0..3 { - // Try filling up the RX FIFO0 buffers with standard packets - let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); - info!("Transmitting frame {}", i); - can.write(&tx_frame).await; - } - for i in 3..max_buffered { - // Try filling up the RX FIFO0 buffers with extended packets - let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap(); - info!("Transmitting frame {}", i); - can.write(&tx_frame).await; - } - - // Try and receive all 6 packets - for i in 0..max_buffered { - let (frame, _ts) = can.read().await.unwrap().parts(); - match frame.id() { - embedded_can::Id::Extended(id) => { - info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); - } - embedded_can::Id::Standard(id) => { - info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); - } - } - } - // Test again with a split let (mut tx, mut rx) = can.split(); - for i in 0..3 { - // Try filling up the RX FIFO0 buffers with standard packets - let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); - info!("Transmitting frame {}", i); - tx.write(&tx_frame).await; - } - for i in 3..max_buffered { - // Try filling up the RX FIFO0 buffers with extended packets - let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap(); - info!("Transmitting frame {}", i); - tx.write(&tx_frame).await; - } - - // Try and receive all 6 packets - for i in 0..max_buffered { - let (frame, _ts) = rx.read().await.unwrap().parts(); - match frame.id() { - embedded_can::Id::Extended(id) => { - info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); - } - embedded_can::Id::Standard(id) => { - info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); - } - } - } + let (mut tx2, mut rx2) = can2.split(); + run_split_can_tests(&mut tx, &mut rx, &options).await; + run_split_can_tests(&mut tx2, &mut rx2, &options).await; info!("Test OK"); cortex_m::asm::bkpt(); From a9f0c8c3a941684c1a610a72dfb2b925535fc8cd Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Wed, 27 Mar 2024 20:29:28 +1000 Subject: [PATCH 757/760] Fixes for no-time. --- embassy-stm32/src/can/bx/mod.rs | 13 +++++++------ embassy-stm32/src/can/frame.rs | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 253bcee13..cb83799d3 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -622,17 +622,18 @@ impl Registers { let id = (stid << 18) | (exid); embedded_can::ExtendedId::new(id).unwrap().into() }; - let data_len = fifo.rdtr().read().dlc(); + let rdtr = fifo.rdtr().read(); + let data_len = rdtr.dlc(); + + #[cfg(not(feature = "time"))] + let ts = rdtr.time(); + let mut data: [u8; 8] = [0; 8]; data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); - let envelope = Envelope { - #[cfg(feature = "time")] - ts, - frame, - }; + let envelope = Envelope { ts, frame }; rfr.modify(|v| v.set_rfom(true)); diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index fb032aee2..d2d1f7aa6 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -3,6 +3,14 @@ use bit_field::BitField; use crate::can::enums::FrameCreateError; +/// Calculate proper timestamp when available. +#[cfg(feature = "time")] +pub type Timestamp = embassy_time::Instant; + +/// Raw register timestamp +#[cfg(not(feature = "time"))] +pub type Timestamp = u16; + /// CAN Header, without meta data #[derive(Debug, Copy, Clone)] pub struct Header { @@ -264,15 +272,14 @@ impl CanHeader for Frame { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Envelope { /// Reception time. - #[cfg(feature = "time")] - pub ts: embassy_time::Instant, + pub ts: Timestamp, /// The actual CAN frame. pub frame: Frame, } impl Envelope { /// Convert into a tuple - pub fn parts(self) -> (Frame, embassy_time::Instant) { + pub fn parts(self) -> (Frame, Timestamp) { (self.frame, self.ts) } } @@ -442,15 +449,15 @@ impl CanHeader for FdFrame { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FdEnvelope { /// Reception time. - #[cfg(feature = "time")] - pub ts: embassy_time::Instant, + pub ts: Timestamp, + /// The actual CAN frame. pub frame: FdFrame, } impl FdEnvelope { /// Convert into a tuple - pub fn parts(self) -> (FdFrame, embassy_time::Instant) { + pub fn parts(self) -> (FdFrame, Timestamp) { (self.frame, self.ts) } } From 25618cd93d5209d864fa250b2077a59532e0bedf Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 28 Mar 2024 09:47:16 +1000 Subject: [PATCH 758/760] RTR fix. --- embassy-stm32/src/can/bx/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index cb83799d3..cd82148ba 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -624,6 +624,7 @@ impl Registers { }; let rdtr = fifo.rdtr().read(); let data_len = rdtr.dlc(); + let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE; #[cfg(not(feature = "time"))] let ts = rdtr.time(); @@ -632,7 +633,7 @@ impl Registers { data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); - let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); + let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap(); let envelope = Envelope { ts, frame }; rfr.modify(|v| v.set_rfom(true)); From 2ea1040e073a54d2a97f75c7d68d0d9a230d15c8 Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Fri, 22 Mar 2024 08:50:56 +0100 Subject: [PATCH 759/760] Adjusted behavior. --- embassy-time/src/timer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 763bfdeeb..d6d0a46e2 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -190,10 +190,10 @@ impl Ticker { self.expires_at = Instant::now() + self.duration; } - /// Reset the ticker to fire for the next time on the deadline. + /// Reset the ticker at the deadline. /// If the deadline is in the past, the ticker will fire instantly. pub fn reset_at(&mut self, deadline: Instant) { - self.expires_at = deadline; + self.expires_at = deadline + self.duration; } /// Resets the ticker, after the specified duration has passed. From a38cbbdc5974fe31f70bffb4fd1995391e4ff331 Mon Sep 17 00:00:00 2001 From: Alexandru Radovici Date: Sat, 30 Mar 2024 22:36:30 +0200 Subject: [PATCH 760/760] fix typo --- embassy-sync/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/README.md b/embassy-sync/README.md index c2e13799e..2c1c0cf68 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md @@ -5,7 +5,7 @@ An [Embassy](https://embassy.dev) project. Synchronization primitives and data structures with async support: - [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. -- [`PriorityChannel`](channel::priority::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are sifted to the front of the channel. +- [`PriorityChannel`](channel::priority::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. - [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers. - [`Signal`](signal::Signal) - Signalling latest value to a single consumer. - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks.