From 39b58a80af3d5291411e66d24ce09d9726bb472b Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Sun, 16 Nov 2025 20:21:34 +0100 Subject: [PATCH 001/114] changed!: Gate undocumented chip features behind the `undoc-features` Cargo feature (#956) --- README.md | 48 +++++++++++++++---- boards/feather_m4/Cargo.toml | 1 + boards/metro_m4/Cargo.toml | 1 + boards/pygamer/Cargo.toml | 1 + crates.json | 60 ++++++++++++++---------- hal/Cargo.toml | 1 + hal/src/sercom/mod.rs | 24 +++++++--- hal/src/sercom/pad.rs | 14 ++++++ hal/src/sercom/pad/impl_pad_thumbv6m.rs | 21 +++++++-- hal/src/sercom/pad/impl_pad_thumbv7em.rs | 54 +++++++++++++++++---- 10 files changed, 169 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 9362a403667c..4b172ccb9875 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,16 @@ This repository holds various crates that support/enable working with Microchip The Hardware Abstraction Layer (HAL - [![Crates.io](https://img.shields.io/crates/v/atsamd_hal.svg)](https://crates.io/crates/atsamd_hal)) crate encodes a type-safe layer over the raw PACs. This crate implements traits specified by the [embedded-hal](https://github.com/rust-embedded/embedded-hal) project, making it compatible with various drivers in the embedded Rust ecosystem. Cargo features are used to enable support for specific hardware variations and features. Online documentation for commonly-used feature sets is provided: -| Chip family | Documented features | -|:------------|:----------------------------------| -| [samd11c] | samd11c dma defmt async | -| [samd11d] | samd11d dma defmt async | -| [samd21g] | samd21g usb dma defmt async | -| [samd21j] | samd21j usb dma defmt async | -| [samd51g] | samd51g usb sdmmc dma defmt async | -| [samd51j] | samd51j usb sdmmc dma defmt async | -| [samd51n] | samd51n usb sdmmc dma defmt async | -| [samd51p] | samd51p usb sdmmc dma defmt async | +| Chip family | Documented features | +|:------------|:-------------------------------------------------| +| [samd11c] | samd11c dma defmt async undoc-features | +| [samd11d] | samd11d dma defmt async undoc-features | +| [samd21g] | samd21g usb dma defmt async undoc-features | +| [samd21j] | samd21j usb dma defmt async undoc-features | +| [samd51g] | samd51g usb sdmmc dma defmt async undoc-features | +| [samd51j] | samd51j usb sdmmc dma defmt async undoc-features | +| [samd51n] | samd51n usb sdmmc dma defmt async undoc-features | +| [samd51p] | samd51p usb sdmmc dma defmt async undoc-features | [samd11c]: https://atsamd-rs.github.io/atsamd/samd11c/thumbv6m-none-eabi/doc/atsamd_hal/index.html [samd11d]: https://atsamd-rs.github.io/atsamd/samd11d/thumbv6m-none-eabi/doc/atsamd_hal/index.html @@ -153,6 +153,34 @@ If you'd like to build all the same things that the CI would build but on your l $ ./build-all.py ``` +## Undocumented chip features + +Some development board manufacturers, such as Adafruit, sell some boards with pin multiplexing configurations that aren't +explicitly allowed by the datasheet. As a convenience, we offer the option to enable these undocumented features by opting +into the `undoc-features` Cargo feature. Note that even though these have shown to work in at least some situations, we do not +provide any guarantees with respect to those. + +Currently, we provide these features undocumented features: + +### SAMD21: + +* Mark `PA00` as I2C-capable according to `circuit_playground_express`. + +* Mark `PA01` as I2C-capable according to `circuit_playground_express`. + +### SAMx5x devices: +* `UndocIoSet1`: Implement an undocumented `IoSet` for PA16, PA17, PB22 & + PB23 configured for `Sercom1`. The `pygamer` & `feather_m4` use this + combination, but it is not listed as valid in the datasheet. + +* `UndocIoSet2`: Implement an undocumented `IoSet` for PA00, PA01, PB22 & + PB23 configured for `Sercom1`. The `itsybitsy_m4` uses this combination, + but it is not listed as valid in the datasheet. + +* Mark `PB02` as I2C-capable according to `metro_m4`. + +* Mark `PB03` as I2C-capable according to `metro_m4`. + ## Running and debugging firmware on target hardware See our wiki page about [loading code onto the device](https://github.com/atsamd-rs/atsamd/wiki/Loading-code-onto-the-device). diff --git a/boards/feather_m4/Cargo.toml b/boards/feather_m4/Cargo.toml index cb9e61f21f5f..c51484162900 100644 --- a/boards/feather_m4/Cargo.toml +++ b/boards/feather_m4/Cargo.toml @@ -27,6 +27,7 @@ version = "0.7" default-features = false path = "../../hal" version = "0.22.2" +features = ["undoc-features"] [dependencies.usb-device] optional = true diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index 79df242185dc..6d3f4e3bef06 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -22,6 +22,7 @@ version = "0.7" default-features = false path = "../../hal" version = "0.22.2" +features = ["undoc-features"] [dependencies.usb-device] optional = true diff --git a/boards/pygamer/Cargo.toml b/boards/pygamer/Cargo.toml index 4044a6d164ac..a3306f450149 100644 --- a/boards/pygamer/Cargo.toml +++ b/boards/pygamer/Cargo.toml @@ -28,6 +28,7 @@ version = "0.7" default-features = false path = "../../hal" version = "0.22.2" +features = ["undoc-features"] [dependencies.usb-device] optional = true diff --git a/crates.json b/crates.json index ac8230519cbd..c58ab16cbdd8 100644 --- a/crates.json +++ b/crates.json @@ -179,7 +179,8 @@ "samd11c", "dma", "defmt", - "async" + "async", + "undoc-features" ], "target": "thumbv6m-none-eabi" }, @@ -188,7 +189,8 @@ "samd11d", "dma", "defmt", - "async" + "async", + "undoc-features" ], "target": "thumbv6m-none-eabi" }, @@ -198,7 +200,8 @@ "usb", "dma", "defmt", - "async" + "async", + "undoc-features" ], "target": "thumbv6m-none-eabi" }, @@ -208,7 +211,8 @@ "usb", "dma", "defmt", - "async" + "async", + "undoc-features" ], "target": "thumbv6m-none-eabi" }, @@ -219,7 +223,8 @@ "sdmmc", "dma", "defmt", - "async" + "async", + "undoc-features" ], "target": "thumbv7em-none-eabihf" }, @@ -230,7 +235,8 @@ "sdmmc", "dma", "defmt", - "async" + "async", + "undoc-features" ], "target": "thumbv7em-none-eabihf" }, @@ -241,7 +247,8 @@ "sdmmc", "dma", "defmt", - "async" + "async", + "undoc-features" ], "target": "thumbv7em-none-eabihf" }, @@ -252,82 +259,83 @@ "sdmmc", "dma", "defmt", - "async" + "async", + "undoc-features" ], "target": "thumbv7em-none-eabihf" } }, "hal_build_variants": { "samd11c": { - "features": [ "samd11c", "dma", "rtic", "defmt", "async" ], + "features": [ "samd11c", "dma", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv6m-none-eabi" }, "samd11d": { - "features": [ "samd11d", "dma", "rtic", "defmt", "async" ], + "features": [ "samd11d", "dma", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv6m-none-eabi" }, "samd21e": { - "features": [ "samd21e", "usb", "dma", "rtic", "defmt", "async" ], + "features": [ "samd21e", "usb", "dma", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv6m-none-eabi" }, "samd21el": { - "features": [ "samd21el", "dma", "rtic", "defmt", "async" ], + "features": [ "samd21el", "dma", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv6m-none-eabi" }, "samd21g": { - "features": [ "samd21g", "usb", "dma", "rtic", "defmt", "async" ], + "features": [ "samd21g", "usb", "dma", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv6m-none-eabi" }, "samd21gl": { - "features": [ "samd21gl", "dma", "rtic", "defmt", "async" ], + "features": [ "samd21gl", "dma", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv6m-none-eabi" }, "samd21j": { - "features": [ "samd21j", "usb", "dma", "rtic", "defmt", "async" ], + "features": [ "samd21j", "usb", "dma", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv6m-none-eabi" }, "samd51g": { - "features": [ "samd51g", "usb", "dma", "sdmmc", "rtic", "defmt", "async" ], + "features": [ "samd51g", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "samd51j": { - "features": [ "samd51j", "usb", "dma", "sdmmc", "rtic", "defmt", "async" ], + "features": [ "samd51j", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "samd51n": { - "features": [ "samd51n", "usb", "dma", "sdmmc", "rtic", "defmt", "async" ], + "features": [ "samd51n", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "samd51p": { - "features": [ "samd51p", "usb", "dma", "sdmmc", "rtic", "defmt", "async" ], + "features": [ "samd51p", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "same51g": { - "features": [ "same51g", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async" ], + "features": [ "same51g", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "same51j": { - "features": [ "same51j", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async" ], + "features": [ "same51j", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "same51n": { - "features": [ "same51n", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async" ], + "features": [ "same51n", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async" , "undoc-features"], "target": "thumbv7em-none-eabihf" }, "same53j": { - "features": [ "same53j", "usb", "dma", "sdmmc", "rtic", "defmt", "async" ], + "features": [ "same53j", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "same53n": { - "features": [ "same53n", "usb", "dma", "sdmmc", "rtic", "defmt", "async" ], + "features": [ "same53n", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "same54n": { - "features": [ "same54n", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async" ], + "features": [ "same54n", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" }, "same54p": { - "features": [ "same54p", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async" ], + "features": [ "same54p", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async", "undoc-features" ], "target": "thumbv7em-none-eabihf" } } diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 4fa93be1cdb4..16d3037a729a 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -197,6 +197,7 @@ rtic = ["rtic-monotonic", "rtic-time", "portable-atomic"] sdmmc = ["embedded-sdmmc"] usb = ["usb-device"] use_rtt = ["jlink_rtt"] +undoc-features = [] #=============================================================================== # Implementation-details diff --git a/hal/src/sercom/mod.rs b/hal/src/sercom/mod.rs index e606b4b64fe2..507ff986ba32 100644 --- a/hal/src/sercom/mod.rs +++ b/hal/src/sercom/mod.rs @@ -2,25 +2,35 @@ //! //! The SERCOM module is used to configure the SERCOM peripherals as USART, SPI //! or I2C interfaces. +//! //! # Undocumented features //! //! The ATSAMx5x chips contain certain features that aren't documented in the //! datasheet. These features are implemented in the HAL based on //! experimentation with certain boards which have verifiably demonstrated that -//! those features work as intended. +//! those features work as intended. These undocumented features are disabled by +//! default, and can be enabled by enabling the `undoc-features` Cargo feature +//! +//! ## SAMD21: +//! * `PA00` is I2C-capable according to `circuit_playground_express`. As such, +//! `PA00` implements [`IsI2cPad`]. +//! +//! * `PA01` is I2C-capable according to `circuit_playground_express`. As such, +//! PA01 implements [`IsI2cPad`]. //! -//! * [`UndocIoSet1`]: Implement an undocumented `IoSet` for PA16, PA17, PB22 & -//! PB23 configured for [`Sercom1`]. The pygamer & feather_m4 use this +//! ## SAMx5x devices: +//! * `UndocIoSet1`: Implement an undocumented `IoSet` for PA16, PA17, PB22 & +//! PB23 configured for [`Sercom1`]. The `pygamer` & `feather_m4` use this //! combination, but it is not listed as valid in the datasheet. //! -//! * [`UndocIoSet2`]: Implement an undocumented `IoSet` for PA00, PA01, PB22 & -//! PB23 configured for [`Sercom1`]. The itsybitsy_m4 uses this combination, +//! * `UndocIoSet2`: Implement an undocumented `IoSet` for PA00, PA01, PB22 & +//! PB23 configured for [`Sercom1`]. The `itsybitsy_m4` uses this combination, //! but it is not listed as valid in the datasheet. //! -//! * [`PB02`] is I2C-capable according to metro_m4. As such, [`PB02`] +//! * [`PB02`] is I2C-capable according to `metro_m4`. As such, [`PB02`] //! implements [`IsI2cPad`]. //! -//! * [`PB03`] is I2C-capable according to metro_m4. As such, [`PB03`] +//! * [`PB03`] is I2C-capable according to `metro_m4`. As such, [`PB03`] //! implements [`IsI2cPad`]. //! //! [`PB02`]: crate::gpio::pin::PB02 diff --git a/hal/src/sercom/pad.rs b/hal/src/sercom/pad.rs index 6f0a76d55fd5..38ff057a8f14 100644 --- a/hal/src/sercom/pad.rs +++ b/hal/src/sercom/pad.rs @@ -309,6 +309,14 @@ mod ioset { }); // Implement IoSets for NoneT, making it act as a wildcard. + #[cfg(not(feature = "undoc-features"))] + seq!(N in 1..=5 { + impl IoSets for NoneT { + type SetList = mk_hlist! ( #(::Order, )* ::Order ); + } + }); + + #[cfg(feature = "undoc-features")] seq!(N in 1..=6 { impl IoSets for NoneT { type SetList = mk_hlist! ( #(::Order, )* ::Order, ::Order ); @@ -335,8 +343,11 @@ mod ioset { /// variants. /// /// [type-level enum]: crate::typelevel#type-level-enum + #[cfg(feature = "undoc-features")] pub enum UndocIoSet1 {} + #[cfg(feature = "undoc-features")] impl Sealed for UndocIoSet1 {} + #[cfg(feature = "undoc-features")] impl IoSet for UndocIoSet1 { type Order = typenum::U8; } @@ -361,8 +372,11 @@ mod ioset { /// variants. /// /// [type-level enum]: crate::typelevel#type-level-enum + #[cfg(feature = "undoc-features")] pub enum UndocIoSet2 {} + #[cfg(feature = "undoc-features")] impl Sealed for UndocIoSet2 {} + #[cfg(feature = "undoc-features")] impl IoSet for UndocIoSet2 { type Order = typenum::U9; } diff --git a/hal/src/sercom/pad/impl_pad_thumbv6m.rs b/hal/src/sercom/pad/impl_pad_thumbv6m.rs index 72e162a6223e..a7c2e58d02ef 100644 --- a/hal/src/sercom/pad/impl_pad_thumbv6m.rs +++ b/hal/src/sercom/pad/impl_pad_thumbv6m.rs @@ -63,12 +63,13 @@ macro_rules! pad_table { #[$id_cfg:meta] $PinId:ident { $( - $( #[$sercom_cfg:meta] )? + $( #[$sercom_cfg:meta] )* $Cfg:ident: ( $Sercom:ident, $PadNum:ident ) $( + $I2C:ident )?, )+ } ) => { $( + #[$id_cfg] $( #[$sercom_cfg] )? pad_info!( $PinId, $Cfg, $Sercom, $PadNum $( + $I2C )? ); @@ -78,13 +79,13 @@ macro_rules! pad_table { ( $PinId:ident { $( - $( #[$sercom_cfg:meta] )? + $( #[$sercom_cfg:meta] )* $Cfg:ident: ( $Sercom:ident, $PadNum:ident ) $( + $I2C:ident )?, )+ } ) => { $( - $( #[$sercom_cfg] )? + $( #[$sercom_cfg] )* pad_info!( $PinId, $Cfg, $Sercom, $PadNum $( + $I2C )? ); )+ }; @@ -94,7 +95,7 @@ macro_rules! pad_table { $( #[$id_cfg:meta] )? $PinId:ident { $( - $( #[$sercom_cfg:meta] )? + $( #[$sercom_cfg:meta] )* $Cfg:ident: ( $Sercom:ident, $PadNum:ident ) $( + $I2C:ident )?, )+ } @@ -105,7 +106,7 @@ macro_rules! pad_table { $( #[$id_cfg] )? $PinId { $( - $( #[$sercom_cfg] )? + $( #[$sercom_cfg] )* $Cfg: ( $Sercom, $PadNum ) $( + $I2C )?, )+ } @@ -250,13 +251,23 @@ pad_table!( pad_table!( #[hal_cfg("pa00")] PA00 { + #[cfg(not(feature = "undoc-features"))] #[hal_cfg("sercom1")] D: (Sercom1, Pad0), + + #[cfg(feature = "undoc-features")] + #[hal_cfg("sercom1")] + D: (Sercom1, Pad0) + I2C, } #[hal_cfg("pa01")] PA01 { + #[cfg(not(feature = "undoc-features"))] #[hal_cfg("sercom1")] D: (Sercom1, Pad1), + + #[cfg(feature = "undoc-features")] + #[hal_cfg("sercom1")] + D: (Sercom1, Pad1) + I2C, } #[hal_cfg("pa04")] PA04 { diff --git a/hal/src/sercom/pad/impl_pad_thumbv7em.rs b/hal/src/sercom/pad/impl_pad_thumbv7em.rs index 53d8314bf496..386b65072de7 100644 --- a/hal/src/sercom/pad/impl_pad_thumbv7em.rs +++ b/hal/src/sercom/pad/impl_pad_thumbv7em.rs @@ -63,27 +63,27 @@ macro_rules! pad_table { #[$id_cfg:meta] $PinId:ident { $( - $( #[$sercom_cfg:meta] )? + $( #[$sercom_cfg:meta] )* $Cfg:ident: ( $Sercom:ident, $PadNum:ident, $( $IoSet:ident ),+ ) $( + $I2C:ident )?, )+ } ) => { $( #[$id_cfg] - $( #[$sercom_cfg] )? + $( #[$sercom_cfg] )* pad_info!( $PinId, $Cfg, $Sercom, $PadNum, $( $IoSet ),+ $( + $I2C )?); )+ }; ( $PinId:ident { $( - $( #[$sercom_cfg:meta] )? + $( #[$sercom_cfg:meta] )* $Cfg:ident: ( $Sercom:ident, $PadNum:ident, $( $IoSet:ident ),+ ) $( + $I2C:ident )?, )+ } ) => { $( - $( #[$sercom_cfg] )? + $( #[$sercom_cfg] )* pad_info!( $PinId, $Cfg, $Sercom, $PadNum, $( $IoSet ),+ $( + $I2C )?); )+ }; @@ -92,7 +92,7 @@ macro_rules! pad_table { $( #[$id_cfg:meta] )? $PinId:ident { $( - $( #[$sercom_cfg:meta] )? + $( #[$sercom_cfg:meta] )* $Cfg:ident: ( $Sercom:ident, $PadNum:ident, $( $IoSet:ident ),+ ) $( + $I2C:ident )?, )+ } @@ -103,7 +103,7 @@ macro_rules! pad_table { $( #[$id_cfg] )? $PinId{ $( - $( #[$sercom_cfg] )? + $( #[$sercom_cfg] )* $Cfg: ( $Sercom, $PadNum, $( $IoSet),+ ) $( + $I2C )?, )+ } @@ -123,11 +123,21 @@ macro_rules! pad_table { pad_table!( #[hal_cfg("pa00")] PA00 { + #[cfg(not(feature = "undoc-features"))] + #[hal_cfg("sercom1")] + D: (Sercom1, Pad0, IoSet4), + + #[cfg(feature = "undoc-features")] #[hal_cfg("sercom1")] D: (Sercom1, Pad0, IoSet4, UndocIoSet2), } #[hal_cfg("pa01")] PA01 { + #[cfg(not(feature = "undoc-features"))] + #[hal_cfg("sercom1")] + D: (Sercom1, Pad1, IoSet4), + + #[cfg(feature = "undoc-features")] #[hal_cfg("sercom1")] D: (Sercom1, Pad1, IoSet4, UndocIoSet2), } @@ -209,6 +219,11 @@ pad_table!( } #[hal_cfg("pa16")] PA16 { + #[hal_cfg("sercom1")] + #[cfg(not(feature = "undoc-features"))] + C: (Sercom1, Pad0, IoSet1) + I2C, + + #[cfg(feature = "undoc-features")] #[hal_cfg("sercom1")] C: (Sercom1, Pad0, IoSet1, UndocIoSet1) + I2C, #[hal_cfg("sercom3")] @@ -216,6 +231,11 @@ pad_table!( } #[hal_cfg("pa17")] PA17 { + #[cfg(not(feature = "undoc-features"))] + #[hal_cfg("sercom1")] + C: (Sercom1, Pad1, IoSet1) + I2C, + + #[cfg(feature = "undoc-features")] #[hal_cfg("sercom1")] C: (Sercom1, Pad1, IoSet1, UndocIoSet1) + I2C, #[hal_cfg("sercom3")] @@ -305,13 +325,21 @@ pad_table!( } #[hal_cfg("pb02")] PB02 { - // According to Metro M4, PB02 is I2C-capable. This disagrees with datasheet table 6-8. + #[cfg(not(feature = "undoc-features"))] + #[hal_cfg("sercom5")] + D: (Sercom5, Pad0, IoSet6), + + #[cfg(feature = "undoc-features")] #[hal_cfg("sercom5")] D: (Sercom5, Pad0, IoSet6) + I2C, } #[hal_cfg("pb03")] PB03 { - // According to Metro M4, PB03 is I2C-capable. This disagrees with datasheet table 6-8. + #[cfg(not(feature = "undoc-features"))] + #[hal_cfg("sercom5")] + D: (Sercom5, Pad1, IoSet6), + + #[cfg(feature = "undoc-features")] #[hal_cfg("sercom5")] D: (Sercom5, Pad1, IoSet6) + I2C, } @@ -399,6 +427,11 @@ pad_table!( } #[hal_cfg("pb22")] PB22 { + #[cfg(not(feature = "undoc-features"))] + #[hal_cfg("sercom1")] + C: (Sercom1, Pad2, IoSet3), + + #[cfg(feature = "undoc-features")] #[hal_cfg("sercom1")] C: (Sercom1, Pad2, IoSet3, UndocIoSet1, UndocIoSet2), #[hal_cfg("sercom5")] @@ -406,6 +439,11 @@ pad_table!( } #[hal_cfg("pb23")] PB23 { + #[cfg(not(feature = "undoc-features"))] + #[hal_cfg("sercom1")] + C: (Sercom1, Pad3, IoSet3), + + #[cfg(feature = "undoc-features")] #[hal_cfg("sercom1")] C: (Sercom1, Pad3, IoSet3, UndocIoSet1, UndocIoSet2), #[hal_cfg("sercom5")] From feab341371ac453703ecd440e98f6ad385a59e84 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Mon, 17 Nov 2025 22:26:17 +0100 Subject: [PATCH 002/114] chore: Remove deprecated warning in aes module (#957) --- hal/src/peripherals/aes/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hal/src/peripherals/aes/mod.rs b/hal/src/peripherals/aes/mod.rs index 23deaec40df8..e30fd6efc6d0 100644 --- a/hal/src/peripherals/aes/mod.rs +++ b/hal/src/peripherals/aes/mod.rs @@ -119,11 +119,6 @@ //! assert_eq!(block, block_copy); //! ``` -// The cipher crate has an outdated dependency on the generic-array crate -// (by way of the crypto_common crate) -// Nothing we can do about this until the dependency chain is up to date -#![allow(deprecated)] - // Re-exports pub use pac::aes::ctrla::{ Aesmodeselect, Cfbsselect, Cipherselect, Keysizeselect, Lodselect, Startmodeselect, From 90b939604b8e8b27cdac000c303144067ac3f984 Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Tue, 18 Nov 2025 01:50:33 -0800 Subject: [PATCH 003/114] feat: Add PB02 and PB03 as undocumented I2C pads for SAMD21 (#958) The circuit-playground-express uses these pads as the Sda/Scl pads. --- hal/src/sercom/pad/impl_pad_thumbv6m.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hal/src/sercom/pad/impl_pad_thumbv6m.rs b/hal/src/sercom/pad/impl_pad_thumbv6m.rs index a7c2e58d02ef..29d9da9b2154 100644 --- a/hal/src/sercom/pad/impl_pad_thumbv6m.rs +++ b/hal/src/sercom/pad/impl_pad_thumbv6m.rs @@ -437,13 +437,23 @@ pad_table!( } #[hal_cfg("pb02")] PB02 { + #[cfg(not(feature = "undoc-features"))] #[hal_cfg("sercom5")] D: (Sercom5, Pad0), + + #[cfg(feature = "undoc-features")] + #[hal_cfg("sercom5")] + D: (Sercom5, Pad0) + I2C, } #[hal_cfg("pb03")] PB03 { + #[cfg(not(feature = "undoc-features"))] #[hal_cfg("sercom5")] D: (Sercom5, Pad1), + + #[cfg(feature = "undoc-features")] + #[hal_cfg("sercom5")] + D: (Sercom5, Pad1) + I2C, } #[hal_cfg("pb08")] PB08 { From a06a4b99c6be00110dd1342d4ac381cb4cdb9390 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Wed, 19 Nov 2025 13:11:23 +0100 Subject: [PATCH 004/114] docs: Document newly undoc I2C-capable pins (PB02,PB03) (#960) --- README.md | 4 ++++ hal/src/sercom/mod.rs | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/README.md b/README.md index 4b172ccb9875..c8e35033d4a0 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,10 @@ Currently, we provide these features undocumented features: * Mark `PA01` as I2C-capable according to `circuit_playground_express`. +* Mark `PB02` as I2C-capable according to `circuit_playground_express`. + +* Mark `PB03` as I2C-capable according to `circuit_playground_express`. + ### SAMx5x devices: * `UndocIoSet1`: Implement an undocumented `IoSet` for PA16, PA17, PB22 & PB23 configured for `Sercom1`. The `pygamer` & `feather_m4` use this diff --git a/hal/src/sercom/mod.rs b/hal/src/sercom/mod.rs index 507ff986ba32..1c678fa9438c 100644 --- a/hal/src/sercom/mod.rs +++ b/hal/src/sercom/mod.rs @@ -18,6 +18,12 @@ //! * `PA01` is I2C-capable according to `circuit_playground_express`. As such, //! PA01 implements [`IsI2cPad`]. //! +//! * `PB02` is I2C-capable according to `circuit_playground_express`. As such, +//! PB02 implements [`IsI2cPad`]. +//! +//! * `PB03` is I2C-capable according to `circuit_playground_express`. As such, +//! PB03 implements [`IsI2cPad`]. +//! //! ## SAMx5x devices: //! * `UndocIoSet1`: Implement an undocumented `IoSet` for PA16, PA17, PB22 & //! PB23 configured for [`Sercom1`]. The `pygamer` & `feather_m4` use this From 025e76adb9282aae9f138f84f96c76bb5b2a2142 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:07:00 +0100 Subject: [PATCH 005/114] chore: release (#947) * chore: release * Minor version bump for all T1 boards --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Justin Beaurivage --- boards/atsame54_xpro/CHANGELOG.md | 6 ++++++ boards/atsame54_xpro/Cargo.toml | 4 ++-- boards/feather_m0/CHANGELOG.md | 6 ++++++ boards/feather_m0/Cargo.toml | 4 ++-- boards/feather_m4/CHANGELOG.md | 6 ++++++ boards/feather_m4/Cargo.toml | 4 ++-- boards/metro_m0/CHANGELOG.md | 6 ++++++ boards/metro_m0/Cargo.toml | 4 ++-- boards/metro_m4/CHANGELOG.md | 6 ++++++ boards/metro_m4/Cargo.toml | 4 ++-- boards/pygamer/CHANGELOG.md | 6 ++++++ boards/pygamer/Cargo.toml | 4 ++-- boards/samd11_bare/CHANGELOG.md | 6 ++++++ boards/samd11_bare/Cargo.toml | 4 ++-- hal/CHANGELOG.md | 32 +++++++++++++++++++++++++++++++ hal/Cargo.toml | 2 +- 16 files changed, 89 insertions(+), 15 deletions(-) diff --git a/boards/atsame54_xpro/CHANGELOG.md b/boards/atsame54_xpro/CHANGELOG.md index 43e077acfb14..1b2e5d37fd9b 100644 --- a/boards/atsame54_xpro/CHANGELOG.md +++ b/boards/atsame54_xpro/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.13.0](https://github.com/atsamd-rs/atsamd/compare/atsame54_xpro-0.12.2...atsame54_xpro-0.13.0) - 2025-11-19 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.12.2](https://github.com/atsamd-rs/atsamd/compare/atsame54_xpro-0.12.1...atsame54_xpro-0.12.2) - 2025-06-26 ### Other diff --git a/boards/atsame54_xpro/Cargo.toml b/boards/atsame54_xpro/Cargo.toml index eafd323a3089..04569f6b463e 100644 --- a/boards/atsame54_xpro/Cargo.toml +++ b/boards/atsame54_xpro/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" name = "atsame54_xpro" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.12.2" +version = "0.13.0" [dependencies.cortex-m-rt] optional = true @@ -24,7 +24,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.22.2" +version = "0.23.0" [dependencies.usb-device] optional = true diff --git a/boards/feather_m0/CHANGELOG.md b/boards/feather_m0/CHANGELOG.md index 43b4b9dad14b..dc1932dfbeea 100644 --- a/boards/feather_m0/CHANGELOG.md +++ b/boards/feather_m0/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.0](https://github.com/atsamd-rs/atsamd/compare/feather_m0-0.19.2...feather_m0-0.20.0) - 2025-11-19 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.19.2](https://github.com/atsamd-rs/atsamd/compare/feather_m0-0.19.1...feather_m0-0.19.2) - 2025-06-26 ### Other diff --git a/boards/feather_m0/Cargo.toml b/boards/feather_m0/Cargo.toml index 81afb47d90b0..0e826e05ed62 100644 --- a/boards/feather_m0/Cargo.toml +++ b/boards/feather_m0/Cargo.toml @@ -9,7 +9,7 @@ name = "feather_m0" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" resolver = "2" -version = "0.19.2" +version = "0.20.0" # for cargo flash [package.metadata] @@ -22,7 +22,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.22.2" +version = "0.23.0" [dependencies.cortex-m] features = ["critical-section-single-core"] diff --git a/boards/feather_m4/CHANGELOG.md b/boards/feather_m4/CHANGELOG.md index bd13d43e1c30..7a147df11a52 100644 --- a/boards/feather_m4/CHANGELOG.md +++ b/boards/feather_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.18.0](https://github.com/atsamd-rs/atsamd/compare/feather_m4-0.17.2...feather_m4-0.18.0) - 2025-11-19 + +### Changed + +- [**breaking**] Gate undocumented chip features behind the `undoc-features` Cargo feature ([#956](https://github.com/atsamd-rs/atsamd/pull/956)) + ## [0.17.2](https://github.com/atsamd-rs/atsamd/compare/feather_m4-0.17.1...feather_m4-0.17.2) - 2025-06-26 ### Other diff --git a/boards/feather_m4/Cargo.toml b/boards/feather_m4/Cargo.toml index c51484162900..888fef37e987 100644 --- a/boards/feather_m4/Cargo.toml +++ b/boards/feather_m4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" name = "feather_m4" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.17.2" +version = "0.18.0" # for cargo flash [package.metadata] @@ -26,7 +26,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.22.2" +version = "0.23.0" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/metro_m0/CHANGELOG.md b/boards/metro_m0/CHANGELOG.md index 7f2a0b888ffa..12140ba7ea53 100644 --- a/boards/metro_m0/CHANGELOG.md +++ b/boards/metro_m0/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.0](https://github.com/atsamd-rs/atsamd/compare/metro_m0-0.19.2...metro_m0-0.20.0) - 2025-11-19 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.19.2](https://github.com/atsamd-rs/atsamd/compare/metro_m0-0.19.1...metro_m0-0.19.2) - 2025-06-26 ### Other diff --git a/boards/metro_m0/Cargo.toml b/boards/metro_m0/Cargo.toml index b485c1154cae..6632c423f387 100644 --- a/boards/metro_m0/Cargo.toml +++ b/boards/metro_m0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "metro_m0" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.19.2" +version = "0.20.0" # for cargo flash [package.metadata] @@ -25,7 +25,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.22.2" +version = "0.23.0" [dependencies.rtic] features = ["thumbv6-backend"] diff --git a/boards/metro_m4/CHANGELOG.md b/boards/metro_m4/CHANGELOG.md index 38acf388d3f3..d628ed846e56 100644 --- a/boards/metro_m4/CHANGELOG.md +++ b/boards/metro_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.19.0](https://github.com/atsamd-rs/atsamd/compare/metro_m4-0.18.2...metro_m4-0.19.0) - 2025-11-19 + +### Changed + +- [**breaking**] Gate undocumented chip features behind the `undoc-features` Cargo feature ([#956](https://github.com/atsamd-rs/atsamd/pull/956)) + ## [0.18.2](https://github.com/atsamd-rs/atsamd/compare/metro_m4-0.18.1...metro_m4-0.18.2) - 2025-06-26 ### Other diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index 6d3f4e3bef06..5974e3ef41c2 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "metro_m4" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.18.2" +version = "0.19.0" # for cargo flash [package.metadata] @@ -21,7 +21,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.22.2" +version = "0.23.0" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/pygamer/CHANGELOG.md b/boards/pygamer/CHANGELOG.md index ef891a3e7ec5..43b8fa4325ec 100644 --- a/boards/pygamer/CHANGELOG.md +++ b/boards/pygamer/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.0](https://github.com/atsamd-rs/atsamd/compare/pygamer-0.15.2...pygamer-0.16.0) - 2025-11-19 + +### Changed + +- [**breaking**] Gate undocumented chip features behind the `undoc-features` Cargo feature ([#956](https://github.com/atsamd-rs/atsamd/pull/956)) + ## [0.15.2](https://github.com/atsamd-rs/atsamd/compare/pygamer-0.15.1...pygamer-0.15.2) - 2025-06-26 ### Other diff --git a/boards/pygamer/Cargo.toml b/boards/pygamer/Cargo.toml index a3306f450149..417265d15572 100644 --- a/boards/pygamer/Cargo.toml +++ b/boards/pygamer/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" name = "pygamer" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.15.2" +version = "0.16.0" [dependencies] cortex-m = {version = "0.7", features = ["critical-section-single-core"]} @@ -27,7 +27,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.22.2" +version = "0.23.0" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/samd11_bare/CHANGELOG.md b/boards/samd11_bare/CHANGELOG.md index 8e1f439274b7..055b9ebc605a 100644 --- a/boards/samd11_bare/CHANGELOG.md +++ b/boards/samd11_bare/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.0](https://github.com/atsamd-rs/atsamd/compare/samd11_bare-0.15.2...samd11_bare-0.16.0) - 2025-11-19 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.15.2](https://github.com/atsamd-rs/atsamd/compare/samd11_bare-0.15.1...samd11_bare-0.15.2) - 2025-06-26 ### Other diff --git a/boards/samd11_bare/Cargo.toml b/boards/samd11_bare/Cargo.toml index 1d06909ef5e8..9bccad655a65 100644 --- a/boards/samd11_bare/Cargo.toml +++ b/boards/samd11_bare/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" name = "samd11_bare" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.15.2" +version = "0.16.0" # for cargo flash [package.metadata] @@ -24,7 +24,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.22.2" +version = "0.23.0" [dependencies.rtic] features = ["thumbv6-backend"] diff --git a/hal/CHANGELOG.md b/hal/CHANGELOG.md index 12c351133f29..6acbf6f78281 100644 --- a/hal/CHANGELOG.md +++ b/hal/CHANGELOG.md @@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.23.0](https://github.com/atsamd-rs/atsamd/compare/atsamd-hal-0.22.2...atsamd-hal-0.23.0) - 2025-11-19 + +### Added + +- Add PB02 and PB03 as undocumented I2C pads for SAMD21 ([#958](https://github.com/atsamd-rs/atsamd/pull/958)) +- *(aes)* Updates the `cipher` dependency. +- *(aes)* Updates the `aes` module: + +### Changed + +- [**breaking**] Gate undocumented chip features behind the `undoc-features` Cargo feature ([#956](https://github.com/atsamd-rs/atsamd/pull/956)) + +### Documentation + +- Document newly undoc I2C-capable pins (PB02,PB03) ([#960](https://github.com/atsamd-rs/atsamd/pull/960)) + +### Fixed + +- *(ci)* silence deprecation warning we have no power over ([#943](https://github.com/atsamd-rs/atsamd/pull/943)) +- *(dmac)* DMAC handler now waits for channel to report as disabled ([#938](https://github.com/atsamd-rs/atsamd/pull/938)) +- [**breaking**] Re-add GCLK0 for CAN dependencies ([#930](https://github.com/atsamd-rs/atsamd/pull/930)) +- Clippy warning about null pointers in DMAC ([#928](https://github.com/atsamd-rs/atsamd/pull/928)) +- Remove GCLK from can::Dependencies ([#919](https://github.com/atsamd-rs/atsamd/pull/919)) + +### Other + +- Remove deprecated warning in aes module ([#957](https://github.com/atsamd-rs/atsamd/pull/957)) +- fix off-by-one Pwm period ([#949](https://github.com/atsamd-rs/atsamd/pull/949)) +- Fix and improve EIC Event control ([#944](https://github.com/atsamd-rs/atsamd/pull/944)) +- Document order of calling enable_interrupt for interrupt timer ([#942](https://github.com/atsamd-rs/atsamd/pull/942)) +- *(ci)* Remove explicit link targets from docs + ## [0.22.2](https://github.com/atsamd-rs/atsamd/compare/atsamd-hal-0.22.1...atsamd-hal-0.22.2) - 2025-06-26 ### Fixed diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 16d3037a729a..3bf305003f54 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -20,7 +20,7 @@ name = "atsamd-hal" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" rust-version = "1.85.1" -version = "0.22.2" +version = "0.23.0" [package.metadata.docs.rs] features = ["samd21g", "samd21g-rt", "usb", "dma", "async", "rtic"] From 20b17d2c6d84beeac689b24a17c67f4ba076a04b Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Thu, 20 Nov 2025 02:22:58 -0800 Subject: [PATCH 006/114] deps(circuit-playground-express): Update dependencies and HAL to 0.23.0 (#953) --- boards/circuit_playground_express/Cargo.toml | 23 ++++-- .../examples/blinky_basic.rs | 10 +-- .../examples/neopixel_rainbow.rs | 22 +++--- .../examples/uart.rs | 75 ++++++++++--------- .../examples/usb_serial.rs | 44 +++++------ boards/circuit_playground_express/src/lib.rs | 71 +++++++++++------- 6 files changed, 139 insertions(+), 106 deletions(-) diff --git a/boards/circuit_playground_express/Cargo.toml b/boards/circuit_playground_express/Cargo.toml index 1245b52a5c45..85683b99840a 100644 --- a/boards/circuit_playground_express/Cargo.toml +++ b/boards/circuit_playground_express/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "circuit_playground_express" +categories = ["embedded", "hardware-support", "no-std"] version = "0.11.1" authors = ["Paul Sajna "] description = "Board Support crate for the Adafruit Circuit Playground Express" @@ -7,26 +8,30 @@ keywords = ["no-std", "arm", "cortex-m", "embedded-hal"] license = "MIT OR Apache-2.0" repository = "https://github.com/atsamd-rs/atsamd" readme = "README.md" -edition = "2018" +edition = "2024" [dependencies.cortex-m-rt] version = "0.7" optional = true [dependencies.atsamd-hal] -version = "0.14" +version = "0.23.0" default-features = false +[dependencies.cortex-m] +features = ["critical-section-single-core"] +version = "0.7" + [dependencies.usb-device] -version = "0.2" +version = "0.3.2" optional = true [dev-dependencies] -cortex-m = "0.7" panic-halt = "0.2" -panic-semihosting = "0.5" -usbd-serial = "0.1" +panic-semihosting = "0.6" +usbd-serial = "0.2" smart-leds = "0.3.0" +heapless = "0.9.2" [dev-dependencies.ws2812-timer-delay] features = ["slow"] @@ -34,9 +39,10 @@ version = "0.3.0" [features] # ask the HAL to enable atsamd21g support -default = ["rt", "atsamd-hal/samd21g"] +# CPE uses all kinds of undoc'd i2c functionality. +default = ["rt", "atsamd-hal/samd21g", "atsamd-hal/undoc-features"] +dma = ["atsamd-hal/dma"] rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"] -unproven = ["atsamd-hal/unproven"] usb = ["atsamd-hal/usb", "usb-device"] use_semihosting = [] @@ -53,3 +59,4 @@ name = "uart" [[example]] name = "usb_serial" required-features = ["usb"] +edition = "2021" diff --git a/boards/circuit_playground_express/examples/blinky_basic.rs b/boards/circuit_playground_express/examples/blinky_basic.rs index c3387886de5c..31af1cf553e9 100644 --- a/boards/circuit_playground_express/examples/blinky_basic.rs +++ b/boards/circuit_playground_express/examples/blinky_basic.rs @@ -21,12 +21,12 @@ fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT); + let pins = bsp::Pins::new(peripherals.port); let mut red_led: bsp::RedLed = pins.d13.into(); let mut delay = Delay::new(core.SYST, &mut clocks); loop { diff --git a/boards/circuit_playground_express/examples/neopixel_rainbow.rs b/boards/circuit_playground_express/examples/neopixel_rainbow.rs index 754221562499..ccc0e4790b82 100644 --- a/boards/circuit_playground_express/examples/neopixel_rainbow.rs +++ b/boards/circuit_playground_express/examples/neopixel_rainbow.rs @@ -20,13 +20,14 @@ use circuit_playground_express as bsp; use bsp::entry; use hal::clock::GenericClockController; use hal::delay::Delay; -use hal::prelude::*; +use hal::fugit::ExtU32; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::{CorePeripherals, Peripherals}; use smart_leds::{ - hsv::{hsv2rgb, Hsv}, SmartLedsWrite, + hsv::{Hsv, hsv2rgb}, }; use ws2812_timer_delay as ws2812; @@ -35,24 +36,25 @@ fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT); + let pins = bsp::Pins::new(peripherals.port); let mut delay = Delay::new(core.SYST, &mut clocks); let gclk0 = clocks.gclk0(); let timer_clock = clocks.tcc2_tc3(&gclk0).unwrap(); - let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.TC3, &mut peripherals.PM); - timer.start(3.mhz()); + let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.tc3, &mut peripherals.pm); + timer.start(1.micros()); let neopixel_pin: bsp::NeoPixel = pins.d8.into(); let mut neopixel = ws2812::Ws2812::new(timer, neopixel_pin); // Loop through all of the available hue values (colors) to make a // rainbow effect from the onboard neopixel + use hal::ehal::delay::DelayNs; loop { for j in 0..255u8 { let colors = [hsv2rgb(Hsv { @@ -61,7 +63,7 @@ fn main() -> ! { val: 2, }); 10]; neopixel.write(colors.iter().cloned()).unwrap(); - delay.delay_ms(5u8); + delay.delay_ms(5); } } } diff --git a/boards/circuit_playground_express/examples/uart.rs b/boards/circuit_playground_express/examples/uart.rs index 9ca526a645ab..91afbe5e20dc 100644 --- a/boards/circuit_playground_express/examples/uart.rs +++ b/boards/circuit_playground_express/examples/uart.rs @@ -1,3 +1,6 @@ +//! This example shows how to use the UART to perform transfers using the +//! embedded-hal-nb traits. + #![no_std] #![no_main] @@ -9,58 +12,62 @@ use panic_semihosting as _; use bsp::hal; use bsp::pac; use circuit_playground_express as bsp; +use hal::nb; -use bsp::entry; +use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; -use hal::prelude::*; +use hal::ehal_nb::serial::{Read, Write}; +use hal::fugit::RateExtU32; -use pac::{CorePeripherals, Peripherals}; +use pac::Peripherals; #[entry] fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); - let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let mut pm = peripherals.PM; - let pins = bsp::Pins::new(peripherals.PORT); - let mut delay = hal::delay::Delay::new(core.SYST, &mut clocks); + let mut pm = peripherals.pm; + let pins = bsp::Pins::new(peripherals.port); - let mut red_led = pins.d13.into_push_pull_output(); + // Take peripheral and pins + let uart_sercom = periph_alias!(peripherals.uart_sercom); + let uart_rx = pin_alias!(pins.uart_rx); + let uart_tx = pin_alias!(pins.uart_tx); - // Setup UART peripheral. - let (rx_pin, tx_pin) = (pins.a6, pins.a7); - let mut uart = bsp::uart( + // Setup UART peripheral + let uart = bsp::uart( &mut clocks, - 9600.hz(), - peripherals.SERCOM4, + 9600.Hz(), + uart_sercom, &mut pm, - rx_pin, - tx_pin, + uart_rx, + uart_tx, ); - // Write out a message on start up. - for byte in b"Hello world!\r\n" { - nb::block!(uart.write(*byte)).unwrap(); - } + // Split uart in rx + tx halves + let (mut rx, mut tx) = uart.split(); + + // Make buffers to store data to send/receive + let mut rx_buffer = [0x00; 50]; + let tx_buffer = b"Hello, world!"; loop { - match uart.read() { - Ok(byte) => { - // Echo all received characters. - nb::block!(uart.write(byte)).unwrap(); + // Send data. We block on each byte, but we could also perform some tasks while + // waiting for the byte to finish sending. + for c in tx_buffer.iter() { + nb::block!(tx.write(*c)).unwrap(); + } - // Blink the red led to show that a character has arrived. - red_led.set_high().unwrap(); - delay.delay_ms(2u16); - red_led.set_low().unwrap(); - } - Err(_) => delay.delay_ms(5u16), - }; + // Receive data. We block on each byte, but we could also perform some tasks + // while waiting for the byte to finish sending. + rx.flush_rx_buffer(); + for c in rx_buffer.iter_mut() { + *c = nb::block!(rx.read()).unwrap(); + } } } diff --git a/boards/circuit_playground_express/examples/usb_serial.rs b/boards/circuit_playground_express/examples/usb_serial.rs index b99fbcd7c43e..a860b9b94843 100644 --- a/boards/circuit_playground_express/examples/usb_serial.rs +++ b/boards/circuit_playground_express/examples/usb_serial.rs @@ -16,7 +16,7 @@ use bsp::hal; use bsp::pac; use circuit_playground_express as bsp; -use bsp::entry; +use bsp::{entry, pin_alias}; use hal::clock::GenericClockController; use hal::prelude::*; use hal::usb::UsbBus; @@ -27,19 +27,19 @@ fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let mut core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT); - let mut red_led: bsp::RedLed = pins.d13.into(); + let pins = bsp::Pins::new(peripherals.port); + let mut red_led: bsp::RedLed = pin_alias!(pins.red_led).into(); let bus_allocator = unsafe { USB_ALLOCATOR = Some(bsp::usb_allocator( - peripherals.USB, + peripherals.usb, &mut clocks, - &mut peripherals.PM, + &mut peripherals.pm, pins.usb_dm, pins.usb_dp, )); @@ -47,12 +47,14 @@ fn main() -> ! { }; unsafe { - USB_SERIAL = Some(SerialPort::new(&bus_allocator)); + USB_SERIAL = Some(SerialPort::new(bus_allocator)); USB_BUS = Some( - UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") + UsbDeviceBuilder::new(bus_allocator, UsbVidPid(0x16c0, 0x27dd)) + .strings(&[StringDescriptors::new(LangID::EN) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST")]) + .expect("Failed to set strings") .device_class(USB_CLASS_CDC) .build(), ); @@ -67,9 +69,7 @@ fn main() -> ! { // entirely interrupt driven. loop { cycle_delay(15 * 1024 * 1024); - red_led.set_high().ok(); - cycle_delay(15 * 1024 * 1024); - red_led.set_low().ok(); + red_led.toggle().ok(); } } @@ -79,8 +79,8 @@ static mut USB_SERIAL: Option> = None; fn poll_usb() { unsafe { - USB_BUS.as_mut().map(|usb_dev| { - USB_SERIAL.as_mut().map(|serial| { + if let Some(usb_dev) = USB_BUS.as_mut() { + if let Some(serial) = USB_SERIAL.as_mut() { usb_dev.poll(&mut [serial]); let mut buf = [0u8; 64]; @@ -89,11 +89,11 @@ fn poll_usb() { if i >= count { break; } - serial.write(&[c.clone()]).ok(); + serial.write(&[*c]).ok(); } }; - }); - }); + }; + }; }; } diff --git a/boards/circuit_playground_express/src/lib.rs b/boards/circuit_playground_express/src/lib.rs index 37941170e076..ce3ade16a907 100644 --- a/boards/circuit_playground_express/src/lib.rs +++ b/boards/circuit_playground_express/src/lib.rs @@ -8,15 +8,23 @@ pub use hal::ehal; pub use hal::pac; use hal::clock::GenericClockController; +use hal::fugit::RateExtU32; use hal::prelude::*; -use hal::sercom::v2::spi; -use hal::sercom::v2::uart::{self, BaudMode, Oversampling}; -use hal::sercom::v2::{Sercom0, Sercom3, Sercom4}; -use hal::sercom::I2CMaster5; -use hal::time::{Hertz, MegaHertz}; +use hal::sercom::i2c; +use hal::sercom::spi; +use hal::sercom::uart::{self, BaudMode, Oversampling}; +use hal::sercom::{Sercom0, Sercom3, Sercom4}; +use hal::time::Hertz; #[cfg(feature = "usb")] -use hal::usb::{usb_device::bus::UsbBusAllocator, UsbBus}; +use hal::usb::{UsbBus, usb_device::bus::UsbBusAllocator}; + +hal::bsp_peripherals!( + Sercom0 { SpiSercom } + Sercom1 { AccelSercom } + Sercom4 { UartSercom } + Sercom5 { I2cSercom } +); /// Definitions related to pins and pin aliases pub mod pins { @@ -186,9 +194,9 @@ pub type Spi = spi::Spi, spi::Duplex>; /// any OutputPin, or even a pulled up line on the slave. pub fn spi_master( clocks: &mut GenericClockController, - baud: impl Into, - sercom0: pac::SERCOM0, - pm: &mut pac::PM, + baud: Hertz, + sercom0: pac::Sercom0, + pm: &mut pac::Pm, sck: impl Into, mosi: impl Into, miso: impl Into, @@ -217,8 +225,8 @@ pub type FlashSpi = spi::Spi, spi::Duplex>; /// SPI Master. pub fn flash_spi_master( clocks: &mut GenericClockController, - sercom3: pac::SERCOM3, - pm: &mut pac::PM, + sercom3: pac::Sercom3, + pm: &mut pac::Pm, sck: impl Into, mosi: impl Into, miso: impl Into, @@ -230,7 +238,7 @@ pub fn flash_spi_master( let (sck, mosi, miso, mut cs) = (sck.into(), mosi.into(), miso.into(), cs.into()); let pads = spi::Pads::default().data_in(miso).data_out(mosi).sclk(sck); let spi = spi::Config::new(pm, sercom3, pads, freq) - .baud(MegaHertz(48)) + .baud(48.MHz()) .spi_mode(spi::MODE_0) .enable(); @@ -239,25 +247,34 @@ pub fn flash_spi_master( (spi, cs) } -/// I2C master for the labelled SDA & SCL pins -pub type I2C = I2CMaster5; +/// I2C pads for the labelled I2C peripheral +/// +/// You can use these pads with other, user-defined [`i2c::Config`]urations. +pub type I2cPads = i2c::Pads; + +/// I2C master for the labelled I2C peripheral +/// +/// This type implements [`Read`](ehal::blocking::i2c::Read), +/// [`Write`](ehal::blocking::i2c::Write) and +/// [`WriteRead`](ehal::blocking::i2c::WriteRead). +pub type I2c = i2c::I2c>; /// Convenience for setting up the labelled SDA, SCL pins to /// operate as an I2C master running at the specified frequency. pub fn i2c_master( clocks: &mut GenericClockController, - baud: impl Into, - sercom5: pac::SERCOM5, - pm: &mut pac::PM, + baud: Hertz, + sercom: I2cSercom, + pm: &mut pac::Pm, sda: impl Into, scl: impl Into, -) -> I2C { +) -> I2c { let gclk0 = clocks.gclk0(); let clock = &clocks.sercom5_core(&gclk0).unwrap(); - let baud = baud.into(); - let sda = sda.into(); - let scl = scl.into(); - I2CMaster5::new(clock, baud, sercom5, pm, sda, scl) + let freq = clock.freq(); + let baud = baud; + let pads = i2c::Pads::new(sda.into(), scl.into()); + i2c::Config::new(pm, sercom, pads, freq).baud(baud).enable() } /// UART pads for the labelled RX & TX pins @@ -270,9 +287,9 @@ pub type Uart = uart::Uart, uart::Duplex>; /// operate as a UART device running at the specified baud. pub fn uart( clocks: &mut GenericClockController, - baud: impl Into, - sercom4: pac::SERCOM4, - pm: &mut pac::PM, + baud: Hertz, + sercom4: pac::Sercom4, + pm: &mut pac::Pm, uart_rx: impl Into, uart_tx: impl Into, ) -> Uart { @@ -288,9 +305,9 @@ pub fn uart( #[cfg(feature = "usb")] /// Convenience function for setting up USB pub fn usb_allocator( - usb: pac::USB, + usb: pac::Usb, clocks: &mut GenericClockController, - pm: &mut pac::PM, + pm: &mut pac::Pm, dm: impl Into, dp: impl Into, ) -> UsbBusAllocator { From 48102c14fc912bcf87a23d571c3a56ea0bed6c86 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:28:12 +0100 Subject: [PATCH 007/114] chore(circuit_playground_express): release v0.12.0 (#961) * chore(circuit_playground_express): release v0.12.0 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Justin Beaurivage --- boards/circuit_playground_express/CHANGELOG.md | 6 ++++++ boards/circuit_playground_express/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/boards/circuit_playground_express/CHANGELOG.md b/boards/circuit_playground_express/CHANGELOG.md index f647054ab54b..23325715749f 100644 --- a/boards/circuit_playground_express/CHANGELOG.md +++ b/boards/circuit_playground_express/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.12.0](https://github.com/atsamd-rs/atsamd/compare/circuit_playground_express-0.11.1...circuit_playground_express-0.12.0) - 2025-11-20 + +### Dependencies + +- *(circuit-playground-express)* Update dependencies and HAL to 0.23.0 ([#953](https://github.com/atsamd-rs/atsamd/pull/953)) + ## [0.11.1](https://github.com/atsamd-rs/atsamd/compare/circuit_playground_express-0.11.0...circuit_playground_express-0.11.1) - 2024-10-17 ### Added diff --git a/boards/circuit_playground_express/Cargo.toml b/boards/circuit_playground_express/Cargo.toml index 85683b99840a..2ed46b56db4d 100644 --- a/boards/circuit_playground_express/Cargo.toml +++ b/boards/circuit_playground_express/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "circuit_playground_express" categories = ["embedded", "hardware-support", "no-std"] -version = "0.11.1" +version = "0.12.0" authors = ["Paul Sajna "] description = "Board Support crate for the Adafruit Circuit Playground Express" keywords = ["no-std", "arm", "cortex-m", "embedded-hal"] From 03d5366bcfc0dc6e777780a066c8a9132ed10400 Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Sun, 23 Nov 2025 07:16:20 -0800 Subject: [PATCH 008/114] chore(ci): Make all shebangs for shell scripts consistent. (#964) --- format-all.sh | 3 ++- rustfmt.sh | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/format-all.sh b/format-all.sh index 09b8408b0d6a..d1510784acb1 100755 --- a/format-all.sh +++ b/format-all.sh @@ -1,4 +1,5 @@ -#!/bin/bash +#!/usr/bin/env bash + set -xe HERE=$PWD diff --git a/rustfmt.sh b/rustfmt.sh index 83555c8b3b6e..12a1d195bf45 100755 --- a/rustfmt.sh +++ b/rustfmt.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + RET=0 # first, all boards & their examples From 3fc3c05c20e1049fc172295aee6e1537cee4c359 Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Mon, 24 Nov 2025 23:37:47 -0800 Subject: [PATCH 009/114] deps(circuit-playground-express): Add RTIC support for CPE (#966) --- boards/circuit_playground_express/Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/circuit_playground_express/Cargo.toml b/boards/circuit_playground_express/Cargo.toml index 2ed46b56db4d..b62e7af558ea 100644 --- a/boards/circuit_playground_express/Cargo.toml +++ b/boards/circuit_playground_express/Cargo.toml @@ -22,6 +22,11 @@ default-features = false features = ["critical-section-single-core"] version = "0.7" +[dependencies.rtic] +features = ["thumbv6-backend"] +optional = true +version = "2.1.1" + [dependencies.usb-device] version = "0.3.2" optional = true @@ -43,6 +48,7 @@ version = "0.3.0" default = ["rt", "atsamd-hal/samd21g", "atsamd-hal/undoc-features"] dma = ["atsamd-hal/dma"] rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"] +rtic = ["dep:rtic", "atsamd-hal/rtic"] usb = ["atsamd-hal/usb", "usb-device"] use_semihosting = [] From 601908a4ffd9eb1a4281c6dd76aa4a929c1e6bf8 Mon Sep 17 00:00:00 2001 From: Addison Hanrattie <40609224+supersimple33@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:56:31 -0500 Subject: [PATCH 010/114] deps(grand_central_m4): Bump HAL dependency to 0.23.0 (#968) --- boards/grand_central_m4/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/grand_central_m4/Cargo.toml b/boards/grand_central_m4/Cargo.toml index 931b14403da5..947c078a61ab 100644 --- a/boards/grand_central_m4/Cargo.toml +++ b/boards/grand_central_m4/Cargo.toml @@ -16,7 +16,7 @@ optional = true [dependencies.atsamd-hal] default-features = false -version = "0.22.0" +version = "0.23.0" [dependencies.usb-device] version = "0.3.2" From 13fbc7a11330f9477829cf2a54c1ecb0d43576e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:57:52 -0500 Subject: [PATCH 011/114] chore(ci): bump actions/checkout from 5 to 6 (#965) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-bsp.yml | 4 ++-- .github/workflows/build-hal.yml | 4 ++-- .github/workflows/check-docs.yml | 2 +- .github/workflows/generate-docs.yml | 4 ++-- .github/workflows/release-crates.yml | 2 +- .github/workflows/rustfmt.yml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-bsp.yml b/.github/workflows/build-bsp.yml index fbd358b76426..1d1417c021c6 100644 --- a/.github/workflows/build-bsp.yml +++ b/.github/workflows/build-bsp.yml @@ -8,7 +8,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Checkout sources - uses: actions/checkout@v5 + uses: actions/checkout@v6 - id: set-matrix uses: ./.github/actions/list-BSPs @@ -26,7 +26,7 @@ jobs: matrix: ${{fromJson(needs.setup.outputs.matrix)}} steps: - name: Checkout sources - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Rust run: | diff --git a/.github/workflows/build-hal.yml b/.github/workflows/build-hal.yml index 44f85fcf240d..72ddd0a1589a 100644 --- a/.github/workflows/build-hal.yml +++ b/.github/workflows/build-hal.yml @@ -8,7 +8,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Checkout sources - uses: actions/checkout@v5 + uses: actions/checkout@v6 - id: set-matrix uses: ./.github/actions/list-HAL-variants @@ -20,7 +20,7 @@ jobs: matrix: ${{fromJson(needs.setup.outputs.matrix)}} steps: - name: Checkout sources - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Rust run: | diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml index 353ef0756e69..b24c81747b88 100644 --- a/.github/workflows/check-docs.yml +++ b/.github/workflows/check-docs.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Rust run: | rustup set profile minimal diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml index 5533728425ea..7443a4f1ead8 100644 --- a/.github/workflows/generate-docs.yml +++ b/.github/workflows/generate-docs.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Rust run: | @@ -80,7 +80,7 @@ jobs: echo ' ' >> "${docs_path}/index.html" echo '' >> "${docs_path}/index.html" - name: Checkout pages branch - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: gh-pages path: gh-pages diff --git a/.github/workflows/release-crates.yml b/.github/workflows/release-crates.yml index 295a2bab5f6b..ebf467ad320c 100644 --- a/.github/workflows/release-crates.yml +++ b/.github/workflows/release-crates.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml index 7efd9e8a7084..96399070a7c0 100644 --- a/.github/workflows/rustfmt.yml +++ b/.github/workflows/rustfmt.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Rust run: | rustup set profile minimal From 2c4a772d0aab96c012421f44620a3a69bb6e4b8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:44:03 -0500 Subject: [PATCH 012/114] chore(deps): bump actions/download-artifact from 6 to 7 (#972) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-bsp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-bsp.yml b/.github/workflows/build-bsp.yml index 1d1417c021c6..1bb8d177b537 100644 --- a/.github/workflows/build-bsp.yml +++ b/.github/workflows/build-bsp.yml @@ -71,7 +71,7 @@ jobs: needs: [setup, build] steps: - name: Download artifacts - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v7 with: path: successful-jobs - name: Do checks From 2deb49dac36a16f9df4c9c3a939efe248ee385c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:44:34 -0500 Subject: [PATCH 013/114] chore(deps): bump actions/upload-artifact from 5 to 6 (#973) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-bsp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-bsp.yml b/.github/workflows/build-bsp.yml index 1bb8d177b537..2976344bbd14 100644 --- a/.github/workflows/build-bsp.yml +++ b/.github/workflows/build-bsp.yml @@ -60,7 +60,7 @@ jobs: $(${clippy_invocation}) - name: Done - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: # name needs to be unique in the workspace name: "${{ matrix.bsp.name }}-${{ matrix.toolchain }}" From 5b5a925843f9d0e4d1d4167d3a8dad4d4b1717c6 Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Wed, 19 Nov 2025 17:49:11 -0800 Subject: [PATCH 014/114] Improve cpe examples * Make the cpe usb_serial example use rtic. This allows the removal of the static muts, which are not legal in edition 2024. * Add an blinky example that uses rtic. --- boards/circuit_playground_express/Cargo.toml | 9 +- .../examples/blinky_rtic.rs | 77 +++++++ .../examples/usb_serial.rs | 190 ++++++++++-------- 3 files changed, 195 insertions(+), 81 deletions(-) create mode 100644 boards/circuit_playground_express/examples/blinky_rtic.rs diff --git a/boards/circuit_playground_express/Cargo.toml b/boards/circuit_playground_express/Cargo.toml index b62e7af558ea..8d643abb9436 100644 --- a/boards/circuit_playground_express/Cargo.toml +++ b/boards/circuit_playground_express/Cargo.toml @@ -35,6 +35,8 @@ optional = true panic-halt = "0.2" panic-semihosting = "0.6" usbd-serial = "0.2" +nom = {version = "5", default-features = false} +rtic-monotonics = {version = "1.3.0", features = ["cortex-m-systick", "systick-10khz"]} smart-leds = "0.3.0" heapless = "0.9.2" @@ -59,10 +61,13 @@ chip = "ATSAMD21G18A" [[example]] name = "blinky_basic" +[[example]] +name = "blinky_rtic" +required-features = ["rtic"] + [[example]] name = "uart" [[example]] name = "usb_serial" -required-features = ["usb"] -edition = "2021" +required-features = ["rtic", "usb"] diff --git a/boards/circuit_playground_express/examples/blinky_rtic.rs b/boards/circuit_playground_express/examples/blinky_rtic.rs new file mode 100644 index 000000000000..86374239ce21 --- /dev/null +++ b/boards/circuit_playground_express/examples/blinky_rtic.rs @@ -0,0 +1,77 @@ +//! Uses RTIC with a software task to blink an LED. +#![no_std] +#![no_main] + +use bsp::hal; +use circuit_playground_express as bsp; +use hal::rtc::rtic::rtc_clock; + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +hal::rtc_monotonic!(Mono, rtc_clock::ClockCustom<8_192>); + +#[rtic::app(device = bsp::pac, dispatchers = [EVSYS])] +mod app { + use super::*; + use bsp::{hal, pin_alias}; + use hal::clock::{ClockGenId, ClockSource, GenericClockController}; + use hal::pac::Peripherals; + use hal::prelude::*; + + #[local] + struct Local {} + + #[shared] + struct Shared { + // The LED could be a local resource, since it is only used in one task + // But we want to showcase shared resources and locking + red_led: bsp::RedLed, + } + + #[init] + fn init(cx: init::Context) -> (Shared, Local) { + let mut peripherals: Peripherals = cx.device; + let pins = bsp::Pins::new(peripherals.port); + let mut core: rtic::export::Peripherals = cx.core; + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, + ); + + // Set the RTC clock to use a 8.192 kHz clock derived from the internal 32 kHz + // oscillator. + let rtc_clock_src = clocks + .configure_gclk_divider_and_source(ClockGenId::Gclk2, 4, ClockSource::Osc32k, true) + .unwrap(); + clocks.configure_standby(ClockGenId::Gclk2, true); + let _ = clocks.rtc(&rtc_clock_src).unwrap(); + + let red_led: bsp::RedLed = pin_alias!(pins.red_led).into(); + + // Start the monotonic + Mono::start(peripherals.rtc); + + // We can use the RTC in standby for maximum power savings + core.SCB.set_sleepdeep(); + + // Start the blink task + blink::spawn().unwrap(); + + (Shared { red_led }, Local {}) + } + + #[task(shared = [red_led])] + async fn blink(mut cx: blink::Context) { + loop { + // If the LED were a local resource, the lock would not be necessary + cx.shared.red_led.lock(|led| led.toggle().unwrap()); + + Mono::delay(1u64.secs()).await; + } + } +} diff --git a/boards/circuit_playground_express/examples/usb_serial.rs b/boards/circuit_playground_express/examples/usb_serial.rs index a860b9b94843..5ebf2623aa72 100644 --- a/boards/circuit_playground_express/examples/usb_serial.rs +++ b/boards/circuit_playground_express/examples/usb_serial.rs @@ -1,103 +1,135 @@ #![no_std] #![no_main] +use bsp::hal; +use circuit_playground_express as bsp; +use core::mem::MaybeUninit; +use hal::rtc::rtic::rtc_clock; + #[cfg(not(feature = "use_semihosting"))] use panic_halt as _; #[cfg(feature = "use_semihosting")] use panic_semihosting as _; -use cortex_m::asm::delay as cycle_delay; -use cortex_m::peripheral::NVIC; -use usb_device::bus::UsbBusAllocator; -use usb_device::prelude::*; -use usbd_serial::{SerialPort, USB_CLASS_CDC}; +hal::rtc_monotonic!(Mono, rtc_clock::ClockCustom<8_192>); -use bsp::hal; -use bsp::pac; -use circuit_playground_express as bsp; +#[rtic::app(device = bsp::pac, dispatchers = [EVSYS])] +mod app { + use super::*; + use usb_device::bus::UsbBusAllocator; + use usb_device::prelude::*; + use usbd_serial::{SerialPort, USB_CLASS_CDC}; + + use bsp::pin_alias; + use hal::clock::{ClockGenId, ClockSource, GenericClockController}; + use hal::pac::Peripherals; + use hal::prelude::*; + use hal::usb::UsbBus; + + #[local] + struct Local { + // usb_allocator: UsbBusAllocator, + } + + #[shared] + struct Shared { + // The LED could be a local resource, since it is only used in one task + // But we want to showcase shared resources and locking + red_led: bsp::RedLed, + usb_bus: UsbDevice<'static, UsbBus>, + usb_serial: SerialPort<'static, UsbBus>, + } + + #[init(local=[usb_allocator: MaybeUninit> = MaybeUninit::uninit()])] + fn init(cx: init::Context) -> (Shared, Local) { + let mut peripherals: Peripherals = cx.device; + let mut core: rtic::export::Peripherals = cx.core; + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, + ); + let pins = bsp::Pins::new(peripherals.port); -use bsp::{entry, pin_alias}; -use hal::clock::GenericClockController; -use hal::prelude::*; -use hal::usb::UsbBus; -use pac::{interrupt, CorePeripherals, Peripherals}; - -#[entry] -fn main() -> ! { - let mut peripherals = Peripherals::take().unwrap(); - let mut core = CorePeripherals::take().unwrap(); - let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.gclk, - &mut peripherals.pm, - &mut peripherals.sysctrl, - &mut peripherals.nvmctrl, - ); - let pins = bsp::Pins::new(peripherals.port); - let mut red_led: bsp::RedLed = pin_alias!(pins.red_led).into(); - - let bus_allocator = unsafe { - USB_ALLOCATOR = Some(bsp::usb_allocator( + let red_led: bsp::RedLed = pin_alias!(pins.red_led).into(); + + *cx.local.usb_allocator = MaybeUninit::new(bsp::usb_allocator( peripherals.usb, &mut clocks, &mut peripherals.pm, pins.usb_dm, pins.usb_dp, )); - USB_ALLOCATOR.as_ref().unwrap() - }; - - unsafe { - USB_SERIAL = Some(SerialPort::new(bus_allocator)); - USB_BUS = Some( - UsbDeviceBuilder::new(bus_allocator, UsbVidPid(0x16c0, 0x27dd)) - .strings(&[StringDescriptors::new(LangID::EN) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST")]) - .expect("Failed to set strings") - .device_class(USB_CLASS_CDC) - .build(), - ); - } + // The usb allocator is initialized just above, which makes sure that + // usb_allocator is allocated by this point. The reason it is done this + // way is to avoid runtime checks for wheather the allocator is update + // that would be required if we use an Option> = None; -static mut USB_BUS: Option> = None; -static mut USB_SERIAL: Option> = None; - -fn poll_usb() { - unsafe { - if let Some(usb_dev) = USB_BUS.as_mut() { - if let Some(serial) = USB_SERIAL.as_mut() { - usb_dev.poll(&mut [serial]); - let mut buf = [0u8; 64]; - - if let Ok(count) = serial.read(&mut buf) { - for (i, c) in buf.iter().enumerate() { - if i >= count { - break; - } - serial.write(&[*c]).ok(); + #[task(binds = USB, shared = [usb_bus, usb_serial])] + fn poll_usb(cx: poll_usb::Context) { + let mut serial = cx.shared.usb_serial; + let mut usb_bus = cx.shared.usb_bus; + + (&mut serial, &mut usb_bus).lock(|s, b| { + if !b.poll(&mut [s]) { + return; + } + let mut buf = [0u8; 64]; + if let Ok(count) = s.read(&mut buf) { + for (i, c) in buf.iter().enumerate() { + if i >= count { + break; } - }; + s.write(&[*c]).ok(); + } }; - }; - }; -} - -#[interrupt] -fn USB() { - poll_usb(); + }) + } } From 3a309278e1b6fa7a92c6cd723fd577fe14f2eeb7 Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Sat, 27 Dec 2025 23:59:40 -0800 Subject: [PATCH 015/114] chore: fix a few clippy errors for circuit-playground-express --- boards/circuit_playground_express/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/boards/circuit_playground_express/src/lib.rs b/boards/circuit_playground_express/src/lib.rs index ce3ade16a907..0862d903721c 100644 --- a/boards/circuit_playground_express/src/lib.rs +++ b/boards/circuit_playground_express/src/lib.rs @@ -272,7 +272,6 @@ pub fn i2c_master( let gclk0 = clocks.gclk0(); let clock = &clocks.sercom5_core(&gclk0).unwrap(); let freq = clock.freq(); - let baud = baud; let pads = i2c::Pads::new(sda.into(), scl.into()); i2c::Config::new(pm, sercom, pads, freq).baud(baud).enable() } @@ -295,7 +294,6 @@ pub fn uart( ) -> Uart { let gclk0 = clocks.gclk0(); let clock = &clocks.sercom4_core(&gclk0).unwrap(); - let baud = baud.into(); let pads = uart::Pads::default().rx(uart_rx.into()).tx(uart_tx.into()); uart::Config::new(pm, sercom4, pads, clock.freq()) .baud(baud, BaudMode::Fractional(Oversampling::Bits16)) From 7baae6b403449e32aa59f1341ddca0dffc0d496b Mon Sep 17 00:00:00 2001 From: Dox5 Date: Mon, 29 Dec 2025 22:24:57 +0000 Subject: [PATCH 016/114] feat(i2c): add I2C capabilities to labelled pins for arduino_nano33iot (#975) --- hal/src/sercom/pad/impl_pad_thumbv6m.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hal/src/sercom/pad/impl_pad_thumbv6m.rs b/hal/src/sercom/pad/impl_pad_thumbv6m.rs index 29d9da9b2154..9a0424a606ea 100644 --- a/hal/src/sercom/pad/impl_pad_thumbv6m.rs +++ b/hal/src/sercom/pad/impl_pad_thumbv6m.rs @@ -457,13 +457,23 @@ pad_table!( } #[hal_cfg("pb08")] PB08 { + #[cfg(not(feature = "undoc-features"))] #[hal_cfg("sercom4")] D: (Sercom4, Pad0), + + #[cfg(feature = "undoc-features")] + #[hal_cfg("sercom4")] + D: (Sercom4, Pad0) + I2C, } #[hal_cfg("pb09")] PB09 { + #[cfg(not(feature = "undoc-features"))] #[hal_cfg("sercom4")] D: (Sercom4, Pad1), + + #[cfg(feature = "undoc-features")] + #[hal_cfg("sercom4")] + D: (Sercom4, Pad1) + I2C, } #[hal_cfg("pb10")] PB10 { From a1754c596e27fce2fe4d05b09c2fd7ef041600de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 29 Dec 2025 17:32:52 -0500 Subject: [PATCH 017/114] chore: release (#974) * chore: release * grand_central_m4 breaking bump --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Justin Beaurivage --- boards/atsame54_xpro/CHANGELOG.md | 6 ++++++ boards/atsame54_xpro/Cargo.toml | 4 ++-- boards/circuit_playground_express/CHANGELOG.md | 11 +++++++++++ boards/circuit_playground_express/Cargo.toml | 2 +- boards/feather_m0/CHANGELOG.md | 6 ++++++ boards/feather_m0/Cargo.toml | 4 ++-- boards/feather_m4/CHANGELOG.md | 6 ++++++ boards/feather_m4/Cargo.toml | 4 ++-- boards/grand_central_m4/CHANGELOG.md | 6 ++++++ boards/grand_central_m4/Cargo.toml | 2 +- boards/metro_m0/CHANGELOG.md | 6 ++++++ boards/metro_m0/Cargo.toml | 4 ++-- boards/metro_m4/CHANGELOG.md | 6 ++++++ boards/metro_m4/Cargo.toml | 4 ++-- boards/pygamer/CHANGELOG.md | 6 ++++++ boards/pygamer/Cargo.toml | 4 ++-- boards/samd11_bare/CHANGELOG.md | 6 ++++++ boards/samd11_bare/Cargo.toml | 4 ++-- hal/CHANGELOG.md | 6 ++++++ hal/Cargo.toml | 2 +- 20 files changed, 82 insertions(+), 17 deletions(-) diff --git a/boards/atsame54_xpro/CHANGELOG.md b/boards/atsame54_xpro/CHANGELOG.md index 1b2e5d37fd9b..f40286fae0c2 100644 --- a/boards/atsame54_xpro/CHANGELOG.md +++ b/boards/atsame54_xpro/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.13.1](https://github.com/atsamd-rs/atsamd/compare/atsame54_xpro-0.13.0...atsame54_xpro-0.13.1) - 2025-12-29 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.13.0](https://github.com/atsamd-rs/atsamd/compare/atsame54_xpro-0.12.2...atsame54_xpro-0.13.0) - 2025-11-19 ### Other diff --git a/boards/atsame54_xpro/Cargo.toml b/boards/atsame54_xpro/Cargo.toml index 04569f6b463e..097db78b7ae6 100644 --- a/boards/atsame54_xpro/Cargo.toml +++ b/boards/atsame54_xpro/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" name = "atsame54_xpro" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.13.0" +version = "0.13.1" [dependencies.cortex-m-rt] optional = true @@ -24,7 +24,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.0" +version = "0.23.1" [dependencies.usb-device] optional = true diff --git a/boards/circuit_playground_express/CHANGELOG.md b/boards/circuit_playground_express/CHANGELOG.md index 23325715749f..d162aad62cdc 100644 --- a/boards/circuit_playground_express/CHANGELOG.md +++ b/boards/circuit_playground_express/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.12.1](https://github.com/atsamd-rs/atsamd/compare/circuit_playground_express-0.12.0...circuit_playground_express-0.12.1) - 2025-12-29 + +### Dependencies + +- *(circuit-playground-express)* Add RTIC support for CPE ([#966](https://github.com/atsamd-rs/atsamd/pull/966)) + +### Other + +- fix a few clippy errors for circuit-playground-express +- Improve cpe examples + ## [0.12.0](https://github.com/atsamd-rs/atsamd/compare/circuit_playground_express-0.11.1...circuit_playground_express-0.12.0) - 2025-11-20 ### Dependencies diff --git a/boards/circuit_playground_express/Cargo.toml b/boards/circuit_playground_express/Cargo.toml index 8d643abb9436..53ef6e5dda00 100644 --- a/boards/circuit_playground_express/Cargo.toml +++ b/boards/circuit_playground_express/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "circuit_playground_express" categories = ["embedded", "hardware-support", "no-std"] -version = "0.12.0" +version = "0.12.1" authors = ["Paul Sajna "] description = "Board Support crate for the Adafruit Circuit Playground Express" keywords = ["no-std", "arm", "cortex-m", "embedded-hal"] diff --git a/boards/feather_m0/CHANGELOG.md b/boards/feather_m0/CHANGELOG.md index dc1932dfbeea..2526ba4c13f6 100644 --- a/boards/feather_m0/CHANGELOG.md +++ b/boards/feather_m0/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.1](https://github.com/atsamd-rs/atsamd/compare/feather_m0-0.20.0...feather_m0-0.20.1) - 2025-12-29 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.20.0](https://github.com/atsamd-rs/atsamd/compare/feather_m0-0.19.2...feather_m0-0.20.0) - 2025-11-19 ### Other diff --git a/boards/feather_m0/Cargo.toml b/boards/feather_m0/Cargo.toml index 0e826e05ed62..92cb4aeca8ee 100644 --- a/boards/feather_m0/Cargo.toml +++ b/boards/feather_m0/Cargo.toml @@ -9,7 +9,7 @@ name = "feather_m0" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" resolver = "2" -version = "0.20.0" +version = "0.20.1" # for cargo flash [package.metadata] @@ -22,7 +22,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.0" +version = "0.23.1" [dependencies.cortex-m] features = ["critical-section-single-core"] diff --git a/boards/feather_m4/CHANGELOG.md b/boards/feather_m4/CHANGELOG.md index 7a147df11a52..d591c6a6e679 100644 --- a/boards/feather_m4/CHANGELOG.md +++ b/boards/feather_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.18.1](https://github.com/atsamd-rs/atsamd/compare/feather_m4-0.18.0...feather_m4-0.18.1) - 2025-12-29 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.18.0](https://github.com/atsamd-rs/atsamd/compare/feather_m4-0.17.2...feather_m4-0.18.0) - 2025-11-19 ### Changed diff --git a/boards/feather_m4/Cargo.toml b/boards/feather_m4/Cargo.toml index 888fef37e987..970ed16e85dc 100644 --- a/boards/feather_m4/Cargo.toml +++ b/boards/feather_m4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" name = "feather_m4" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.18.0" +version = "0.18.1" # for cargo flash [package.metadata] @@ -26,7 +26,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.0" +version = "0.23.1" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/grand_central_m4/CHANGELOG.md b/boards/grand_central_m4/CHANGELOG.md index f7294c89d5cc..65676cbfcb2d 100644 --- a/boards/grand_central_m4/CHANGELOG.md +++ b/boards/grand_central_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.10.0](https://github.com/atsamd-rs/atsamd/compare/grand_central_m4-0.9.0...grand_central_m4-0.10.0) - 2025-12-29 + +### Dependencies + +- *(grand_central_m4)* Bump HAL dependency to 0.23.0 ([#968](https://github.com/atsamd-rs/atsamd/pull/968)) + ## [0.9.0](https://github.com/atsamd-rs/atsamd/compare/grand_central_m4-0.8.2...grand_central_m4-0.9.0) - 2025-06-22 ### Dependencies diff --git a/boards/grand_central_m4/Cargo.toml b/boards/grand_central_m4/Cargo.toml index 947c078a61ab..5b0f31119e64 100644 --- a/boards/grand_central_m4/Cargo.toml +++ b/boards/grand_central_m4/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grand_central_m4" -version = "0.9.0" +version = "0.10.0" authors = ["Dustin Little "] description = "Board Support crate for the Adafruit Grand Central M4 Express" keywords = ["no-std", "arm", "cortex-m", "embedded-hal"] diff --git a/boards/metro_m0/CHANGELOG.md b/boards/metro_m0/CHANGELOG.md index 12140ba7ea53..71369101a413 100644 --- a/boards/metro_m0/CHANGELOG.md +++ b/boards/metro_m0/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.1](https://github.com/atsamd-rs/atsamd/compare/metro_m0-0.20.0...metro_m0-0.20.1) - 2025-12-29 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.20.0](https://github.com/atsamd-rs/atsamd/compare/metro_m0-0.19.2...metro_m0-0.20.0) - 2025-11-19 ### Other diff --git a/boards/metro_m0/Cargo.toml b/boards/metro_m0/Cargo.toml index 6632c423f387..55afe6feebf7 100644 --- a/boards/metro_m0/Cargo.toml +++ b/boards/metro_m0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "metro_m0" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.20.0" +version = "0.20.1" # for cargo flash [package.metadata] @@ -25,7 +25,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.0" +version = "0.23.1" [dependencies.rtic] features = ["thumbv6-backend"] diff --git a/boards/metro_m4/CHANGELOG.md b/boards/metro_m4/CHANGELOG.md index d628ed846e56..7df0dd28976b 100644 --- a/boards/metro_m4/CHANGELOG.md +++ b/boards/metro_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.19.1](https://github.com/atsamd-rs/atsamd/compare/metro_m4-0.19.0...metro_m4-0.19.1) - 2025-12-29 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.19.0](https://github.com/atsamd-rs/atsamd/compare/metro_m4-0.18.2...metro_m4-0.19.0) - 2025-11-19 ### Changed diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index 5974e3ef41c2..8115fc1f781a 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "metro_m4" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.19.0" +version = "0.19.1" # for cargo flash [package.metadata] @@ -21,7 +21,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.0" +version = "0.23.1" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/pygamer/CHANGELOG.md b/boards/pygamer/CHANGELOG.md index 43b8fa4325ec..e32a1aafce10 100644 --- a/boards/pygamer/CHANGELOG.md +++ b/boards/pygamer/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.1](https://github.com/atsamd-rs/atsamd/compare/pygamer-0.16.0...pygamer-0.16.1) - 2025-12-29 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.16.0](https://github.com/atsamd-rs/atsamd/compare/pygamer-0.15.2...pygamer-0.16.0) - 2025-11-19 ### Changed diff --git a/boards/pygamer/Cargo.toml b/boards/pygamer/Cargo.toml index 417265d15572..d8fda2e32c40 100644 --- a/boards/pygamer/Cargo.toml +++ b/boards/pygamer/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" name = "pygamer" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.16.0" +version = "0.16.1" [dependencies] cortex-m = {version = "0.7", features = ["critical-section-single-core"]} @@ -27,7 +27,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.0" +version = "0.23.1" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/samd11_bare/CHANGELOG.md b/boards/samd11_bare/CHANGELOG.md index 055b9ebc605a..d0b1db8a00cd 100644 --- a/boards/samd11_bare/CHANGELOG.md +++ b/boards/samd11_bare/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.1](https://github.com/atsamd-rs/atsamd/compare/samd11_bare-0.16.0...samd11_bare-0.16.1) - 2025-12-29 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.16.0](https://github.com/atsamd-rs/atsamd/compare/samd11_bare-0.15.2...samd11_bare-0.16.0) - 2025-11-19 ### Other diff --git a/boards/samd11_bare/Cargo.toml b/boards/samd11_bare/Cargo.toml index 9bccad655a65..7cb77e1a32d6 100644 --- a/boards/samd11_bare/Cargo.toml +++ b/boards/samd11_bare/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" name = "samd11_bare" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.16.0" +version = "0.16.1" # for cargo flash [package.metadata] @@ -24,7 +24,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.0" +version = "0.23.1" [dependencies.rtic] features = ["thumbv6-backend"] diff --git a/hal/CHANGELOG.md b/hal/CHANGELOG.md index 6acbf6f78281..84f3a819cfcf 100644 --- a/hal/CHANGELOG.md +++ b/hal/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.23.1](https://github.com/atsamd-rs/atsamd/compare/atsamd-hal-0.23.0...atsamd-hal-0.23.1) - 2025-12-29 + +### Added + +- *(i2c)* add I2C capabilities to labelled pins for arduino_nano33iot ([#975](https://github.com/atsamd-rs/atsamd/pull/975)) + ## [0.23.0](https://github.com/atsamd-rs/atsamd/compare/atsamd-hal-0.22.2...atsamd-hal-0.23.0) - 2025-11-19 ### Added diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 3bf305003f54..0c6ff1f0c449 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -20,7 +20,7 @@ name = "atsamd-hal" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" rust-version = "1.85.1" -version = "0.23.0" +version = "0.23.1" [package.metadata.docs.rs] features = ["samd21g", "samd21g-rt", "usb", "dma", "async", "rtic"] From ca2ff93522ec167e96cb5f185258ddb92ee80037 Mon Sep 17 00:00:00 2001 From: Dox5 Date: Mon, 29 Dec 2025 22:59:36 +0000 Subject: [PATCH 018/114] deps(nano33iot)!: Update nano33iot HAL dependency to 0.23.0 (#971) --- boards/arduino_nano33iot/Cargo.toml | 16 +++---- .../examples/blinky_basic.rs | 10 ++--- .../arduino_nano33iot/examples/i2c_ssd1306.rs | 17 ++++---- boards/arduino_nano33iot/examples/serial.rs | 16 +++---- .../arduino_nano33iot/examples/spi_st7735.rs | 17 ++++---- .../arduino_nano33iot/examples/usb_logging.rs | 22 +++++----- boards/arduino_nano33iot/src/lib.rs | 43 +++++++++++-------- 7 files changed, 74 insertions(+), 67 deletions(-) diff --git a/boards/arduino_nano33iot/Cargo.toml b/boards/arduino_nano33iot/Cargo.toml index 0bc2a015aa85..1fa5734badee 100644 --- a/boards/arduino_nano33iot/Cargo.toml +++ b/boards/arduino_nano33iot/Cargo.toml @@ -15,11 +15,12 @@ version = "0.7" optional = true [dependencies.atsamd-hal] -version = "0.14" +version = "0.23.0" default-features = false +features = ["undoc-features"] [dependencies.usb-device] -version = "0.2" +version = "0.3.2" optional = true [dependencies.rand] @@ -28,10 +29,10 @@ default-features = false features = ["small_rng"] [dev-dependencies] -cortex-m = "0.7" -usbd-serial = "0.1" -panic-halt = "0.2" -panic-semihosting = "0.5" +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } +usbd-serial = "0.2.2" +panic-halt = "1.0.0" +panic-semihosting = "0.6" embedded-graphics = "0.7" st7735-lcd = "0.8" ssd1306 = { version = "0.7", features = ["graphics"] } @@ -41,7 +42,6 @@ ssd1306 = { version = "0.7", features = ["graphics"] } default = ["rt", "atsamd-hal/samd21g"] rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"] usb = ["atsamd-hal/usb", "usb-device"] -unproven = ["atsamd-hal/unproven"] use_semihosting = [] # for cargo flash @@ -53,7 +53,7 @@ name = "blinky_basic" [[example]] name = "usb_logging" -required-features = ["usb", "unproven"] +required-features = ["usb"] [[example]] name = "serial" diff --git a/boards/arduino_nano33iot/examples/blinky_basic.rs b/boards/arduino_nano33iot/examples/blinky_basic.rs index 665d6793c6ed..eff8e6f2c167 100644 --- a/boards/arduino_nano33iot/examples/blinky_basic.rs +++ b/boards/arduino_nano33iot/examples/blinky_basic.rs @@ -20,12 +20,12 @@ fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT); + let pins = bsp::Pins::new(peripherals.port); let mut led: bsp::Led = pins.led_sck.into(); let mut delay = Delay::new(core.SYST, &mut clocks); diff --git a/boards/arduino_nano33iot/examples/i2c_ssd1306.rs b/boards/arduino_nano33iot/examples/i2c_ssd1306.rs index a84e40136961..41bbb464a695 100644 --- a/boards/arduino_nano33iot/examples/i2c_ssd1306.rs +++ b/boards/arduino_nano33iot/examples/i2c_ssd1306.rs @@ -28,7 +28,6 @@ use hal::clock::GenericClockController; use hal::delay::Delay; use hal::pac::{CorePeripherals, Peripherals}; use hal::prelude::*; -use hal::time::KiloHertz; use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306}; @@ -42,21 +41,21 @@ fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT); + let pins = bsp::Pins::new(peripherals.port); let mut delay = Delay::new(core.SYST, &mut clocks); delay.delay_ms(BOOT_DELAY_MS); let i2c = bsp::i2c_master( &mut clocks, - KiloHertz(400), - peripherals.SERCOM4, - &mut peripherals.PM, + 400.kHz(), + peripherals.sercom4, + &mut peripherals.pm, pins.sda, pins.scl, ); diff --git a/boards/arduino_nano33iot/examples/serial.rs b/boards/arduino_nano33iot/examples/serial.rs index aa7a264d9da8..1b9d7e1e5f42 100644 --- a/boards/arduino_nano33iot/examples/serial.rs +++ b/boards/arduino_nano33iot/examples/serial.rs @@ -20,19 +20,19 @@ fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT); + let pins = bsp::Pins::new(peripherals.port); let mut delay = Delay::new(core.SYST, &mut clocks); let mut uart = bsp::uart( &mut clocks, - 9600.hz(), - peripherals.SERCOM5, - &mut peripherals.PM, + 9600.Hz(), + peripherals.sercom5, + &mut peripherals.pm, pins.rx, pins.tx, ); diff --git a/boards/arduino_nano33iot/examples/spi_st7735.rs b/boards/arduino_nano33iot/examples/spi_st7735.rs index a867ae5ae116..235af95347db 100644 --- a/boards/arduino_nano33iot/examples/spi_st7735.rs +++ b/boards/arduino_nano33iot/examples/spi_st7735.rs @@ -17,7 +17,6 @@ use hal::clock::GenericClockController; use hal::delay::Delay; use hal::pac::{CorePeripherals, Peripherals}; use hal::prelude::*; -use hal::time::MegaHertz; use embedded_graphics::{ image::{Image, ImageRaw, ImageRawLE}, @@ -35,21 +34,21 @@ fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT); + let pins = bsp::Pins::new(peripherals.port); let mut delay = Delay::new(core.SYST, &mut clocks); delay.delay_ms(BOOT_DELAY_MS); let spi = bsp::spi_master( &mut clocks, - MegaHertz(16), - peripherals.SERCOM1, - &mut peripherals.PM, + 16.MHz(), + peripherals.sercom1, + &mut peripherals.pm, pins.led_sck, pins.mosi, pins.miso, diff --git a/boards/arduino_nano33iot/examples/usb_logging.rs b/boards/arduino_nano33iot/examples/usb_logging.rs index 4c0d32394c88..a8ae0f95ff70 100644 --- a/boards/arduino_nano33iot/examples/usb_logging.rs +++ b/boards/arduino_nano33iot/examples/usb_logging.rs @@ -30,19 +30,19 @@ fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let mut core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT); + let pins = bsp::Pins::new(peripherals.port); let mut led: bsp::Led = pins.led_sck.into(); let bus_allocator = unsafe { USB_ALLOCATOR = Some(bsp::usb_allocator( - peripherals.USB, + peripherals.usb, &mut clocks, - &mut peripherals.PM, + &mut peripherals.pm, pins.usb_dm, pins.usb_dp, )); @@ -53,9 +53,11 @@ fn main() -> ! { USB_SERIAL = Some(SerialPort::new(&bus_allocator)); USB_BUS = Some( UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x2222, 0x3333)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") + .strings(&[StringDescriptors::new(LangID::EN_US) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST")]) + .unwrap() .device_class(USB_CLASS_CDC) .build(), ); diff --git a/boards/arduino_nano33iot/src/lib.rs b/boards/arduino_nano33iot/src/lib.rs index 60e100654355..9334e288dd48 100644 --- a/boards/arduino_nano33iot/src/lib.rs +++ b/boards/arduino_nano33iot/src/lib.rs @@ -8,8 +8,7 @@ pub use hal::ehal; pub use hal::pac; use hal::clock::GenericClockController; -use hal::sercom::v2::{spi, uart, Sercom1, Sercom2, Sercom5}; -use hal::sercom::I2CMaster4; +use hal::sercom::{i2c, spi, uart, Sercom1, Sercom2, Sercom4, Sercom5}; use hal::time::Hertz; #[cfg(feature = "usb")] @@ -213,9 +212,9 @@ hal::bsp_pins!( #[cfg(feature = "usb")] pub fn usb_allocator( - usb: pac::USB, + usb: pac::Usb, clocks: &mut GenericClockController, - pm: &mut pac::PM, + pm: &mut pac::Pm, dm: impl Into, dp: impl Into, ) -> UsbBusAllocator { @@ -225,21 +224,29 @@ pub fn usb_allocator( UsbBusAllocator::new(UsbBus::new(usb_clock, pm, dm, dp, usb)) } +/// I2C Pads +pub type I2cPads = i2c::Pads; + +/// I2C device for labelled SDA & SCL pads +pub type I2c = i2c::I2c>; + /// Convenience for setting up the labelled SDA, SCL pins to /// operate as an I2C master running at the specified frequency. pub fn i2c_master( clocks: &mut GenericClockController, - bus_speed: impl Into, - sercom4: pac::SERCOM4, - pm: &mut pac::PM, + baud: impl Into, + sercom: pac::Sercom4, + pm: &mut pac::Pm, sda: impl Into, scl: impl Into, -) -> I2CMaster4 { +) -> I2c { let gclk0 = &clocks.gclk0(); let clock = &clocks.sercom4_core(&gclk0).unwrap(); - let (bus_speed, sda, scl) = (bus_speed.into(), sda.into(), scl.into()); + let freq = clock.freq(); + let baud = baud.into(); + let pads = I2cPads::new(sda.into(), scl.into()); - I2CMaster4::new(clock, bus_speed, sercom4, pm, sda, scl) + i2c::Config::new(pm, sercom, pads, freq).baud(baud).enable() } /// UART pads @@ -252,8 +259,8 @@ pub type Uart = uart::Uart, uart::Duplex>; pub fn uart( clocks: &mut GenericClockController, baud: impl Into, - sercom5: pac::SERCOM5, - pm: &mut pac::PM, + sercom5: pac::Sercom5, + pm: &mut pac::Pm, rx: impl Into, tx: impl Into, ) -> Uart { @@ -283,8 +290,8 @@ pub type Spi = spi::Spi, spi::Duplex>; pub fn spi_master( clocks: &mut GenericClockController, baud: impl Into, - sercom1: pac::SERCOM1, - pm: &mut pac::PM, + sercom1: pac::Sercom1, + pm: &mut pac::Pm, sck: impl Into, mosi: impl Into, miso: impl Into, @@ -295,7 +302,7 @@ pub fn spi_master( let pads = spi::Pads::default().data_in(miso).data_out(mosi).sclk(sclk); spi::Config::new(pm, sercom1, pads, clock.freq()) - .baud(baud) + .baud(baud.into()) .spi_mode(spi::MODE_0) .enable() } @@ -316,8 +323,8 @@ pub type NinaSpi = spi::Spi, spi::Duplex>; pub fn nina_spi_master( clocks: &mut GenericClockController, baud: impl Into, - sercom2: pac::SERCOM2, - pm: &mut pac::PM, + sercom2: pac::Sercom2, + pm: &mut pac::Pm, sck: impl Into, mosi: impl Into, miso: impl Into, @@ -328,7 +335,7 @@ pub fn nina_spi_master( let pads = spi::Pads::default().data_in(miso).data_out(mosi).sclk(sclk); spi::Config::new(pm, sercom2, pads, clock.freq()) - .baud(baud) + .baud(baud.into()) .spi_mode(spi::MODE_0) .enable() } From d49d3fd6a04977814b60cd80113c1ff7699a6767 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 29 Dec 2025 18:04:07 -0500 Subject: [PATCH 019/114] chore(arduino_nano33iot): release v0.8.0 (#976) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- boards/arduino_nano33iot/CHANGELOG.md | 6 ++++++ boards/arduino_nano33iot/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/boards/arduino_nano33iot/CHANGELOG.md b/boards/arduino_nano33iot/CHANGELOG.md index 67c09979cbf9..267cc00ff81c 100644 --- a/boards/arduino_nano33iot/CHANGELOG.md +++ b/boards/arduino_nano33iot/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.8.0](https://github.com/atsamd-rs/atsamd/compare/arduino_nano33iot-0.7.2...arduino_nano33iot-0.8.0) - 2025-12-29 + +### Dependencies + +- *(nano33iot)* [**breaking**] Update nano33iot HAL dependency to 0.23.0 ([#971](https://github.com/atsamd-rs/atsamd/pull/971)) + ## [0.7.2](https://github.com/atsamd-rs/atsamd/compare/arduino_nano33iot-0.7.1...arduino_nano33iot-0.7.2) - 2024-10-17 ### Refactored diff --git a/boards/arduino_nano33iot/Cargo.toml b/boards/arduino_nano33iot/Cargo.toml index 1fa5734badee..29ffe584bc9d 100644 --- a/boards/arduino_nano33iot/Cargo.toml +++ b/boards/arduino_nano33iot/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arduino_nano33iot" -version = "0.7.2" +version = "0.8.0" authors = ["Gus Wynn "] description = "Board Support crate for the Arduino Nano 33 IOT" keywords = ["no-std", "arm", "cortex-m", "embedded-hal", "arduino"] From 09a218870c5b741aa6162736e51488436d43790d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20W=C4=99grzyn?= Date: Tue, 13 Jan 2026 18:29:54 +0100 Subject: [PATCH 020/114] fix(pwm): Fix for off-by-one in get_max_duty() (#959) --- hal/src/peripherals/pwm/d11.rs | 4 ++-- hal/src/peripherals/pwm/d5x.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hal/src/peripherals/pwm/d11.rs b/hal/src/peripherals/pwm/d11.rs index a640912a34ce..0b1b2bfb8497 100644 --- a/hal/src/peripherals/pwm/d11.rs +++ b/hal/src/peripherals/pwm/d11.rs @@ -97,7 +97,7 @@ impl $crate::ehal::pwm::SetDutyCycle for $TYPE { fn max_duty_cycle(&self) -> u16 { let count = self.tc.count16(); let top = count.cc(0).read().cc().bits(); - top + top.saturating_add(1) } fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { @@ -252,7 +252,7 @@ impl $crate::ehal_02::Pwm for $TYPE { fn get_max_duty(&self) -> Self::Duty { let top = self.tcc.per().read().bits(); - top + top + 1 } fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { diff --git a/hal/src/peripherals/pwm/d5x.rs b/hal/src/peripherals/pwm/d5x.rs index a9094fac4ac6..f101e3b494b2 100644 --- a/hal/src/peripherals/pwm/d5x.rs +++ b/hal/src/peripherals/pwm/d5x.rs @@ -227,7 +227,7 @@ impl $crate::ehal::pwm::SetDutyCycle for $TYPE { fn max_duty_cycle(&self) -> u16 { let count = self.tc.count16(); let top = count.cc(0).read().cc().bits(); - top + top.saturating_add(1) } fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { @@ -637,7 +637,7 @@ impl $crate::ehal_02::Pwm for $TYPE { fn get_max_duty(&self) -> Self::Duty { let top = self.tcc.per().read().bits(); - top + top + 1 } fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { From ef02fe3e21031da27aaef629368105962363b370 Mon Sep 17 00:00:00 2001 From: "Ashcon Mohseninia (RAND_ASH)" Date: Fri, 6 Feb 2026 14:32:57 +0000 Subject: [PATCH 021/114] feat(usb): USB allocation rework and simplification (#963) * Add in option for more USB buffer sizes * Simplify USB buffer allocation and prevent panic --- hal/Cargo.toml | 15 ++++- hal/src/peripherals/usb/d11/buffer.rs | 92 +++++++++++++++++++++++++++ hal/src/peripherals/usb/d11/bus.rs | 59 +++-------------- hal/src/peripherals/usb/d11/mod.rs | 2 + hal/src/peripherals/usb/d5x/buffer.rs | 92 +++++++++++++++++++++++++++ hal/src/peripherals/usb/d5x/bus.rs | 59 +++-------------- hal/src/peripherals/usb/d5x/mod.rs | 2 + 7 files changed, 219 insertions(+), 102 deletions(-) create mode 100644 hal/src/peripherals/usb/d11/buffer.rs create mode 100644 hal/src/peripherals/usb/d5x/buffer.rs diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 0c6ff1f0c449..f2c658feed3c 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -195,10 +195,21 @@ dma = [] max-channels = ["dma"] rtic = ["rtic-monotonic", "rtic-time", "portable-atomic"] sdmmc = ["embedded-sdmmc"] -usb = ["usb-device"] use_rtt = ["jlink_rtt"] undoc-features = [] +# USB features +usb = ["usb-device"] # Default with 2048 byte buffer + +# USB buffer sizes +# These denote the size of the global buffer for all USB endpoints. +# The buffer is split between all device endpoints equally + +usb-buffer-1k = ["usb"] # 1024 byte buffer shared between all USB endpoints +usb-buffer-2k = ["usb"] # 2048 byte buffer shared between all USB endpoints (Default) +usb-buffer-4k = ["usb"] # 4096 byte buffer shared between all USB endpoints +usb-buffer-8k = ["usb"] # 8192 byte buffer shared between all USB endpoints + #=============================================================================== # Implementation-details #=============================================================================== @@ -209,4 +220,4 @@ undoc-features = [] # The `device` feature tells the HAL that a device has been selected from the # feature list. It exists mostly to provide better error messages. -device = [] +device = [] \ No newline at end of file diff --git a/hal/src/peripherals/usb/d11/buffer.rs b/hal/src/peripherals/usb/d11/buffer.rs new file mode 100644 index 000000000000..ddc21b5b4372 --- /dev/null +++ b/hal/src/peripherals/usb/d11/buffer.rs @@ -0,0 +1,92 @@ +use core::ops::{Deref, DerefMut}; +use cortex_m::singleton; +use usb_device::{Result as UsbResult, UsbError}; + +/// Size of the buffer that holds ALL USB endpoint buffers +pub const BUFFER_SIZE: usize = { + #[cfg(feature = "usb-buffer-1k")] + { + 1024 + } + #[cfg(feature = "usb-buffer-4k")] + { + 4098 + } + #[cfg(feature = "usb-buffer-8k")] + { + 8192 + } + #[cfg(not(any( + feature = "usb-buffer-1k", + feature = "usb-buffer-4k", + feature = "usb-buffer-8k" + )))] + { + 2048 // Default + } +}; + +/// Size of each USB endpoints buffer (Always guaranteed to be divisible by 4) +pub const ALLOC_SIZE_MAX_PER_EP: usize = BUFFER_SIZE / 16; + +/// USB endpoint storage buffer, aligned to 4 bytes +#[repr(C, align(4))] +pub struct Buffer { + inner: [u8; BUFFER_SIZE], +} + +impl Default for Buffer { + fn default() -> Self { + Self { + inner: [0; BUFFER_SIZE], + } + } +} + +impl Deref for Buffer { + type Target = [u8; BUFFER_SIZE]; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Buffer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +fn buffer() -> &'static mut Buffer { + singleton!(: Buffer = Buffer::default() ).unwrap() +} + +pub struct BufferAllocator { + buffers: &'static mut Buffer, + next_buf: usize, +} + +impl Default for BufferAllocator { + fn default() -> Self { + Self { + next_buf: 0, + buffers: buffer(), + } + } +} + +impl BufferAllocator { + + /// Allocates a fixed buffer of [`ALLOC_SIZE_MAX_PER_EP`] + pub fn allocate_buffer(&mut self) -> UsbResult<*mut u8> { + // Do all range checks first + if self.next_buf >= self.buffers.len() + || self.next_buf + ALLOC_SIZE_MAX_PER_EP > self.buffers.len() + { + return Err(UsbError::EndpointMemoryOverflow); + } + + let start_addr = &mut self.buffers[self.next_buf] as *mut u8; + self.next_buf += ALLOC_SIZE_MAX_PER_EP; + Ok(start_addr) + } +} diff --git a/hal/src/peripherals/usb/d11/bus.rs b/hal/src/peripherals/usb/d11/bus.rs index 45315e94bbd3..fb765e04ec48 100644 --- a/hal/src/peripherals/usb/d11/bus.rs +++ b/hal/src/peripherals/usb/d11/bus.rs @@ -11,13 +11,12 @@ use crate::clock; use crate::gpio::{AlternateG, AnyPin, Pin, PA24, PA25}; use crate::pac::usb::Device; use crate::pac::{Pm, Usb}; +use crate::usb::buffer::*; use crate::usb::devicedesc::DeviceDescBank; use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::cell::{Ref, RefCell, RefMut}; use core::marker::PhantomData; -use core::mem; -use cortex_m::singleton; -use critical_section::{with as disable_interrupts, Mutex}; +use critical_section::{Mutex, with as disable_interrupts}; use usb_device::bus::PollResult; use usb_device::endpoint::{EndpointAddress, EndpointType}; use usb_device::{Result as UsbResult, UsbDirection, UsbError}; @@ -146,51 +145,6 @@ impl AllEndpoints { } } -// FIXME: replace with more general heap? -const BUFFER_SIZE: usize = 2048; -fn buffer() -> &'static mut [u8; BUFFER_SIZE] { - singleton!(: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE] ).unwrap() -} - -struct BufferAllocator { - buffers: &'static mut [u8; BUFFER_SIZE], - next_buf: u16, -} - -impl BufferAllocator { - fn new() -> Self { - Self { - next_buf: 0, - buffers: buffer(), - } - } - - fn allocate_buffer(&mut self, size: u16) -> UsbResult<*mut u8> { - debug_assert!(size & 1 == 0); - - let start_addr = &mut self.buffers[self.next_buf as usize] as *mut u8; - let buf_end = unsafe { start_addr.add(BUFFER_SIZE) }; - - // The address must be 32-bit aligned, so allow for that here - // by offsetting by an appropriate alignment. - let offset = start_addr.align_offset(mem::align_of::()); - let start_addr = unsafe { start_addr.add(offset) }; - - if start_addr >= buf_end { - return Err(UsbError::EndpointMemoryOverflow); - } - - let end_addr = unsafe { start_addr.offset(size as isize) }; - if end_addr > buf_end { - return Err(UsbError::EndpointMemoryOverflow); - } - - self.next_buf = unsafe { end_addr.sub(self.buffers.as_ptr() as usize) as u16 }; - - Ok(start_addr) - } -} - struct Inner { desc: RefCell, _dm_pad: Pin, @@ -498,7 +452,7 @@ impl UsbBus { _dm_pad: dm_pad.into().into_mode::(), _dp_pad: dp_pad.into().into_mode::(), desc, - buffers: RefCell::new(BufferAllocator::new()), + buffers: RefCell::new(BufferAllocator::default()), endpoints: RefCell::new(AllEndpoints::new()), }; @@ -695,7 +649,12 @@ impl Inner { _ => return Err(UsbError::Unsupported), }; - let buffer = self.buffers.borrow_mut().allocate_buffer(allocated_size)?; + // packet size is too big to fit into an endpoint buffer + if allocated_size > ALLOC_SIZE_MAX_PER_EP as u16 { + return Err(UsbError::EndpointMemoryOverflow); + } + + let buffer = self.buffers.borrow_mut().allocate_buffer()?; let mut endpoints = self.endpoints.borrow_mut(); diff --git a/hal/src/peripherals/usb/d11/mod.rs b/hal/src/peripherals/usb/d11/mod.rs index 73fd05566fe4..4afd47d2a380 100644 --- a/hal/src/peripherals/usb/d11/mod.rs +++ b/hal/src/peripherals/usb/d11/mod.rs @@ -7,7 +7,9 @@ use crate::gpio::{ pub use usb_device; +mod buffer; mod bus; +pub use self::buffer::*; pub use self::bus::UsbBus; mod devicedesc; diff --git a/hal/src/peripherals/usb/d5x/buffer.rs b/hal/src/peripherals/usb/d5x/buffer.rs new file mode 100644 index 000000000000..ddc21b5b4372 --- /dev/null +++ b/hal/src/peripherals/usb/d5x/buffer.rs @@ -0,0 +1,92 @@ +use core::ops::{Deref, DerefMut}; +use cortex_m::singleton; +use usb_device::{Result as UsbResult, UsbError}; + +/// Size of the buffer that holds ALL USB endpoint buffers +pub const BUFFER_SIZE: usize = { + #[cfg(feature = "usb-buffer-1k")] + { + 1024 + } + #[cfg(feature = "usb-buffer-4k")] + { + 4098 + } + #[cfg(feature = "usb-buffer-8k")] + { + 8192 + } + #[cfg(not(any( + feature = "usb-buffer-1k", + feature = "usb-buffer-4k", + feature = "usb-buffer-8k" + )))] + { + 2048 // Default + } +}; + +/// Size of each USB endpoints buffer (Always guaranteed to be divisible by 4) +pub const ALLOC_SIZE_MAX_PER_EP: usize = BUFFER_SIZE / 16; + +/// USB endpoint storage buffer, aligned to 4 bytes +#[repr(C, align(4))] +pub struct Buffer { + inner: [u8; BUFFER_SIZE], +} + +impl Default for Buffer { + fn default() -> Self { + Self { + inner: [0; BUFFER_SIZE], + } + } +} + +impl Deref for Buffer { + type Target = [u8; BUFFER_SIZE]; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Buffer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +fn buffer() -> &'static mut Buffer { + singleton!(: Buffer = Buffer::default() ).unwrap() +} + +pub struct BufferAllocator { + buffers: &'static mut Buffer, + next_buf: usize, +} + +impl Default for BufferAllocator { + fn default() -> Self { + Self { + next_buf: 0, + buffers: buffer(), + } + } +} + +impl BufferAllocator { + + /// Allocates a fixed buffer of [`ALLOC_SIZE_MAX_PER_EP`] + pub fn allocate_buffer(&mut self) -> UsbResult<*mut u8> { + // Do all range checks first + if self.next_buf >= self.buffers.len() + || self.next_buf + ALLOC_SIZE_MAX_PER_EP > self.buffers.len() + { + return Err(UsbError::EndpointMemoryOverflow); + } + + let start_addr = &mut self.buffers[self.next_buf] as *mut u8; + self.next_buf += ALLOC_SIZE_MAX_PER_EP; + Ok(start_addr) + } +} diff --git a/hal/src/peripherals/usb/d5x/bus.rs b/hal/src/peripherals/usb/d5x/bus.rs index 1441ff780dc2..17fe18ea14db 100644 --- a/hal/src/peripherals/usb/d5x/bus.rs +++ b/hal/src/peripherals/usb/d5x/bus.rs @@ -12,12 +12,11 @@ use crate::gpio::{AlternateH, AnyPin, Pin, PA24, PA25}; use crate::pac; use crate::pac::usb::Device; use crate::pac::{Mclk, Usb}; +use crate::usb::buffer::*; use crate::usb::devicedesc::DeviceDescBank; use core::cell::{Ref, RefCell, RefMut}; use core::marker::PhantomData; -use core::mem; -use cortex_m::singleton; -use critical_section::{with as disable_interrupts, Mutex}; +use critical_section::{Mutex, with as disable_interrupts}; use usb_device::bus::PollResult; use usb_device::endpoint::{EndpointAddress, EndpointType}; use usb_device::{Result as UsbResult, UsbDirection, UsbError}; @@ -146,51 +145,6 @@ impl AllEndpoints { } } -// FIXME: replace with more general heap? -const BUFFER_SIZE: usize = 2048; -fn buffer() -> &'static mut [u8; BUFFER_SIZE] { - singleton!(: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE] ).unwrap() -} - -struct BufferAllocator { - buffers: &'static mut [u8; BUFFER_SIZE], - next_buf: u16, -} - -impl BufferAllocator { - fn new() -> Self { - Self { - next_buf: 0, - buffers: buffer(), - } - } - - fn allocate_buffer(&mut self, size: u16) -> UsbResult<*mut u8> { - debug_assert!(size & 1 == 0); - - let start_addr = &mut self.buffers[self.next_buf as usize] as *mut u8; - let buf_end = unsafe { start_addr.add(BUFFER_SIZE) }; - - // The address must be 32-bit aligned, so allow for that here - // by offsetting by an appropriate alignment. - let offset = start_addr.align_offset(mem::align_of::()); - let start_addr = unsafe { start_addr.add(offset) }; - - if start_addr >= buf_end { - return Err(UsbError::EndpointMemoryOverflow); - } - - let end_addr = unsafe { start_addr.offset(size as isize) }; - if end_addr > buf_end { - return Err(UsbError::EndpointMemoryOverflow); - } - - self.next_buf = unsafe { end_addr.sub(self.buffers.as_ptr() as usize) as u16 }; - - Ok(start_addr) - } -} - struct Inner { desc: RefCell, _dm_pad: Pin, @@ -541,7 +495,7 @@ impl UsbBus { _dm_pad: dm_pad.into().into_mode::(), _dp_pad: dp_pad.into().into_mode::(), desc, - buffers: RefCell::new(BufferAllocator::new()), + buffers: RefCell::new(BufferAllocator::default()), endpoints: RefCell::new(AllEndpoints::new()), }; @@ -722,7 +676,12 @@ impl Inner { _ => return Err(UsbError::Unsupported), }; - let buffer = self.buffers.borrow_mut().allocate_buffer(allocated_size)?; + // packet size is too big to fit into an endpoint buffer + if allocated_size > ALLOC_SIZE_MAX_PER_EP as u16 { + return Err(UsbError::EndpointMemoryOverflow); + } + + let buffer = self.buffers.borrow_mut().allocate_buffer()?; let mut endpoints = self.endpoints.borrow_mut(); diff --git a/hal/src/peripherals/usb/d5x/mod.rs b/hal/src/peripherals/usb/d5x/mod.rs index 10d22657214e..82cc5be5dec5 100644 --- a/hal/src/peripherals/usb/d5x/mod.rs +++ b/hal/src/peripherals/usb/d5x/mod.rs @@ -7,7 +7,9 @@ use crate::gpio::{ pub use usb_device; +mod buffer; mod bus; +pub use self::buffer::*; pub use self::bus::UsbBus; mod devicedesc; From 8f846447e22d7ab6cd14ad3b8f63b3354c8c5e6c Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Fri, 20 Feb 2026 15:53:36 -0500 Subject: [PATCH 022/114] fix(dmac): Check+document that the DMAC transfers are smaller than u16::MAX long (#984) --- hal/src/dmac/channel/mod.rs | 15 +++++++++++---- hal/src/dmac/mod.rs | 6 +++++- hal/src/dmac/transfer.rs | 11 +++++++++-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/hal/src/dmac/channel/mod.rs b/hal/src/dmac/channel/mod.rs index 26bcaf822b86..68d0da72e818 100644 --- a/hal/src/dmac/channel/mod.rs +++ b/hal/src/dmac/channel/mod.rs @@ -543,6 +543,8 @@ impl Channel { /// compatible lengths. You must guarantee that: /// - Either `source` or `dest` has a buffer length of 1, or /// - Both buffers have the same length. + /// * The source and destination buffers must have a length smaller or equal + /// to `u16::MAX`. /// * You must ensure that the transfer is completed or stopped before /// returning the [`Channel`]. Doing otherwise breaks type safety, because /// a [`Ready`] channel would still be in the middle of a transfer. @@ -676,10 +678,6 @@ impl Channel { /// /// # Safety /// - /// * This method does not check that the two provided buffers have - /// compatible lengths. You must guarantee that: - /// - Either `source` or `dest` has a buffer length of 1, or - /// - Both buffers have the same length. /// * You must ensure that the transfer is completed or stopped before /// returning the [`Channel`]. Doing otherwise breaks type safety, because /// a [`ReadyFuture`] channel would still be in the middle of a transfer. @@ -841,6 +839,13 @@ impl Default for InterruptFlags { /// location, or be null. They must not be circular (ie, points to itself). /// Any linked transfer must strictly be a read transaction (destination /// pointer is a byte buffer, source pointer is the SERCOM DATA register). +/// +/// * The length of both the source and destination buffers must be smaller or +/// equal to `u16::MAX`. +/// +/// * Either: +/// - `source` or `dest` has a buffer length of 1, or +/// - Both buffers have the same length. #[inline] pub(crate) unsafe fn write_descriptor>( descriptor: &mut DmacDescriptor, @@ -856,6 +861,8 @@ pub(crate) unsafe fn write_descriptor let dst_inc = destination.incrementing(); let dst_len = destination.buffer_len(); + // This is sufficient since buffers of unequal lengths breaks the safety + // contract if neither buffer has a length of 1. let length = core::cmp::max(src_len, dst_len); // Channel::xfer_complete() tests the channel enable bit, which indicates diff --git a/hal/src/dmac/mod.rs b/hal/src/dmac/mod.rs index c1d4980a9daf..c6cbc8207943 100644 --- a/hal/src/dmac/mod.rs +++ b/hal/src/dmac/mod.rs @@ -264,12 +264,16 @@ pub enum Error { /// Buffers need to either have the same length in beats, or one should have /// length == 1. In cases where one buffer is length 1, that buffer will be /// the source or destination of each beat in the transfer. If both buffers - /// had length >1, but not equal to each other, then it would not be clear + /// had length > 1, but not equal to each other, then it would not be clear /// how to structure the transfer. LengthMismatch, + /// The DMAC only supports up to `u16::MAX` beats in a single transfer. + TooManyBeats, + /// Operation is not valid in the current state of the object. InvalidState, + /// Chip reported an error during transfer TransferError, } diff --git a/hal/src/dmac/transfer.rs b/hal/src/dmac/transfer.rs index 34d09e5a54bc..7d9012327f5e 100644 --- a/hal/src/dmac/transfer.rs +++ b/hal/src/dmac/transfer.rs @@ -329,8 +329,10 @@ where /// /// # Errors /// - /// Returns [`Error::LengthMismatch`] if both - /// buffers have a length > 1 and are not of equal length. + /// * Returns [`Error::LengthMismatch`] if both buffers have a length > 1 + /// and are not of equal length. + /// * Returns [`Error::TooManyBeats`] if the number of beats are greater + /// than `u16::MAX``. #[allow(clippy::new_ret_no_self)] #[inline] pub fn new( @@ -360,6 +362,8 @@ where if src_len > 1 && dst_len > 1 && src_len != dst_len { Err(Error::LengthMismatch) + } else if src_len.max(dst_len) > u16::MAX.into() { + Err(Error::TooManyBeats) } else { Ok(()) } @@ -387,6 +391,9 @@ where /// exacly the same, unless one or both buffers are of length 1. The /// transfer length will be set to the longest of both buffers if they are /// not of equal size. + /// + /// * The source and destination buffers should have a length smaller or + /// equal to `u16::MAX`. #[inline] pub unsafe fn new_unchecked( mut chan: C, From 87882485dc4d82edb1941a7979800bfdf9d85a79 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Fri, 20 Feb 2026 15:54:34 -0500 Subject: [PATCH 023/114] fix(uart): Fix embedded_io::Read::read impl (#983) Fix embedded_io::Read::read implementation for sercom::Uart Signed-off-by: Justin Beaurivage --- hal/src/sercom/uart/impl_ehal.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/hal/src/sercom/uart/impl_ehal.rs b/hal/src/sercom/uart/impl_ehal.rs index 54df1068cf49..cf439f08fd79 100644 --- a/hal/src/sercom/uart/impl_ehal.rs +++ b/hal/src/sercom/uart/impl_ehal.rs @@ -107,12 +107,36 @@ where return Ok(0); } + while !self.read_flags_errors()?.contains(Flags::RXC) { + core::hint::spin_loop(); + } + + let mut bytes_read = 0; + + while self.read_flags_errors()?.contains(Flags::RXC) { + let w = nb::block!(>::read(self))?; + buf[bytes_read] = w; + bytes_read += 1; + } + + Ok(bytes_read) + } + + #[inline] + fn read_exact( + &mut self, + buf: &mut [u8], + ) -> Result<(), embedded_io::ReadExactError> { + if buf.is_empty() { + return Ok(()); + } + for byte in buf.iter_mut() { let w = nb::block!(>::read(self))?; *byte = w; } - Ok(buf.len()) + Ok(()) } } From 7f108ae7b87b6f596cf9929561020e74d2d17e1e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:12:32 -0500 Subject: [PATCH 024/114] chore: release (#979) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- boards/atsame54_xpro/CHANGELOG.md | 6 ++++++ boards/atsame54_xpro/Cargo.toml | 4 ++-- boards/feather_m0/CHANGELOG.md | 6 ++++++ boards/feather_m0/Cargo.toml | 4 ++-- boards/feather_m4/CHANGELOG.md | 6 ++++++ boards/feather_m4/Cargo.toml | 4 ++-- boards/metro_m0/CHANGELOG.md | 6 ++++++ boards/metro_m0/Cargo.toml | 4 ++-- boards/metro_m4/CHANGELOG.md | 6 ++++++ boards/metro_m4/Cargo.toml | 4 ++-- boards/pygamer/CHANGELOG.md | 6 ++++++ boards/pygamer/Cargo.toml | 4 ++-- boards/samd11_bare/CHANGELOG.md | 6 ++++++ boards/samd11_bare/Cargo.toml | 4 ++-- hal/CHANGELOG.md | 12 ++++++++++++ hal/Cargo.toml | 4 ++-- 16 files changed, 70 insertions(+), 16 deletions(-) diff --git a/boards/atsame54_xpro/CHANGELOG.md b/boards/atsame54_xpro/CHANGELOG.md index f40286fae0c2..dc68db6c7702 100644 --- a/boards/atsame54_xpro/CHANGELOG.md +++ b/boards/atsame54_xpro/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.13.2](https://github.com/atsamd-rs/atsamd/compare/atsame54_xpro-0.13.1...atsame54_xpro-0.13.2) - 2026-02-20 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.13.1](https://github.com/atsamd-rs/atsamd/compare/atsame54_xpro-0.13.0...atsame54_xpro-0.13.1) - 2025-12-29 ### Other diff --git a/boards/atsame54_xpro/Cargo.toml b/boards/atsame54_xpro/Cargo.toml index 097db78b7ae6..c311730dfe65 100644 --- a/boards/atsame54_xpro/Cargo.toml +++ b/boards/atsame54_xpro/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" name = "atsame54_xpro" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.13.1" +version = "0.13.2" [dependencies.cortex-m-rt] optional = true @@ -24,7 +24,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.1" +version = "0.23.2" [dependencies.usb-device] optional = true diff --git a/boards/feather_m0/CHANGELOG.md b/boards/feather_m0/CHANGELOG.md index 2526ba4c13f6..3c53c514a042 100644 --- a/boards/feather_m0/CHANGELOG.md +++ b/boards/feather_m0/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.2](https://github.com/atsamd-rs/atsamd/compare/feather_m0-0.20.1...feather_m0-0.20.2) - 2026-02-20 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.20.1](https://github.com/atsamd-rs/atsamd/compare/feather_m0-0.20.0...feather_m0-0.20.1) - 2025-12-29 ### Other diff --git a/boards/feather_m0/Cargo.toml b/boards/feather_m0/Cargo.toml index 92cb4aeca8ee..4bfeb8415826 100644 --- a/boards/feather_m0/Cargo.toml +++ b/boards/feather_m0/Cargo.toml @@ -9,7 +9,7 @@ name = "feather_m0" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" resolver = "2" -version = "0.20.1" +version = "0.20.2" # for cargo flash [package.metadata] @@ -22,7 +22,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.1" +version = "0.23.2" [dependencies.cortex-m] features = ["critical-section-single-core"] diff --git a/boards/feather_m4/CHANGELOG.md b/boards/feather_m4/CHANGELOG.md index d591c6a6e679..1a75dda961a4 100644 --- a/boards/feather_m4/CHANGELOG.md +++ b/boards/feather_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.18.2](https://github.com/atsamd-rs/atsamd/compare/feather_m4-0.18.1...feather_m4-0.18.2) - 2026-02-20 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.18.1](https://github.com/atsamd-rs/atsamd/compare/feather_m4-0.18.0...feather_m4-0.18.1) - 2025-12-29 ### Other diff --git a/boards/feather_m4/Cargo.toml b/boards/feather_m4/Cargo.toml index 970ed16e85dc..e3e973dfaa71 100644 --- a/boards/feather_m4/Cargo.toml +++ b/boards/feather_m4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" name = "feather_m4" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.18.1" +version = "0.18.2" # for cargo flash [package.metadata] @@ -26,7 +26,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.1" +version = "0.23.2" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/metro_m0/CHANGELOG.md b/boards/metro_m0/CHANGELOG.md index 71369101a413..446f7fd4df8e 100644 --- a/boards/metro_m0/CHANGELOG.md +++ b/boards/metro_m0/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.2](https://github.com/atsamd-rs/atsamd/compare/metro_m0-0.20.1...metro_m0-0.20.2) - 2026-02-20 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.20.1](https://github.com/atsamd-rs/atsamd/compare/metro_m0-0.20.0...metro_m0-0.20.1) - 2025-12-29 ### Other diff --git a/boards/metro_m0/Cargo.toml b/boards/metro_m0/Cargo.toml index 55afe6feebf7..c33d1532bd7d 100644 --- a/boards/metro_m0/Cargo.toml +++ b/boards/metro_m0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "metro_m0" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.20.1" +version = "0.20.2" # for cargo flash [package.metadata] @@ -25,7 +25,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.1" +version = "0.23.2" [dependencies.rtic] features = ["thumbv6-backend"] diff --git a/boards/metro_m4/CHANGELOG.md b/boards/metro_m4/CHANGELOG.md index 7df0dd28976b..6138b3ec66c4 100644 --- a/boards/metro_m4/CHANGELOG.md +++ b/boards/metro_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.19.2](https://github.com/atsamd-rs/atsamd/compare/metro_m4-0.19.1...metro_m4-0.19.2) - 2026-02-20 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.19.1](https://github.com/atsamd-rs/atsamd/compare/metro_m4-0.19.0...metro_m4-0.19.1) - 2025-12-29 ### Other diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index 8115fc1f781a..42a28089bc61 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "metro_m4" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.19.1" +version = "0.19.2" # for cargo flash [package.metadata] @@ -21,7 +21,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.1" +version = "0.23.2" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/pygamer/CHANGELOG.md b/boards/pygamer/CHANGELOG.md index e32a1aafce10..8e55bb23c74b 100644 --- a/boards/pygamer/CHANGELOG.md +++ b/boards/pygamer/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.2](https://github.com/atsamd-rs/atsamd/compare/pygamer-0.16.1...pygamer-0.16.2) - 2026-02-20 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.16.1](https://github.com/atsamd-rs/atsamd/compare/pygamer-0.16.0...pygamer-0.16.1) - 2025-12-29 ### Other diff --git a/boards/pygamer/Cargo.toml b/boards/pygamer/Cargo.toml index d8fda2e32c40..57aae9409cde 100644 --- a/boards/pygamer/Cargo.toml +++ b/boards/pygamer/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" name = "pygamer" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.16.1" +version = "0.16.2" [dependencies] cortex-m = {version = "0.7", features = ["critical-section-single-core"]} @@ -27,7 +27,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.1" +version = "0.23.2" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/samd11_bare/CHANGELOG.md b/boards/samd11_bare/CHANGELOG.md index d0b1db8a00cd..e70452136ef0 100644 --- a/boards/samd11_bare/CHANGELOG.md +++ b/boards/samd11_bare/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.2](https://github.com/atsamd-rs/atsamd/compare/samd11_bare-0.16.1...samd11_bare-0.16.2) - 2026-02-20 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.16.1](https://github.com/atsamd-rs/atsamd/compare/samd11_bare-0.16.0...samd11_bare-0.16.1) - 2025-12-29 ### Other diff --git a/boards/samd11_bare/Cargo.toml b/boards/samd11_bare/Cargo.toml index 7cb77e1a32d6..317c845414f8 100644 --- a/boards/samd11_bare/Cargo.toml +++ b/boards/samd11_bare/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" name = "samd11_bare" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.16.1" +version = "0.16.2" # for cargo flash [package.metadata] @@ -24,7 +24,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.1" +version = "0.23.2" [dependencies.rtic] features = ["thumbv6-backend"] diff --git a/hal/CHANGELOG.md b/hal/CHANGELOG.md index 84f3a819cfcf..367cae510bef 100644 --- a/hal/CHANGELOG.md +++ b/hal/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.23.2](https://github.com/atsamd-rs/atsamd/compare/atsamd-hal-0.23.1...atsamd-hal-0.23.2) - 2026-02-20 + +### Added + +- *(usb)* USB allocation rework and simplification ([#963](https://github.com/atsamd-rs/atsamd/pull/963)) + +### Fixed + +- *(uart)* Fix embedded_io::Read::read impl ([#983](https://github.com/atsamd-rs/atsamd/pull/983)) +- *(dmac)* Check+document that the DMAC transfers are smaller than u16::MAX long ([#984](https://github.com/atsamd-rs/atsamd/pull/984)) +- *(pwm)* Fix for off-by-one in get_max_duty() ([#959](https://github.com/atsamd-rs/atsamd/pull/959)) + ## [0.23.1](https://github.com/atsamd-rs/atsamd/compare/atsamd-hal-0.23.0...atsamd-hal-0.23.1) - 2025-12-29 ### Added diff --git a/hal/Cargo.toml b/hal/Cargo.toml index f2c658feed3c..7b4fe2bc21ea 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -20,7 +20,7 @@ name = "atsamd-hal" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" rust-version = "1.85.1" -version = "0.23.1" +version = "0.23.2" [package.metadata.docs.rs] features = ["samd21g", "samd21g-rt", "usb", "dma", "async", "rtic"] @@ -220,4 +220,4 @@ usb-buffer-8k = ["usb"] # 8192 byte buffer shared between all USB endpoints # The `device` feature tells the HAL that a device has been selected from the # feature list. It exists mostly to provide better error messages. -device = [] \ No newline at end of file +device = [] From 8c7a04f50f1c407a05e689c25eeb4d6cf188cc29 Mon Sep 17 00:00:00 2001 From: Nico Lube <32245510+nicolube@users.noreply.github.com> Date: Wed, 25 Feb 2026 19:10:25 +0100 Subject: [PATCH 025/114] fix(adc): ADC clearing flags when reading value & make it somewhat consistent (#989) --- hal/src/peripherals/adc/mod.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/hal/src/peripherals/adc/mod.rs b/hal/src/peripherals/adc/mod.rs index c34b560ad113..a5c6eb0cb729 100644 --- a/hal/src/peripherals/adc/mod.rs +++ b/hal/src/peripherals/adc/mod.rs @@ -358,6 +358,7 @@ impl Adc { while !self.read_flags().contains(Flags::RESRDY) { core::hint::spin_loop(); } + self.clear_all_flags(); self.discard = false; } } @@ -381,15 +382,7 @@ impl Adc { self.mux(ch); self.enable_freerunning(); self.start_conversion(); - if self.discard { - // Discard first result - while !self.read_flags().contains(Flags::RESRDY) { - core::hint::spin_loop(); - } - self.clear_all_flags(); - self.discard = false; - } - + self.check_read_discard(); for result in dst.iter_mut() { while !self.read_flags().contains(Flags::RESRDY) { core::hint::spin_loop(); @@ -468,7 +461,7 @@ where self.inner.start_conversion(); let _ = self.wait_flags(Flags::RESRDY).await; self.inner.discard = false; - let _ = self.inner.conversion_result(); + self.inner.clear_all_flags(); } self.inner.start_conversion(); // Here we explicitly ignore the result, because we know that From a04f33a798848c7ca55f9693b591f9b570aa4c6c Mon Sep 17 00:00:00 2001 From: QuartzShard Date: Mon, 2 Mar 2026 20:38:41 +0000 Subject: [PATCH 026/114] chore(clippy): New lint doesn't like nesting if in match (#993) --- hal/src/peripherals/eic/d11/pin.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/hal/src/peripherals/eic/d11/pin.rs b/hal/src/peripherals/eic/d11/pin.rs index e1b3ec8e3ae4..8de32744bbb2 100644 --- a/hal/src/peripherals/eic/d11/pin.rs +++ b/hal/src/peripherals/eic/d11/pin.rs @@ -4,7 +4,7 @@ use crate::ehal::digital::{ErrorType, InputPin}; use crate::ehal_02::digital::v2::InputPin as InputPin_02; use crate::eic::*; use crate::gpio::{ - self, pin::*, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt, + self, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt, pin::*, }; use core::convert::Infallible; @@ -213,16 +213,9 @@ mod async_impls { self.disable_interrupt(); match sense { - Sense::High => { - if self.is_high().unwrap() { - return; - } - } - Sense::Low => { - if self.is_low().unwrap() { - return; - } - } + Sense::High if self.is_high().unwrap() => return, + + Sense::Low if self.is_low().unwrap() => return, _ => (), } From 74fb81074fee52a10d29eba1314d9c85163d04a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 17:41:50 -0500 Subject: [PATCH 027/114] chore(deps): bump actions/upload-artifact from 6 to 7 (#994) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-bsp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-bsp.yml b/.github/workflows/build-bsp.yml index 2976344bbd14..af2f960bd311 100644 --- a/.github/workflows/build-bsp.yml +++ b/.github/workflows/build-bsp.yml @@ -60,7 +60,7 @@ jobs: $(${clippy_invocation}) - name: Done - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: # name needs to be unique in the workspace name: "${{ matrix.bsp.name }}-${{ matrix.toolchain }}" From ef547e6520da3f72322bdfe385dd53f4b6d92333 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 17:42:20 -0500 Subject: [PATCH 028/114] chore(deps): bump actions/download-artifact from 7 to 8 (#995) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-bsp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-bsp.yml b/.github/workflows/build-bsp.yml index af2f960bd311..5c1732eb2bf5 100644 --- a/.github/workflows/build-bsp.yml +++ b/.github/workflows/build-bsp.yml @@ -71,7 +71,7 @@ jobs: needs: [setup, build] steps: - name: Download artifacts - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: path: successful-jobs - name: Do checks From ad76394d51ef36d6cfcbdbcee547c17e91bd6dcc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 19:21:56 -0500 Subject: [PATCH 029/114] chore: release (#996) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- boards/atsame54_xpro/CHANGELOG.md | 6 ++++++ boards/atsame54_xpro/Cargo.toml | 4 ++-- boards/feather_m0/CHANGELOG.md | 6 ++++++ boards/feather_m0/Cargo.toml | 4 ++-- boards/feather_m4/CHANGELOG.md | 6 ++++++ boards/feather_m4/Cargo.toml | 4 ++-- boards/metro_m0/CHANGELOG.md | 6 ++++++ boards/metro_m0/Cargo.toml | 4 ++-- boards/metro_m4/CHANGELOG.md | 6 ++++++ boards/metro_m4/Cargo.toml | 4 ++-- boards/pygamer/CHANGELOG.md | 6 ++++++ boards/pygamer/Cargo.toml | 4 ++-- boards/samd11_bare/CHANGELOG.md | 6 ++++++ boards/samd11_bare/Cargo.toml | 4 ++-- hal/CHANGELOG.md | 10 ++++++++++ hal/Cargo.toml | 2 +- 16 files changed, 67 insertions(+), 15 deletions(-) diff --git a/boards/atsame54_xpro/CHANGELOG.md b/boards/atsame54_xpro/CHANGELOG.md index dc68db6c7702..4bee8d6fc5c1 100644 --- a/boards/atsame54_xpro/CHANGELOG.md +++ b/boards/atsame54_xpro/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.13.3](https://github.com/atsamd-rs/atsamd/compare/atsame54_xpro-0.13.2...atsame54_xpro-0.13.3) - 2026-03-02 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.13.2](https://github.com/atsamd-rs/atsamd/compare/atsame54_xpro-0.13.1...atsame54_xpro-0.13.2) - 2026-02-20 ### Other diff --git a/boards/atsame54_xpro/Cargo.toml b/boards/atsame54_xpro/Cargo.toml index c311730dfe65..175936b23b97 100644 --- a/boards/atsame54_xpro/Cargo.toml +++ b/boards/atsame54_xpro/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" name = "atsame54_xpro" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.13.2" +version = "0.13.3" [dependencies.cortex-m-rt] optional = true @@ -24,7 +24,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.2" +version = "0.23.3" [dependencies.usb-device] optional = true diff --git a/boards/feather_m0/CHANGELOG.md b/boards/feather_m0/CHANGELOG.md index 3c53c514a042..62b20d557e78 100644 --- a/boards/feather_m0/CHANGELOG.md +++ b/boards/feather_m0/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.3](https://github.com/atsamd-rs/atsamd/compare/feather_m0-0.20.2...feather_m0-0.20.3) - 2026-03-02 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.20.2](https://github.com/atsamd-rs/atsamd/compare/feather_m0-0.20.1...feather_m0-0.20.2) - 2026-02-20 ### Other diff --git a/boards/feather_m0/Cargo.toml b/boards/feather_m0/Cargo.toml index 4bfeb8415826..cda71df03fcb 100644 --- a/boards/feather_m0/Cargo.toml +++ b/boards/feather_m0/Cargo.toml @@ -9,7 +9,7 @@ name = "feather_m0" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" resolver = "2" -version = "0.20.2" +version = "0.20.3" # for cargo flash [package.metadata] @@ -22,7 +22,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.2" +version = "0.23.3" [dependencies.cortex-m] features = ["critical-section-single-core"] diff --git a/boards/feather_m4/CHANGELOG.md b/boards/feather_m4/CHANGELOG.md index 1a75dda961a4..94c78dbfd744 100644 --- a/boards/feather_m4/CHANGELOG.md +++ b/boards/feather_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.18.3](https://github.com/atsamd-rs/atsamd/compare/feather_m4-0.18.2...feather_m4-0.18.3) - 2026-03-02 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.18.2](https://github.com/atsamd-rs/atsamd/compare/feather_m4-0.18.1...feather_m4-0.18.2) - 2026-02-20 ### Other diff --git a/boards/feather_m4/Cargo.toml b/boards/feather_m4/Cargo.toml index e3e973dfaa71..8c7da29207f7 100644 --- a/boards/feather_m4/Cargo.toml +++ b/boards/feather_m4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" name = "feather_m4" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.18.2" +version = "0.18.3" # for cargo flash [package.metadata] @@ -26,7 +26,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.2" +version = "0.23.3" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/metro_m0/CHANGELOG.md b/boards/metro_m0/CHANGELOG.md index 446f7fd4df8e..293982cb4868 100644 --- a/boards/metro_m0/CHANGELOG.md +++ b/boards/metro_m0/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.3](https://github.com/atsamd-rs/atsamd/compare/metro_m0-0.20.2...metro_m0-0.20.3) - 2026-03-02 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.20.2](https://github.com/atsamd-rs/atsamd/compare/metro_m0-0.20.1...metro_m0-0.20.2) - 2026-02-20 ### Other diff --git a/boards/metro_m0/Cargo.toml b/boards/metro_m0/Cargo.toml index c33d1532bd7d..103de8532a77 100644 --- a/boards/metro_m0/Cargo.toml +++ b/boards/metro_m0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "metro_m0" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.20.2" +version = "0.20.3" # for cargo flash [package.metadata] @@ -25,7 +25,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.2" +version = "0.23.3" [dependencies.rtic] features = ["thumbv6-backend"] diff --git a/boards/metro_m4/CHANGELOG.md b/boards/metro_m4/CHANGELOG.md index 6138b3ec66c4..bf4a9de429b6 100644 --- a/boards/metro_m4/CHANGELOG.md +++ b/boards/metro_m4/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.19.3](https://github.com/atsamd-rs/atsamd/compare/metro_m4-0.19.2...metro_m4-0.19.3) - 2026-03-02 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.19.2](https://github.com/atsamd-rs/atsamd/compare/metro_m4-0.19.1...metro_m4-0.19.2) - 2026-02-20 ### Other diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index 42a28089bc61..29f730f241e1 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "metro_m4" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.19.2" +version = "0.19.3" # for cargo flash [package.metadata] @@ -21,7 +21,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.2" +version = "0.23.3" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/pygamer/CHANGELOG.md b/boards/pygamer/CHANGELOG.md index 8e55bb23c74b..89e8203e0e30 100644 --- a/boards/pygamer/CHANGELOG.md +++ b/boards/pygamer/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.3](https://github.com/atsamd-rs/atsamd/compare/pygamer-0.16.2...pygamer-0.16.3) - 2026-03-02 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.16.2](https://github.com/atsamd-rs/atsamd/compare/pygamer-0.16.1...pygamer-0.16.2) - 2026-02-20 ### Other diff --git a/boards/pygamer/Cargo.toml b/boards/pygamer/Cargo.toml index 57aae9409cde..8393af5de64d 100644 --- a/boards/pygamer/Cargo.toml +++ b/boards/pygamer/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" name = "pygamer" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.16.2" +version = "0.16.3" [dependencies] cortex-m = {version = "0.7", features = ["critical-section-single-core"]} @@ -27,7 +27,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.2" +version = "0.23.3" features = ["undoc-features"] [dependencies.usb-device] diff --git a/boards/samd11_bare/CHANGELOG.md b/boards/samd11_bare/CHANGELOG.md index e70452136ef0..66c8f829c1f4 100644 --- a/boards/samd11_bare/CHANGELOG.md +++ b/boards/samd11_bare/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.3](https://github.com/atsamd-rs/atsamd/compare/samd11_bare-0.16.2...samd11_bare-0.16.3) - 2026-03-02 + +### Other + +- updated the following local packages: atsamd-hal + ## [0.16.2](https://github.com/atsamd-rs/atsamd/compare/samd11_bare-0.16.1...samd11_bare-0.16.2) - 2026-02-20 ### Other diff --git a/boards/samd11_bare/Cargo.toml b/boards/samd11_bare/Cargo.toml index 317c845414f8..c7653549ca54 100644 --- a/boards/samd11_bare/Cargo.toml +++ b/boards/samd11_bare/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" name = "samd11_bare" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" -version = "0.16.2" +version = "0.16.3" # for cargo flash [package.metadata] @@ -24,7 +24,7 @@ version = "0.7" [dependencies.atsamd-hal] default-features = false path = "../../hal" -version = "0.23.2" +version = "0.23.3" [dependencies.rtic] features = ["thumbv6-backend"] diff --git a/hal/CHANGELOG.md b/hal/CHANGELOG.md index 367cae510bef..1ab6ecd97223 100644 --- a/hal/CHANGELOG.md +++ b/hal/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.23.3](https://github.com/atsamd-rs/atsamd/compare/atsamd-hal-0.23.2...atsamd-hal-0.23.3) - 2026-03-02 + +### Fixed + +- *(adc)* ADC clearing flags when reading value & make it somewhat consistent ([#989](https://github.com/atsamd-rs/atsamd/pull/989)) + +### Other + +- *(clippy)* New lint doesn't like nesting if in match ([#993](https://github.com/atsamd-rs/atsamd/pull/993)) + ## [0.23.2](https://github.com/atsamd-rs/atsamd/compare/atsamd-hal-0.23.1...atsamd-hal-0.23.2) - 2026-02-20 ### Added diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 7b4fe2bc21ea..8f5b29172c87 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -20,7 +20,7 @@ name = "atsamd-hal" readme = "README.md" repository = "https://github.com/atsamd-rs/atsamd" rust-version = "1.85.1" -version = "0.23.2" +version = "0.23.3" [package.metadata.docs.rs] features = ["samd21g", "samd21g-rt", "usb", "dma", "async", "rtic"] From c23e4681febff0b865e6437a95dd0a35c514ef37 Mon Sep 17 00:00:00 2001 From: QuartzShard Date: Mon, 23 Mar 2026 06:17:10 +0000 Subject: [PATCH 030/114] fix(rtc): disable compare interrupt instead of stopping the RTC counter (#992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit disable_timer()/enable_timer() were calling RtcMode::disable()/enable(), which clears/sets CTRLA.ENABLE — stopping and restarting the entire RTC peripheral. The rtic-time TimerQueue calls disable_timer() whenever the queue is empty, so any period with no pending delays freezes the hardware counter and permanently loses wall-clock time. This violates the TimerQueueBackend trait contract, which states that enabling/disabling must propagate to now() so instants remain valid. Fix: toggle the compare match interrupt (INTENCLR/INTENSET) instead of the peripheral enable bit. The RTC counter keeps running, preserving monotonicity. Only the Compare0 interrupt used for RTIC task wakeups is affected — half-period and overflow interrupts remain enabled. --- hal/src/rtc/rtic/backends.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hal/src/rtc/rtic/backends.rs b/hal/src/rtc/rtic/backends.rs index 29bab219defc..20223b73a2d6 100644 --- a/hal/src/rtc/rtic/backends.rs +++ b/hal/src/rtc/rtic/backends.rs @@ -132,11 +132,11 @@ macro_rules! __internal_basic_backend { } fn enable_timer() { - <$mode>::enable(unsafe { &pac::Rtc::steal() }); + <$mode>::enable_interrupt::<$rtic_int>(unsafe { &pac::Rtc::steal() }); } fn disable_timer() { - <$mode>::disable(unsafe { &pac::Rtc::steal() }); + <$mode>::disable_interrupt::<$rtic_int>(unsafe { &pac::Rtc::steal() }); } fn on_interrupt() { @@ -243,12 +243,12 @@ macro_rules! __internal_half_period_counting_backend { fn enable_timer() { let rtc = unsafe { pac::Rtc::steal() }; - <$mode>::enable(&rtc); + <$mode>::enable_interrupt::<$rtic_int>(&rtc); } fn disable_timer() { let rtc = unsafe { pac::Rtc::steal() }; - <$mode>::disable(&rtc); + <$mode>::disable_interrupt::<$rtic_int>(&rtc); } fn on_interrupt() { From f0ed5b4fa19102788556098f0081fbdf37febfbb Mon Sep 17 00:00:00 2001 From: "Ashcon Mohseninia (RAND_ASH)" Date: Mon, 23 Mar 2026 21:57:24 +0100 Subject: [PATCH 031/114] Make ADC `check_read_discard` private again (#1003) --- hal/src/peripherals/adc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/peripherals/adc/mod.rs b/hal/src/peripherals/adc/mod.rs index a5c6eb0cb729..1b22a158a9bb 100644 --- a/hal/src/peripherals/adc/mod.rs +++ b/hal/src/peripherals/adc/mod.rs @@ -352,7 +352,7 @@ impl Adc { // If the ADC has to discard the next value, then we try to read it // and then discard it #[inline] - pub fn check_read_discard(&mut self) { + fn check_read_discard(&mut self) { if self.discard { self.start_conversion(); while !self.read_flags().contains(Flags::RESRDY) { From eccc9c1f76ba5a33ac487701a4fb9b3f16a8ec21 Mon Sep 17 00:00:00 2001 From: Ginger Date: Mon, 23 Mar 2026 17:27:05 -0400 Subject: [PATCH 032/114] deps(qt_py_m0): Update QT PY M0 to latest HAL version (#970) --- boards/qt_py_m0/Cargo.toml | 22 ++++--- boards/qt_py_m0/examples/neopixel.rs | 36 ++++++----- boards/qt_py_m0/examples/usb_echo.rs | 89 +++++++++------------------- boards/qt_py_m0/src/lib.rs | 59 +++++++++++------- 4 files changed, 97 insertions(+), 109 deletions(-) diff --git a/boards/qt_py_m0/Cargo.toml b/boards/qt_py_m0/Cargo.toml index 2cb79b0d86b3..bb94e0bb070d 100644 --- a/boards/qt_py_m0/Cargo.toml +++ b/boards/qt_py_m0/Cargo.toml @@ -8,27 +8,33 @@ categories = ["embedded", "hardware-support", "no-std"] license = "MIT OR Apache-2.0" repository = "https://github.com/atsamd-rs/atsamd" readme = "README.md" -edition = "2018" +edition = "2024" -[dependencies] -cortex-m-rt = { version = "0.7", optional = true } -usb-device = { version = "0.2", optional = true } +[dependencies.cortex-m] +features = ["critical-section-single-core"] +version = "0.7" + +[dependencies.cortex-m-rt] +version = "0.7" +optional = true + +[dependencies.usb-device] +version = "0.3.2" +optional = true [dependencies.atsamd-hal] -version = "0.14" +version = "0.23" default-features = false [dev-dependencies] -usbd-serial = "0.1" +usbd-serial = "0.2" panic-halt = "0.2" smart-leds = "0.3" ws2812-timer-delay = { version = "0.3", features = ["slow"] } -cortex-m = "0.7" [features] default = ["rt", "atsamd-hal/samd21e"] rt = ["cortex-m-rt", "atsamd-hal/samd21e-rt"] -unproven = ["atsamd-hal/unproven"] use_semihosting = [] usb = ["atsamd-hal/usb", "usb-device"] diff --git a/boards/qt_py_m0/examples/neopixel.rs b/boards/qt_py_m0/examples/neopixel.rs index 15062e9d59e7..af8b641ae6c9 100644 --- a/boards/qt_py_m0/examples/neopixel.rs +++ b/boards/qt_py_m0/examples/neopixel.rs @@ -4,43 +4,47 @@ //! Neopixel example for the Adafruit QT Py board. Demonstrates powering up the //! neopixel using the attached GPIO line. //! -//! *NOTE*: This example currently only works in release mode. +//! *NOTE*: This example needs to be compiled with --release for the timing to +//! be correct. -use hal::ehal::digital::v1_compat::OldOutputPin; +use atsamd_hal::prelude::InterruptDrivenTimer; use panic_halt as _; -use smart_leds::hsv::hsv2rgb; -use smart_leds::hsv::Hsv; -use smart_leds::SmartLedsWrite; -use ws2812_timer_delay::Ws2812; -use bsp::entry; use bsp::hal; +use qt_py_m0 as bsp; + use bsp::Pins; +use bsp::entry; use hal::clock::GenericClockController; use hal::delay::Delay; use hal::pac::CorePeripherals; use hal::pac::Peripherals; use hal::prelude::*; use hal::timer::TimerCounter; -use qt_py_m0 as bsp; + +use smart_leds::SmartLedsWrite; +use smart_leds::hsv::Hsv; +use smart_leds::hsv::hsv2rgb; +use ws2812_timer_delay::Ws2812; #[entry] fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_8mhz( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = Pins::new(peripherals.PORT).split(); + let pins = Pins::new(peripherals.port).split(); let gclk0 = clocks.gclk0(); let timer_clock = clocks.tcc2_tc3(&gclk0).unwrap(); - let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.TC3, &mut peripherals.PM); - timer.start(3.mhz()); + let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.tc3, &mut peripherals.pm); + InterruptDrivenTimer::start(&mut timer, 300.nanos()); + InterruptDrivenTimer::enable_interrupt(&mut timer); // The neopixel sources power from a GPIO pin. It must be driven high to power // up the neopixel before it can be used. @@ -50,7 +54,7 @@ fn main() -> ! { .set_high() .unwrap(); - let neopixel_data: OldOutputPin<_> = pins.neopixel.data.into_push_pull_output().into(); + let neopixel_data: bsp::NeopixelData = pins.neopixel.data.into(); let mut neopixel = Ws2812::new(timer, neopixel_data); let mut delay = Delay::new(core.SYST, &mut clocks); diff --git a/boards/qt_py_m0/examples/usb_echo.rs b/boards/qt_py_m0/examples/usb_echo.rs index 8005d32ac31b..95e8161dd02c 100644 --- a/boards/qt_py_m0/examples/usb_echo.rs +++ b/boards/qt_py_m0/examples/usb_echo.rs @@ -6,9 +6,6 @@ use panic_halt as _; -use cortex_m::asm::wfi; -use cortex_m::peripheral::NVIC; -use usb_device::bus::UsbBusAllocator; use usb_device::prelude::*; use usbd_serial::SerialPort; use usbd_serial::USB_CLASS_CDC; @@ -19,73 +16,41 @@ use qt_py_m0 as bsp; use bsp::entry; use hal::clock::GenericClockController; -use hal::usb::UsbBus; -use pac::interrupt; -use pac::CorePeripherals; use pac::Peripherals; #[entry] fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); - let mut core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, ); - let pins = bsp::Pins::new(peripherals.PORT).split(); - - let bus_allocator = unsafe { - USB_ALLOCATOR = Some( - pins.usb - .init(peripherals.USB, &mut clocks, &mut peripherals.PM), - ); - USB_ALLOCATOR.as_ref().unwrap() - }; - - unsafe { - USB_SERIAL = Some(SerialPort::new(&bus_allocator)); - USB_BUS = Some( - UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") - .device_class(USB_CLASS_CDC) - .build(), - ); - } - - unsafe { - core.NVIC.set_priority(interrupt::USB, 1); - NVIC::unmask(interrupt::USB); - } + let pins = bsp::Pins::new(peripherals.port).split(); + + let usb_bus = pins + .usb + .init(peripherals.usb, &mut clocks, &mut peripherals.pm); + + let mut serial = SerialPort::new(&usb_bus); + let mut usb_device = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x239a, 0x00cb)) + .strings(&[StringDescriptors::new(LangID::EN) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST")]) + .expect("Failed to set strings") + .device_class(USB_CLASS_CDC) + .build(); loop { - wfi(); + if !usb_device.poll(&mut [&mut serial]) { + continue; + } + + let mut buf = [0u8; 64]; + if let Ok(count) = serial.read(&mut buf) { + let _ = serial.write(&buf[..count]); + } } } - -static mut USB_ALLOCATOR: Option> = None; -static mut USB_BUS: Option> = None; -static mut USB_SERIAL: Option> = None; - -fn poll_usb() { - unsafe { - USB_BUS.as_mut().map(|usb_dev| { - USB_SERIAL.as_mut().map(|serial| { - usb_dev.poll(&mut [serial]); - let mut buf = [0u8; 64]; - - if let Ok(count) = serial.read(&mut buf) { - serial.write(&buf[..count]).ok(); - }; - }); - }); - }; -} - -#[interrupt] -fn USB() { - poll_usb(); -} diff --git a/boards/qt_py_m0/src/lib.rs b/boards/qt_py_m0/src/lib.rs index 4705af349fc3..182bf7959644 100644 --- a/boards/qt_py_m0/src/lib.rs +++ b/boards/qt_py_m0/src/lib.rs @@ -24,10 +24,10 @@ pub use hal::pac; use hal::bsp_pins; use hal::clock::GenericClockController; -use hal::sercom::v2::spi; -use hal::sercom::v2::uart::{self, BaudMode, Oversampling}; -use hal::sercom::v2::{Sercom0, Sercom2}; -use hal::sercom::I2CMaster1; +use hal::sercom::i2c; +use hal::sercom::spi; +use hal::sercom::uart::{self, BaudMode, Oversampling}; +use hal::sercom::{Sercom0, Sercom2}; use hal::time::Hertz; #[cfg(feature = "rt")] @@ -38,6 +38,12 @@ use hal::usb::UsbBus; #[cfg(feature = "usb")] use usb_device::bus::UsbBusAllocator; +hal::bsp_peripherals! { + Sercom0 { UartSercom } + Sercom1 { I2cSercom } + Sercom2 { SpiSercom } +} + bsp_pins! { // General purpose pins. PA02 { @@ -273,8 +279,8 @@ impl Uart { self, clocks: &mut GenericClockController, freq: impl Into, - sercom0: pac::SERCOM0, - pm: &mut pac::PM, + sercom0: pac::Sercom0, + pm: &mut pac::Pm, ) -> UartConfig { let gclk0 = clocks.gclk0(); let clock = &clocks.sercom0_core(&gclk0).unwrap(); @@ -308,9 +314,9 @@ impl Spi { pub fn init( self, clocks: &mut GenericClockController, - baud: impl Into, - sercom2: pac::SERCOM2, - pm: &mut pac::PM, + baud: Hertz, + sercom2: pac::Sercom2, + pm: &mut pac::Pm, ) -> SpiConfig { let gclk0 = clocks.gclk0(); let clock = clocks.sercom2_core(&gclk0).unwrap(); @@ -333,25 +339,32 @@ pub struct I2c { pub scl: I2cSclReset, } +/// I2C pads for the labelled I2C peripheral +/// +/// You can use these pads with other, user-defined [`i2c::Config`]urations. +pub type I2cPads = i2c::Pads; + +/// I2C master for the labelled I2C peripheral +/// +/// This type implements [`Read`](ehal::blocking::i2c::Read), +/// [`Write`](ehal::blocking::i2c::Write) and +/// [`WriteRead`](ehal::blocking::i2c::WriteRead). +pub type I2cConfig = i2c::I2c>; + impl I2c { /// Convenience function for creating an I2C host on the I2C pins. pub fn init( self, clocks: &mut GenericClockController, - freq: impl Into, - sercom1: pac::SERCOM1, - pm: &mut pac::PM, - ) -> I2CMaster1 { + baud: Hertz, + sercom: I2cSercom, + pm: &mut pac::Pm, + ) -> I2cConfig { let gclk0 = clocks.gclk0(); let clock = &clocks.sercom1_core(&gclk0).unwrap(); - I2CMaster1::new( - clock, - freq.into(), - sercom1, - pm, - self.sda.into(), - self.scl.into(), - ) + let freq = clock.freq(); + let pads = i2c::Pads::new(self.sda, self.scl); + i2c::Config::new(pm, sercom, pads, freq).baud(baud).enable() } } @@ -377,9 +390,9 @@ impl Usb { #[cfg(feature = "usb")] pub fn init( self, - usb: pac::USB, + usb: pac::Usb, clocks: &mut GenericClockController, - pm: &mut pac::PM, + pm: &mut pac::Pm, ) -> UsbBusAllocator { let gclk0 = clocks.gclk0(); let usb_clock = &clocks.usb(&gclk0).unwrap(); From 9320d0544b0c06baf8fcfb74d6065308893f386d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20W=C4=99grzyn?= Date: Tue, 24 Mar 2026 04:26:56 +0100 Subject: [PATCH 033/114] deps(itsybitsy_m4): Switch itsybitsy_m4 BSP to latest HAL release. (#954) --- boards/itsybitsy_m4/Cargo.toml | 2 +- boards/itsybitsy_m4/examples/sercom_interrupt.rs | 4 ++-- boards/itsybitsy_m4/src/lib.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/boards/itsybitsy_m4/Cargo.toml b/boards/itsybitsy_m4/Cargo.toml index 40d1dfe58311..2e1b51c9042c 100644 --- a/boards/itsybitsy_m4/Cargo.toml +++ b/boards/itsybitsy_m4/Cargo.toml @@ -24,7 +24,7 @@ version = "0.7" optional = true [dependencies.atsamd-hal] -version = "0.21" +version = "0.22.2" default-features = false [dependencies.usb-device] diff --git a/boards/itsybitsy_m4/examples/sercom_interrupt.rs b/boards/itsybitsy_m4/examples/sercom_interrupt.rs index af81a3811f7d..47d21d7efcd0 100644 --- a/boards/itsybitsy_m4/examples/sercom_interrupt.rs +++ b/boards/itsybitsy_m4/examples/sercom_interrupt.rs @@ -42,12 +42,12 @@ use bsp::hal::{ prelude::*, sercom::{ uart::{self, BaudMode, Flags, Oversampling}, - IoSet3, Sercom0, + Sercom0, }, time::Hertz, }; -type UartPads0 = uart::Pads; +type UartPads0 = uart::Pads; type Uart0 = uart::Uart, uart::Duplex>; /// Utility function for setting up SERCOM0 pins as an additional diff --git a/boards/itsybitsy_m4/src/lib.rs b/boards/itsybitsy_m4/src/lib.rs index 568d36e55ffc..ee3ff5aecc12 100644 --- a/boards/itsybitsy_m4/src/lib.rs +++ b/boards/itsybitsy_m4/src/lib.rs @@ -288,7 +288,7 @@ pub fn qspi_master( /// I2C pads for the labelled I2C peripheral /// /// You can use these pads with other, user-defined [`i2c::Config`]urations. -pub type I2cPads = i2c::Pads; +pub type I2cPads = i2c::Pads; /// I2C master for the labelled I2C peripheral /// @@ -318,7 +318,7 @@ pub fn i2c_master( } /// UART Pads for the labelled UART peripheral -pub type UartPads = uart::Pads; +pub type UartPads = uart::Pads; /// UART device for the labelled RX & TX pins pub type Uart = uart::Uart, uart::Duplex>; @@ -375,7 +375,7 @@ pub fn dotstar_bitbang( /// SPI pads for the labelled SPI peripheral /// /// You can use these pads with other, user-defined [`spi::Config`]urations. -pub type SpiPads = spi::Pads; +pub type SpiPads = spi::Pads; /// SPI master for the labelled SPI peripheral /// From 94308e9fea2487f88a1c85ea480f4971413c4678 Mon Sep 17 00:00:00 2001 From: "Ashcon Mohseninia (RAND_ASH)" Date: Tue, 12 May 2026 20:25:31 +0100 Subject: [PATCH 034/114] Update DMAC documentation (#1005) --- hal/src/dmac/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hal/src/dmac/mod.rs b/hal/src/dmac/mod.rs index c6cbc8207943..f64c35bfe80f 100644 --- a/hal/src/dmac/mod.rs +++ b/hal/src/dmac/mod.rs @@ -120,20 +120,20 @@ //! # Example //! ``` //! let mut peripherals = Peripherals::take().unwrap(); -//! let mut dmac = DmaController::init(peripherals.DMAC, &mut peripherals.PM); +//! let mut dmac = DmaController::init(peripherals.dmac, &mut peripherals.pm); //! // Get individual handles to DMA channels //! let channels = dmac.split(); //! //! // Initialize DMA Channel 0 -//! let chan0 = channels.0.init(PriorityLevel::LVL0, false, &mut dmac); +//! let chan0 = channels.0.init(PriorityLevel::Lvl0); //! //! // Setup a DMA transfer (memory-to-memory -> incrementing source, incrementing destination) //! // NOTE: buf_src and buf_dest should be either: //! // &'static mut T, &'static mut [T], or &'static mut [T; N] where T: BeatSize //! let xfer = Transfer::new(chan0, buf_src, buf_dest, false).begin( //! &mut dmac, -//! TriggerSource::DISABLE, -//! TriggerAction::BLOCK, +//! TriggerSource::Disable, +//! TriggerAction::Block, //! ); //! //! // Wait for transfer to complete and grab resulting buffers @@ -141,7 +141,7 @@ //! //! // (Optional) free the [`DmaController`] struct and return the underlying PAC struct //! channels.0 = chan0.into(); -//! let dmac = dmac.free(channels, &mut peripherals.PM); +//! let dmac = dmac.free(channels, &mut peripherals.pm); //! ``` //! //! # [`Transfer`] recycling From a3ba6be7e8b1c9eda4f69f1bc92a36d571a52eb3 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Tue, 12 May 2026 15:48:25 -0400 Subject: [PATCH 035/114] Fix nightly clippy lint (#1006) --- hal/src/peripherals/usb/d11/devicedesc.rs | 2 +- hal/src/peripherals/usb/d5x/devicedesc.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/peripherals/usb/d11/devicedesc.rs b/hal/src/peripherals/usb/d11/devicedesc.rs index fa6e579d6d0f..c2519a64ed2e 100644 --- a/hal/src/peripherals/usb/d11/devicedesc.rs +++ b/hal/src/peripherals/usb/d11/devicedesc.rs @@ -205,7 +205,7 @@ pub struct Descriptors { impl Debug for Descriptors { fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult { for ep in 0..8 { - write!(fmt, "\nep{}: {:?}", ep, &self.desc[ep])?; + write!(fmt, "\nep{}: {:?}", ep, self.desc[ep])?; } Ok(()) } diff --git a/hal/src/peripherals/usb/d5x/devicedesc.rs b/hal/src/peripherals/usb/d5x/devicedesc.rs index f4752cb195b0..e9427268a783 100644 --- a/hal/src/peripherals/usb/d5x/devicedesc.rs +++ b/hal/src/peripherals/usb/d5x/devicedesc.rs @@ -206,7 +206,7 @@ pub struct Descriptors { impl Debug for Descriptors { fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult { for ep in 0..8 { - write!(fmt, "\nep{}: {:?}", ep, &self.desc[ep])?; + write!(fmt, "\nep{}: {:?}", ep, self.desc[ep])?; } Ok(()) } From 610a5e17344a1963e1889699b0b7ea8ab4189a83 Mon Sep 17 00:00:00 2001 From: "Ashcon Mohseninia (RAND_ASH)" Date: Sun, 31 May 2026 19:09:12 +0100 Subject: [PATCH 036/114] feat(usb): Enable Multi-Packet Rx and Tx (#1009) * Add 16KB buffer for USB option (1024 bytes per EP) --- hal/Cargo.toml | 9 +- hal/src/peripherals/usb/d11/buffer.rs | 8 +- hal/src/peripherals/usb/d11/bus.rs | 115 ++++++++++++++++--------- hal/src/peripherals/usb/d5x/buffer.rs | 7 +- hal/src/peripherals/usb/d5x/bus.rs | 117 +++++++++++++++++--------- 5 files changed, 172 insertions(+), 84 deletions(-) diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 8f5b29172c87..07e236b7ca1d 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -205,10 +205,11 @@ usb = ["usb-device"] # Default with 2048 byte buffer # These denote the size of the global buffer for all USB endpoints. # The buffer is split between all device endpoints equally -usb-buffer-1k = ["usb"] # 1024 byte buffer shared between all USB endpoints -usb-buffer-2k = ["usb"] # 2048 byte buffer shared between all USB endpoints (Default) -usb-buffer-4k = ["usb"] # 4096 byte buffer shared between all USB endpoints -usb-buffer-8k = ["usb"] # 8192 byte buffer shared between all USB endpoints +usb-buffer-1k = ["usb"] # 1024 byte buffer shared between all USB endpoints (64 bytes per endpoint) +usb-buffer-2k = ["usb"] # 2048 byte buffer shared between all USB endpoints (128 bytes per endpoint) (Default) +usb-buffer-4k = ["usb"] # 4096 byte buffer shared between all USB endpoints (256 bytes per endpoint) +usb-buffer-8k = ["usb"] # 8192 byte buffer shared between all USB endpoints (512 bytes per endpoint) +usb-buffer-16k = ["usb"] # 16384 byte buffer shared between all USB endpoints (1024 bytes per endpoint) #=============================================================================== # Implementation-details diff --git a/hal/src/peripherals/usb/d11/buffer.rs b/hal/src/peripherals/usb/d11/buffer.rs index ddc21b5b4372..35c1ae0951c5 100644 --- a/hal/src/peripherals/usb/d11/buffer.rs +++ b/hal/src/peripherals/usb/d11/buffer.rs @@ -16,10 +16,15 @@ pub const BUFFER_SIZE: usize = { { 8192 } + #[cfg(feature = "usb-buffer-16k")] + { + 16384 + } #[cfg(not(any( feature = "usb-buffer-1k", feature = "usb-buffer-4k", - feature = "usb-buffer-8k" + feature = "usb-buffer-8k", + feature = "usb-buffer-16k" )))] { 2048 // Default @@ -75,7 +80,6 @@ impl Default for BufferAllocator { } impl BufferAllocator { - /// Allocates a fixed buffer of [`ALLOC_SIZE_MAX_PER_EP`] pub fn allocate_buffer(&mut self) -> UsbResult<*mut u8> { // Do all range checks first diff --git a/hal/src/peripherals/usb/d11/bus.rs b/hal/src/peripherals/usb/d11/bus.rs index fb765e04ec48..2695ea36f1f8 100644 --- a/hal/src/peripherals/usb/d11/bus.rs +++ b/hal/src/peripherals/usb/d11/bus.rs @@ -8,7 +8,7 @@ use super::Descriptors; use crate::calibration::{usb_transn_cal, usb_transp_cal, usb_trim_cal}; use crate::clock; -use crate::gpio::{AlternateG, AnyPin, Pin, PA24, PA25}; +use crate::gpio::{AlternateG, AnyPin, PA24, PA25, Pin}; use crate::pac::usb::Device; use crate::pac::{Pm, Usb}; use crate::usb::buffer::*; @@ -50,22 +50,17 @@ impl From for EndpointTypeBits { #[derive(Default, Clone, Copy)] struct EPConfig { ep_type: EndpointTypeBits, - allocated_size: u16, max_packet_size: u16, + multi_packet_size: u16, addr: usize, } impl EPConfig { - fn new( - ep_type: EndpointType, - allocated_size: u16, - max_packet_size: u16, - buffer_addr: *mut u8, - ) -> Self { + fn new(ep_type: EndpointType, max_packet_size: u16, buffer_addr: *mut u8) -> Self { Self { ep_type: ep_type.into(), - allocated_size, max_packet_size, + multi_packet_size: 0, addr: buffer_addr as usize, } } @@ -126,7 +121,6 @@ impl AllEndpoints { dir: UsbDirection, idx: usize, ep_type: EndpointType, - allocated_size: u16, max_packet_size: u16, _interval: u8, buffer_addr: *mut u8, @@ -139,7 +133,7 @@ impl AllEndpoints { return Err(UsbError::EndpointOverflow); } - *bank = EPConfig::new(ep_type, allocated_size, max_packet_size, buffer_addr); + *bank = EPConfig::new(ep_type, max_packet_size, buffer_addr); Ok(EndpointAddress::from_parts(idx, dir)) } @@ -257,7 +251,7 @@ impl Bank<'_, InBank> { /// bank1 buffer. The caller must call set_ready() to finalize the /// transfer. pub fn write(&mut self, buf: &[u8]) -> UsbResult { - let size = buf.len().min(self.config().allocated_size as usize); + let size = buf.len().min(ALLOC_SIZE_MAX_PER_EP); let desc = self.desc_bank(); unsafe { @@ -364,6 +358,7 @@ impl Bank<'_, OutBank> { /// must call set_ready to indicate the buffer is free for the next /// transfer. pub fn read(&mut self, buf: &mut [u8]) -> UsbResult { + let mp_size = self.config().multi_packet_size; let desc = self.desc_bank(); let size = desc.get_byte_count() as usize; @@ -376,7 +371,7 @@ impl Bank<'_, OutBank> { } desc.set_byte_count(0); - desc.set_multi_packet_size(0); + desc.set_multi_packet_size(mp_size); Ok(size) } @@ -634,23 +629,8 @@ impl Inner { max_packet_size: u16, interval: u8, ) -> UsbResult { - // The USB hardware encodes the maximum packet size in 3 bits, so - // reserve enough buffer that the hardware won't overwrite it even if - // the other side issues an overly-long transfer. - let allocated_size = match max_packet_size { - 1..=8 => 8, - 9..=16 => 16, - 17..=32 => 32, - 33..=64 => 64, - 65..=128 => 128, - 129..=256 => 256, - 257..=512 => 512, - 513..=1023 => 1024, - _ => return Err(UsbError::Unsupported), - }; - // packet size is too big to fit into an endpoint buffer - if allocated_size > ALLOC_SIZE_MAX_PER_EP as u16 { + if max_packet_size > ALLOC_SIZE_MAX_PER_EP as u16 { return Err(UsbError::EndpointMemoryOverflow); } @@ -663,15 +643,8 @@ impl Inner { Some(addr) => addr.index(), }; - let addr = endpoints.allocate_endpoint( - dir, - idx, - ep_type, - allocated_size, - max_packet_size, - interval, - buffer, - )?; + let addr = + endpoints.allocate_endpoint(dir, idx, ep_type, max_packet_size, interval, buffer)?; Ok(addr) } @@ -690,6 +663,26 @@ impl Inner { false } + /// Configure the multi-packet reception of an OUT endpoint + fn set_out_ep_multi_packet_size( + &mut self, + ep: EndpointAddress, + size: u16, + ) -> Result<(), UsbError> { + { + let config = &mut self.endpoints.borrow_mut().endpoints[ep.index()].bank0; + if size > ALLOC_SIZE_MAX_PER_EP as u16 { + return Err(UsbError::EndpointMemoryOverflow); + } else if size % config.max_packet_size != 0 { + return Err(UsbError::Unsupported); + } else { + config.multi_packet_size = size; + } + } + self.bank0(ep)?.flush_config(); + Ok(()) + } + fn poll(&self) -> PollResult { let intflags = self.usb().intflag().read(); if intflags.eorst().bit() { @@ -831,6 +824,52 @@ impl UsbBus { pub fn check_sof_interrupt(&self) -> bool { disable_interrupts(|cs| self.inner.borrow(cs).borrow_mut().check_sof_interrupt()) } + + /// Configures the Multi-Packet-Rx feature of the USB peripheral. + /// + /// This allows for the USB Peripheral to ACK multiple incomming packets in hardware, and then + /// only fire an interrupt once the buffer is full. This will reduce the number of USB interrupts, + /// especially when dealing with BULK endpoints. + /// + /// The default behaviour of the endpoint is to trigger an interrupt as soon as any amount of + /// data is received (`size = 0`). + /// + /// The Buffer size can be configured using the HAL's feature flags: + /// + /// |Feature flag|Endpoint buffer size|Max number of hardware ACK packets| + /// |:-:|:-:|:-:| + /// |`usb-buffer-1k`|64|1| + /// |`usb-buffer-2k`|128|2| + /// |`usb-buffer-4k`|256|4| + /// |`usb-buffer-8k`|512|8| + /// |`usb-buffer-16k`|1024|16| + /// + /// **NOTE**: Above table assumes a 64 byte packet size (USB FS Standard) + /// + /// ## Requirements + /// 1. `size` is less than the allocated buffer of the endpoint. + /// 2. `size` is a multiple of the endpoints packet size. + /// 3. The provided `ep` is an OUT endpoint. + /// + /// ## Notes + /// * For IN endpoints, multi-packet transfer is automatically handled without + /// any user input. + /// * If less than `size` bytes are received by the endpoint, then it will NOT + /// fire an interrupt. + /// * ZLP packets still result in an interrupt being fired, regardless + /// of the endpoints received data length + pub fn configure_out_endpoint_multipacket_rx( + &self, + ep: EndpointAddress, + size: u16, + ) -> Result<(), UsbError> { + disable_interrupts(|cs| { + self.inner + .borrow(cs) + .borrow_mut() + .set_out_ep_multi_packet_size(ep, size) + }) + } } impl usb_device::bus::UsbBus for UsbBus { diff --git a/hal/src/peripherals/usb/d5x/buffer.rs b/hal/src/peripherals/usb/d5x/buffer.rs index ddc21b5b4372..179a12e4ea2c 100644 --- a/hal/src/peripherals/usb/d5x/buffer.rs +++ b/hal/src/peripherals/usb/d5x/buffer.rs @@ -16,10 +16,15 @@ pub const BUFFER_SIZE: usize = { { 8192 } + #[cfg(feature = "usb-buffer-16k")] + { + 16384 + } #[cfg(not(any( feature = "usb-buffer-1k", feature = "usb-buffer-4k", - feature = "usb-buffer-8k" + feature = "usb-buffer-8k", + feature = "usb-buffer-16k" )))] { 2048 // Default diff --git a/hal/src/peripherals/usb/d5x/bus.rs b/hal/src/peripherals/usb/d5x/bus.rs index 17fe18ea14db..7a8aa70e6000 100644 --- a/hal/src/peripherals/usb/d5x/bus.rs +++ b/hal/src/peripherals/usb/d5x/bus.rs @@ -8,7 +8,7 @@ use super::Descriptors; use crate::calibration::{usb_transn_cal, usb_transp_cal, usb_trim_cal}; use crate::clock; -use crate::gpio::{AlternateH, AnyPin, Pin, PA24, PA25}; +use crate::gpio::{AlternateH, AnyPin, PA24, PA25, Pin}; use crate::pac; use crate::pac::usb::Device; use crate::pac::{Mclk, Usb}; @@ -50,22 +50,17 @@ impl From for EndpointTypeBits { #[derive(Default, Clone, Copy)] struct EPConfig { ep_type: EndpointTypeBits, - allocated_size: u16, max_packet_size: u16, + multi_packet_size: u16, addr: usize, } impl EPConfig { - fn new( - ep_type: EndpointType, - allocated_size: u16, - max_packet_size: u16, - buffer_addr: *mut u8, - ) -> Self { + fn new(ep_type: EndpointType, max_packet_size: u16, buffer_addr: *mut u8) -> Self { Self { ep_type: ep_type.into(), - allocated_size, max_packet_size, + multi_packet_size: 0, addr: buffer_addr as usize, } } @@ -126,7 +121,6 @@ impl AllEndpoints { dir: UsbDirection, idx: usize, ep_type: EndpointType, - allocated_size: u16, max_packet_size: u16, _interval: u8, buffer_addr: *mut u8, @@ -139,7 +133,7 @@ impl AllEndpoints { return Err(UsbError::EndpointOverflow); } - *bank = EPConfig::new(ep_type, allocated_size, max_packet_size, buffer_addr); + *bank = EPConfig::new(ep_type, max_packet_size, buffer_addr); Ok(EndpointAddress::from_parts(idx, dir)) } @@ -253,7 +247,7 @@ impl Bank<'_, InBank> { /// bank1 buffer. The caller must call set_ready() to finalize the /// transfer. pub fn write(&mut self, buf: &[u8]) -> UsbResult { - let size = buf.len().min(self.config().allocated_size as usize); + let size = buf.len().min(ALLOC_SIZE_MAX_PER_EP); let desc = self.desc_bank(); unsafe { @@ -337,7 +331,7 @@ impl Bank<'_, OutBank> { let desc = self.desc_bank(); desc.set_address(config.addr as *mut u8); desc.set_endpoint_size(config.max_packet_size); - desc.set_multi_packet_size(0); + desc.set_multi_packet_size(config.multi_packet_size); desc.set_byte_count(0); } } @@ -352,6 +346,7 @@ impl Bank<'_, OutBank> { /// must call set_ready to indicate the buffer is free for the next /// transfer. pub fn read(&mut self, buf: &mut [u8]) -> UsbResult { + let mp_size = self.config().multi_packet_size; let desc = self.desc_bank(); let size = desc.get_byte_count() as usize; @@ -364,7 +359,7 @@ impl Bank<'_, OutBank> { } desc.set_byte_count(0); - desc.set_multi_packet_size(0); + desc.set_multi_packet_size(mp_size); Ok(size) } @@ -661,23 +656,8 @@ impl Inner { max_packet_size: u16, interval: u8, ) -> UsbResult { - // The USB hardware encodes the maximum packet size in 3 bits, so - // reserve enough buffer that the hardware won't overwrite it even if - // the other side issues an overly-long transfer. - let allocated_size = match max_packet_size { - 1..=8 => 8, - 9..=16 => 16, - 17..=32 => 32, - 33..=64 => 64, - 65..=128 => 128, - 129..=256 => 256, - 257..=512 => 512, - 513..=1023 => 1024, - _ => return Err(UsbError::Unsupported), - }; - // packet size is too big to fit into an endpoint buffer - if allocated_size > ALLOC_SIZE_MAX_PER_EP as u16 { + if max_packet_size > ALLOC_SIZE_MAX_PER_EP as u16 { return Err(UsbError::EndpointMemoryOverflow); } @@ -690,15 +670,8 @@ impl Inner { Some(addr) => addr.index(), }; - let addr = endpoints.allocate_endpoint( - dir, - idx, - ep_type, - allocated_size, - max_packet_size, - interval, - buffer, - )?; + let addr = + endpoints.allocate_endpoint(dir, idx, ep_type, max_packet_size, interval, buffer)?; Ok(addr) } @@ -717,6 +690,26 @@ impl Inner { false } + /// Configure the multi-packet reception of an OUT endpoint + fn set_out_ep_multi_packet_size( + &mut self, + ep: EndpointAddress, + size: u16, + ) -> Result<(), UsbError> { + { + let config = &mut self.endpoints.borrow_mut().endpoints[ep.index()].bank0; + if size > ALLOC_SIZE_MAX_PER_EP as u16 { + return Err(UsbError::EndpointMemoryOverflow); + } else if size % config.max_packet_size != 0 { + return Err(UsbError::Unsupported); + } else { + config.multi_packet_size = size; + } + } + self.bank0(ep)?.flush_config(); + Ok(()) + } + fn poll(&self) -> PollResult { let intflags = self.usb().intflag().read(); if intflags.eorst().bit() { @@ -858,6 +851,52 @@ impl UsbBus { pub fn check_sof_interrupt(&self) -> bool { disable_interrupts(|cs| self.inner.borrow(cs).borrow_mut().check_sof_interrupt()) } + + /// Configures the Multi-Packet-Rx feature of the USB peripheral. + /// + /// This allows for the USB Peripheral to ACK multiple incomming packets in hardware, and then + /// only fire an interrupt once the buffer is full. This will reduce the number of USB interrupts, + /// especially when dealing with BULK endpoints. + /// + /// The default behaviour of the endpoint is to trigger an interrupt as soon as any amount of + /// data is received (`size = 0`). + /// + /// The Buffer size can be configured using the HAL's feature flags: + /// + /// |Feature flag|Endpoint buffer size|Max number of hardware ACK packets| + /// |:-:|:-:|:-:| + /// |`usb-buffer-1k`|64|1| + /// |`usb-buffer-2k`|128|2| + /// |`usb-buffer-4k`|256|4| + /// |`usb-buffer-8k`|512|8| + /// |`usb-buffer-16k`|1024|16| + /// + /// **NOTE**: Above table assumes a 64 byte packet size (USB FS Standard) + /// + /// ## Requirements + /// 1. `size` is less than the allocated buffer of the endpoint. + /// 2. `size` is a multiple of the endpoints packet size. + /// 3. The provided `ep` is an OUT endpoint. + /// + /// ## Notes + /// * For IN endpoints, multi-packet transfer is automatically handled without + /// any user input. + /// * If less than `size` bytes are received by the endpoint, then it will NOT + /// fire an interrupt. + /// * ZLP packets still result in an interrupt being fired, regardless + /// of the endpoints received data length + pub fn configure_out_endpoint_multipacket_rx( + &self, + ep: EndpointAddress, + size: u16, + ) -> Result<(), UsbError> { + disable_interrupts(|cs| { + self.inner + .borrow(cs) + .borrow_mut() + .set_out_ep_multi_packet_size(ep, size) + }) + } } impl usb_device::bus::UsbBus for UsbBus { From e3ac59327c1b0bea68f434f4e89ac2b0ff0a44ea Mon Sep 17 00:00:00 2001 From: "Ashcon Mohseninia (RAND_ASH)" Date: Sun, 31 May 2026 19:13:38 +0100 Subject: [PATCH 037/114] fix(timer): Fix misuse of ctrlbset and ctrlbclr (#1001) --- hal/src/peripherals/timer/d11.rs | 6 +++--- hal/src/peripherals/timer/d5x.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hal/src/peripherals/timer/d11.rs b/hal/src/peripherals/timer/d11.rs index b484eabf417c..8b36b16fa233 100644 --- a/hal/src/peripherals/timer/d11.rs +++ b/hal/src/peripherals/timer/d11.rs @@ -57,11 +57,11 @@ where // need to manually read the bit here while count.ctrla().read().bits() & 1 != 0 {} - count.ctrlbset().write(|w| { + count.ctrlbclr().write(|w| { // Count up when the direction bit is zero - w.dir().clear_bit(); + w.dir().set_bit(); // Periodic - w.oneshot().clear_bit() + w.oneshot().set_bit() }); // Set TOP value for mfrq mode diff --git a/hal/src/peripherals/timer/d5x.rs b/hal/src/peripherals/timer/d5x.rs index 260f7e2f7b6a..4290e9c3b225 100644 --- a/hal/src/peripherals/timer/d5x.rs +++ b/hal/src/peripherals/timer/d5x.rs @@ -55,11 +55,11 @@ where count.ctrla().write(|w| w.swrst().set_bit()); while count.syncbusy().read().swrst().bit_is_set() {} - count.ctrlbset().write(|w| { + count.ctrlbclr().write(|w| { // Count up when the direction bit is zero - w.dir().clear_bit(); + w.dir().set_bit(); // Periodic - w.oneshot().clear_bit() + w.oneshot().set_bit() }); // Set TOP value for mfrq mode From 140789159f8ebd699e6374acc998c5d279efbb1d Mon Sep 17 00:00:00 2001 From: "Ashcon Mohseninia (RAND_ASH)" Date: Sun, 31 May 2026 19:30:50 +0100 Subject: [PATCH 038/114] chore: Introduce more peripheral free methods for consistency (#1000) * Add free methods to Tc,Tcc,Nvm and Trng peripherals --- hal/src/peripherals/nvm/mod.rs | 6 ++++++ hal/src/peripherals/pwm/d11.rs | 9 +++++++++ hal/src/peripherals/pwm/d5x.rs | 8 ++++++++ hal/src/peripherals/timer/d11.rs | 9 +++++++++ hal/src/peripherals/timer/d5x.rs | 9 +++++++++ hal/src/peripherals/trng.rs | 5 +++++ 6 files changed, 46 insertions(+) diff --git a/hal/src/peripherals/nvm/mod.rs b/hal/src/peripherals/nvm/mod.rs index e4082db3f19f..b41284b5739a 100644 --- a/hal/src/peripherals/nvm/mod.rs +++ b/hal/src/peripherals/nvm/mod.rs @@ -176,6 +176,12 @@ impl Nvm { Self { nvm } } + /// Releases the NvmCtrl resource + #[inline] + pub fn free(self) -> Nvmctrl { + self.nvm + } + /// Raw access to the registers. /// /// # Safety diff --git a/hal/src/peripherals/pwm/d11.rs b/hal/src/peripherals/pwm/d11.rs index 0b1b2bfb8497..49ef1c285475 100644 --- a/hal/src/peripherals/pwm/d11.rs +++ b/hal/src/peripherals/pwm/d11.rs @@ -57,6 +57,15 @@ impl $TYPE { } } + #[inline] + // Disables the TC, then releases it + pub fn free(self) -> crate::pac::$TC { + let count = self.tc.count16(); + count.ctrla().write(|w| w.swrst().set_bit()); + while count.ctrla().read().bits() & 1 != 0 {} + self.tc + } + pub fn set_period(&mut self, period: Hertz) { let params = TimerParams::new(period, self.clock_freq); diff --git a/hal/src/peripherals/pwm/d5x.rs b/hal/src/peripherals/pwm/d5x.rs index f101e3b494b2..30e4286a46cf 100644 --- a/hal/src/peripherals/pwm/d5x.rs +++ b/hal/src/peripherals/pwm/d5x.rs @@ -606,6 +606,14 @@ impl $TYPE { pinout, } } + + #[inline] + // Disables the TCC, then releases it + pub fn free(self) -> crate::pac::$TCC { + self.tcc.ctrla().write(|w| w.swrst().set_bit()); + while self.tcc.syncbusy().read().swrst().bit_is_set() {} + self.tcc + } } impl $crate::ehal_02::Pwm for $TYPE { diff --git a/hal/src/peripherals/timer/d11.rs b/hal/src/peripherals/timer/d11.rs index 8b36b16fa233..dd79f19f6477 100644 --- a/hal/src/peripherals/timer/d11.rs +++ b/hal/src/peripherals/timer/d11.rs @@ -129,6 +129,15 @@ impl TimerCounter<$TC> tc, } } + + #[inline] + // Disables the TC, then releases it + pub fn free(self) -> $TC { + let count = self.tc.count16(); + count.ctrla().write(|w| w.swrst().set_bit()); + while count.ctrla().read().bits() & 1 != 0 {} + self.tc + } } )+ } diff --git a/hal/src/peripherals/timer/d5x.rs b/hal/src/peripherals/timer/d5x.rs index 4290e9c3b225..31b457166d98 100644 --- a/hal/src/peripherals/timer/d5x.rs +++ b/hal/src/peripherals/timer/d5x.rs @@ -128,6 +128,15 @@ impl TimerCounter<$TC> tc, } } + + #[inline] + // Disables the TC, then releases it + pub fn free(self) -> $TC { + let count = self.tc.count_16(); + count.ctrla().write(|w| w.swrst().set_bit()); + while count.syncbusy().read().swrst().bit_is_set() {} + self.tc + } } )+ } diff --git a/hal/src/peripherals/trng.rs b/hal/src/peripherals/trng.rs index e6f76e14b32d..f4e7706d8037 100644 --- a/hal/src/peripherals/trng.rs +++ b/hal/src/peripherals/trng.rs @@ -13,6 +13,11 @@ impl Trng { Self(trng) } + /// Releases the Trng resource + pub fn free(self) -> pac::Trng { + self.0 + } + pub fn random(&self, buf: &mut [u8]) { for chunk in buf.chunks_mut(4) { chunk.copy_from_slice(&self.random_u32().to_le_bytes()[..chunk.len()]); From 03c84d7dd6cbfdee89264e79882041df968d74ac Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 10:16:21 +1200 Subject: [PATCH 039/114] Merge thumbv6m and thumbv7em clock modules Manually replicated from Bradley Harden's work, rebased as 4b94fb0aefdfcc2c6a70b2a183269ef66edfba4d --- hal/src/clock.rs | 16 ++++++++++++++++ .../clock/d11.rs => clock/v1_thumbv6m.rs} | 4 ++-- .../clock/d5x/v1.rs => clock/v1_thumbv7em.rs} | 2 +- hal/src/{peripherals/clock/d5x => clock}/v2.rs | 0 .../{peripherals/clock/d5x => clock}/v2/ahb.rs | 0 .../{peripherals/clock/d5x => clock}/v2/apb.rs | 0 .../{peripherals/clock/d5x => clock}/v2/dfll.rs | 0 .../{peripherals/clock/d5x => clock}/v2/dpll.rs | 0 .../{peripherals/clock/d5x => clock}/v2/gclk.rs | 0 .../clock/d5x => clock}/v2/osculp32k.rs | 0 .../{peripherals/clock/d5x => clock}/v2/pclk.rs | 0 .../{peripherals/clock/d5x => clock}/v2/reset.rs | 0 .../clock/d5x => clock}/v2/rtcosc.rs | 6 +++--- .../{peripherals/clock/d5x => clock}/v2/types.rs | 0 .../{peripherals/clock/d5x => clock}/v2/xosc.rs | 2 +- .../clock/d5x => clock}/v2/xosc32k.rs | 4 ++-- hal/src/lib.rs | 2 ++ hal/src/peripherals/clock/d5x/mod.rs | 9 --------- hal/src/peripherals/eic.rs | 2 +- hal/src/peripherals/mod.rs | 6 ------ 20 files changed, 28 insertions(+), 25 deletions(-) create mode 100644 hal/src/clock.rs rename hal/src/{peripherals/clock/d11.rs => clock/v1_thumbv6m.rs} (99%) rename hal/src/{peripherals/clock/d5x/v1.rs => clock/v1_thumbv7em.rs} (99%) rename hal/src/{peripherals/clock/d5x => clock}/v2.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/ahb.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/apb.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/dfll.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/dpll.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/gclk.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/osculp32k.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/pclk.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/reset.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/rtcosc.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/types.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/xosc.rs (99%) rename hal/src/{peripherals/clock/d5x => clock}/v2/xosc32k.rs (99%) delete mode 100644 hal/src/peripherals/clock/d5x/mod.rs diff --git a/hal/src/clock.rs b/hal/src/clock.rs new file mode 100644 index 000000000000..830b82b36470 --- /dev/null +++ b/hal/src/clock.rs @@ -0,0 +1,16 @@ +//! # Clocking API +//! +//! Users are encouraged to use [`v2`] variant of an API because of the richer +//! feature set and safety. +use atsamd_hal_macros::{hal_cfg, hal_module}; + +#[hal_module( + any("clock-d11", "clock-d21") => "clock/v1_thumbv6m.rs", + "clock-d5x" => "clock/v1_thumbv7em.rs", +)] +pub mod v1 {} + +pub use v1::*; + +#[hal_cfg("clock-d5x")] +pub mod v2; diff --git a/hal/src/peripherals/clock/d11.rs b/hal/src/clock/v1_thumbv6m.rs similarity index 99% rename from hal/src/peripherals/clock/d11.rs rename to hal/src/clock/v1_thumbv6m.rs index 0ff080c2cf17..7573da6c4d55 100644 --- a/hal/src/peripherals/clock/d11.rs +++ b/hal/src/clock/v1_thumbv6m.rs @@ -488,7 +488,7 @@ fn enable_gclk_apb(pm: &mut Pm) { /// Turn on the internal 32hkz oscillator pub fn enable_internal_32kosc(sysctrl: &mut Sysctrl) { - let calibration = super::calibration::osc32k_cal(); + let calibration = crate::calibration::osc32k_cal(); sysctrl.osc32k().write(|w| { unsafe { w.ondemand().clear_bit(); @@ -562,7 +562,7 @@ fn configure_and_enable_dfll48m(sysctrl: &mut Sysctrl, use_external_crystal: boo }); } else { // Apply calibration - let coarse = super::calibration::dfll48m_coarse_cal(); + let coarse = crate::calibration::dfll48m_coarse_cal(); let fine = 0x1ff; sysctrl.dfllval().write(|w| unsafe { diff --git a/hal/src/peripherals/clock/d5x/v1.rs b/hal/src/clock/v1_thumbv7em.rs similarity index 99% rename from hal/src/peripherals/clock/d5x/v1.rs rename to hal/src/clock/v1_thumbv7em.rs index a04166d20068..b6369fa3a429 100644 --- a/hal/src/peripherals/clock/d5x/v1.rs +++ b/hal/src/clock/v1_thumbv7em.rs @@ -15,7 +15,7 @@ use crate::clock::v2::pclk::{Pclk, PclkSourceId, ids::*}; use crate::pac::gclk::genctrl::Srcselect::*; use crate::pac::gclk::pchctrl::Genselect::*; use crate::pac::{self, Gclk, Mclk, Nvmctrl, Osc32kctrl, Oscctrl}; -use crate::sercom::*; +// use crate::sercom::*; // TODO why does this warn now but not before? use crate::time::Hertz; pub type ClockGenId = pac::gclk::pchctrl::Genselect; diff --git a/hal/src/peripherals/clock/d5x/v2.rs b/hal/src/clock/v2.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2.rs rename to hal/src/clock/v2.rs diff --git a/hal/src/peripherals/clock/d5x/v2/ahb.rs b/hal/src/clock/v2/ahb.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/ahb.rs rename to hal/src/clock/v2/ahb.rs diff --git a/hal/src/peripherals/clock/d5x/v2/apb.rs b/hal/src/clock/v2/apb.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/apb.rs rename to hal/src/clock/v2/apb.rs diff --git a/hal/src/peripherals/clock/d5x/v2/dfll.rs b/hal/src/clock/v2/dfll.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/dfll.rs rename to hal/src/clock/v2/dfll.rs diff --git a/hal/src/peripherals/clock/d5x/v2/dpll.rs b/hal/src/clock/v2/dpll.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/dpll.rs rename to hal/src/clock/v2/dpll.rs diff --git a/hal/src/peripherals/clock/d5x/v2/gclk.rs b/hal/src/clock/v2/gclk.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/gclk.rs rename to hal/src/clock/v2/gclk.rs diff --git a/hal/src/peripherals/clock/d5x/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/osculp32k.rs rename to hal/src/clock/v2/osculp32k.rs diff --git a/hal/src/peripherals/clock/d5x/v2/pclk.rs b/hal/src/clock/v2/pclk.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/pclk.rs rename to hal/src/clock/v2/pclk.rs diff --git a/hal/src/peripherals/clock/d5x/v2/reset.rs b/hal/src/clock/v2/reset.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/reset.rs rename to hal/src/clock/v2/reset.rs diff --git a/hal/src/peripherals/clock/d5x/v2/rtcosc.rs b/hal/src/clock/v2/rtcosc.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/rtcosc.rs rename to hal/src/clock/v2/rtcosc.rs index 7edd596ea319..a13b7376b678 100644 --- a/hal/src/peripherals/clock/d5x/v2/rtcosc.rs +++ b/hal/src/clock/v2/rtcosc.rs @@ -93,16 +93,16 @@ use core::marker::PhantomData; -use crate::pac::osc32kctrl::rtcctrl::Rtcselselect; -use crate::pac::osc32kctrl::Rtcctrl; use crate::pac::Osc32kctrl; +use crate::pac::osc32kctrl::Rtcctrl; +use crate::pac::osc32kctrl::rtcctrl::Rtcselselect; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment}; +use super::Source; use super::osculp32k::{OscUlp1kId, OscUlp32kId}; use super::xosc32k::{Xosc1kId, Xosc32kId}; -use super::Source; //============================================================================== // RtcOscToken diff --git a/hal/src/peripherals/clock/d5x/v2/types.rs b/hal/src/clock/v2/types.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/types.rs rename to hal/src/clock/v2/types.rs diff --git a/hal/src/peripherals/clock/d5x/v2/xosc.rs b/hal/src/clock/v2/xosc.rs similarity index 99% rename from hal/src/peripherals/clock/d5x/v2/xosc.rs rename to hal/src/clock/v2/xosc.rs index 2169636ca691..13290f988085 100644 --- a/hal/src/peripherals/clock/d5x/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -210,7 +210,7 @@ use typenum::U0; use crate::pac::oscctrl::{self, Xoscctrl}; -use crate::gpio::{FloatingDisabled, Pin, PinId, PA14, PA15, PB22, PB23}; +use crate::gpio::{FloatingDisabled, PA14, PA15, PB22, PB23, Pin, PinId}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; diff --git a/hal/src/peripherals/clock/d5x/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs similarity index 99% rename from hal/src/peripherals/clock/d5x/v2/xosc32k.rs rename to hal/src/clock/v2/xosc32k.rs index 838d02b1cbf8..e33c983b3578 100644 --- a/hal/src/peripherals/clock/d5x/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -345,9 +345,9 @@ use fugit::RateExtU32; use typenum::U0; use crate::pac::osc32kctrl::xosc32k::{Cgmselect, Startupselect}; -use crate::pac::osc32kctrl::{self, status, Cfdctrl}; +use crate::pac::osc32kctrl::{self, Cfdctrl, status}; -use crate::gpio::{FloatingDisabled, Pin, PA00, PA01}; +use crate::gpio::{FloatingDisabled, PA00, PA01, Pin}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; diff --git a/hal/src/lib.rs b/hal/src/lib.rs index e20f6b5025d1..4bf3008b7bba 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -74,6 +74,8 @@ macro_rules! dbgprint { #[cfg(feature = "async")] pub mod async_hal; +#[cfg(feature = "device")] +pub mod clock; #[cfg(feature = "device")] pub mod delay; #[cfg(feature = "device")] diff --git a/hal/src/peripherals/clock/d5x/mod.rs b/hal/src/peripherals/clock/d5x/mod.rs deleted file mode 100644 index ce090b2fd4b5..000000000000 --- a/hal/src/peripherals/clock/d5x/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! # Clocking API -//! -//! Users are encouraged to use [`v2`] variant of an API because of the richer -//! feature set and safety. - -pub mod v1; -pub use v1::*; - -pub mod v2; diff --git a/hal/src/peripherals/eic.rs b/hal/src/peripherals/eic.rs index e3d4f2fe829d..b959d9e74c38 100644 --- a/hal/src/peripherals/eic.rs +++ b/hal/src/peripherals/eic.rs @@ -83,7 +83,7 @@ mod impls {} pub use impls::async_api::*; #[hal_cfg("eic-d5x")] -use super::clock::v2::{self, gclk::GclkId, osculp32k::OscUlp32kId, pclk::Pclk, rtcosc::RtcOsc}; +use crate::clock::v2::{self, gclk::GclkId, osculp32k::OscUlp32kId, pclk::Pclk, rtcosc::RtcOsc}; pub type Sense = pac::eic::config::Sense0select; diff --git a/hal/src/peripherals/mod.rs b/hal/src/peripherals/mod.rs index 78eb4048a08c..45259be902ac 100644 --- a/hal/src/peripherals/mod.rs +++ b/hal/src/peripherals/mod.rs @@ -31,12 +31,6 @@ pub mod usb {} )] pub mod pwm {} -#[hal_module( - any("clock-d11", "clock-d21") => "clock/d11.rs", - "clock-d5x" => "clock/d5x/mod.rs", -)] -pub mod clock {} - #[hal_module("aes")] pub mod aes {} From 04ee5aa25b9daefc22607cd3f53a7580ff7acc9e Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 12:20:41 +1200 Subject: [PATCH 040/114] TODO Hack to compile, nightly only --- hal/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 4bf3008b7bba..d6b11ea42b72 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,4 +1,6 @@ #![no_std] +// TODO Allows using hal_cfg to gate clock v2 for thumbv6, nightly only +#![feature(proc_macro_hygiene)] pub use embedded_hal_1 as ehal; use embedded_hal_02 as ehal_02; From 5da868dd090865bfa78738f8615f797a7902f96e Mon Sep 17 00:00:00 2001 From: Bradley Harden Date: Wed, 28 Dec 2022 15:29:18 -0500 Subject: [PATCH 041/114] Work towards clock v2 GCLK and PCLK for thumbv6 This was the first "stash" in Bradley Harden's clock_v2_thumbv6m branch --- hal/src/clock/v2/gclk.rs | 274 +++++++++++++++++++++++++-------------- hal/src/clock/v2/pclk.rs | 65 +++++++--- 2 files changed, 226 insertions(+), 113 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 18a28eddf99e..4ca2372a3e30 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -335,6 +335,7 @@ //! [`Pins`]: crate::gpio::Pins //! [`Sercom0`]: crate::sercom::Sercom0 +use atsamd_hal_macros::hal_cfg; use core::cmp::max; use core::marker::PhantomData; @@ -344,19 +345,20 @@ use typenum::{U0, U1}; use crate::pac; use crate::pac::Nvmctrl; -use crate::pac::gclk::genctrl::Divselselect; -use crate::gpio::{self, AlternateM, AnyPin, Pin, PinId}; +use crate::gpio::{self, AlternateH, AnyPin, Pin, PinId}; use crate::pac::gclk::Genctrl; +#[hal_cfg(any("clock-d11", "clock-d21"))] +use crate::pac::gclk::Gendiv; use crate::pac::gclk::genctrl::Srcselect; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; use super::dfll::DfllId; -use super::dpll::{Dpll0Id, Dpll1Id}; -use super::osculp32k::OscUlp32kId; -use super::xosc::{Xosc0Id, Xosc1Id}; -use super::xosc32k::Xosc32kId; +// use super::dpll::{Dpll0Id, Dpll1Id}; +// use super::osculp32k::OscUlp32kId; +// use super::xosc::{Xosc0Id, Xosc1Id}; +// use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; //============================================================================== @@ -404,7 +406,20 @@ impl GclkToken { // of registers for the corresponding `GclkId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - unsafe { (*pac::Gclk::PTR).genctrl(G::NUM) } + #[hal_cfg("clock-d5x")] + unsafe { + &(*pac::Gclk::PTR).genctrl(G::NUM) + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*pac::Gclk::PTR).genctrl + } + } + + #[hal_cfg(any("clock-d11", "clock-d21"))] + #[inline] + fn gendiv(&self) -> &Gendiv { + unsafe { &(*pac::Gclk::PTR).gendiv } } /// Block until synchronization has completed @@ -416,8 +431,16 @@ impl GclkToken { // Safety: We are only reading from the `SYNCBUSY` register, and we are // only observing the bit corresponding to this particular `GclkId`, so // there is no risk of memory corruption. - let syncbusy = unsafe { &(*pac::Gclk::PTR).syncbusy() }; - while syncbusy.read().genctrl().bits() & Self::MASK != 0 {} + #[hal_cfg("clock-d5x")] + { + let syncbusy = unsafe { &(*pac::Gclk::PTR).syncbusy() }; + while syncbusy.read().genctrl().bits() & Self::MASK != 0 {} + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + let status = unsafe { &(*pac::Gclk::PTR).status }; + while status.read().syncbusy().bit() {} + } } /// Set the clock source for this [`Gclk`] @@ -436,10 +459,21 @@ impl GclkToken { let (divsel, div) = div.divsel_div(); // Safety: The `DIVSEL` and `DIV` values are derived from the // `GclkDivider` type, so they are guaranteed to be valid. - self.genctrl().modify(|_, w| unsafe { - w.divsel().variant(divsel); - w.div().bits(div) - }); + #[hal_cfg("clock-d5x")] + { + self.genctrl().modify(|_, w| unsafe { + w.divsel().bit(divsel); + w.div().bits(div) + }); + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + self.genctrl().write(|w| { + unsafe { w.id().bits(G::NUM as u8) }; + w.divsel().bit(divsel) + }); + self.gendiv().write(|w| unsafe { w.div().bits(div) }); + } self.wait_syncbusy(); } @@ -466,7 +500,7 @@ impl GclkToken { /// Disable [`Gclk`] output on a GPIO [`Pin`] /// - /// If a corresponding [`Pin`] is in the [`AlternateM`] mode, it's logic + /// If a corresponding [`Pin`] is in the [`AlternateH`] mode, it's logic /// level will depend on the [`output_off_value`]. #[inline] fn disable_gclk_out(&mut self) { @@ -475,33 +509,31 @@ impl GclkToken { } #[inline] - fn configure(&mut self, id: DynGclkSourceId, settings: Settings) { + fn enable(&mut self, id: DynGclkSourceId, settings: Settings) { let (divsel, div) = settings.div.divsel_div(); - self.genctrl().modify(|_, w| { + self.genctrl().write(|w| { // Safety: The `DIVSEL` and `DIV` values are derived from the // `GclkDivider` type, so they are guaranteed to be valid. unsafe { - w.divsel().variant(divsel); + #[hal_cfg("clock-d5x")] w.div().bits(div); + #[hal_cfg(any("clock-d11", "clock-d21"))] + w.id().bits(G::NUM as u8); }; + w.divsel().bit(divsel); w.src().variant(id.into()); w.idc().bit(settings.improve_duty_cycle); w.oov().bit(settings.output_off_value) }); - self.wait_syncbusy(); - } - - /// Enable the [`Gclk`] - #[inline] - fn enable(&mut self) { - self.genctrl().modify(|_, w| w.genen().set_bit()); + #[hal_cfg(any("clock-d11", "clock-d21"))] + self.gendiv().write(|w| unsafe { w.div().bits(div) }); self.wait_syncbusy(); } /// Disable the [`Gclk`] #[inline] fn disable(&mut self) { - self.genctrl().modify(|_, w| w.genen().clear_bit()); + self.genctrl().write(|w| w.genen().clear_bit()); self.wait_syncbusy(); } } @@ -516,6 +548,20 @@ impl GclkToken { /// generators. /// /// `DynGclkId` is the value-level equivalent of [`GclkId`]. +#[hal_cfg(any("clock-d11", "clock-d21"))] +pub enum DynGclkId { + Gclk0, + Gclk1, + Gclk2, + Gclk3, + Gclk4, + Gclk5, + Gclk6, + Gclk7, + Gclk8, +} + +#[hal_cfg("clock-d5x")] pub enum DynGclkId { Gclk0, Gclk1, @@ -589,7 +635,32 @@ impl GclkId for Gclk1Id { type Divider = GclkDiv16; } -seq!(N in 2..=11 { +macro_rules! with_gclk_max { + ($N:ident in $start:literal ..= max $mac:tt) => { + #[hal_cfg("clock-d5x")] + seq!($N in $start..=11 $mac); + #[hal_cfg(any("clock-d11", "clock-d21"))] + seq!($N in $start..=8 $mac); + }; +} + +#[hal_cfg("clock-d5x")] +macro_rules! with_gclk_max_expr { + ($N:ident in $start:literal ..= max $mac:tt) => { + seq!($N in $start..=11 $mac) + }; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +macro_rules! with_gclk_max_expr { + ($N:ident in $start:literal ..= max $mac:tt) => { + seq!($N in $start..=8 $mac) + }; +} + +pub(super) use with_gclk_max_expr; + +with_gclk_max!(N in 2..=max { paste! { /// Type-level variant of [`GclkId`] representing the identity of #[doc = "GCLK" N] @@ -631,7 +702,7 @@ pub trait GclkDivider: Sealed + Default + Copy { /// Returns the actual clock divider value as a `u32` fn divider(&self) -> u32; /// Return the corresponding `DIVSEL` and and `DIV` register fields - fn divsel_div(&self) -> (Divselselect, u16); + fn divsel_div(&self) -> (bool, u16); } //============================================================================== @@ -678,11 +749,11 @@ impl GclkDivider for GclkDiv8 { } #[inline] - fn divsel_div(&self) -> (Divselselect, u16) { + fn divsel_div(&self) -> (bool, u16) { match self { - GclkDiv8::Div(div) => (Divselselect::Div1, (*div).into()), - GclkDiv8::Div2Pow8 => (Divselselect::Div2, 7), - GclkDiv8::Div2Pow9 => (Divselselect::Div2, 8), + GclkDiv8::Div(div) => (false, (*div).into()), + GclkDiv8::Div2Pow8 => (true, 7), + GclkDiv8::Div2Pow9 => (true, 8), } } } @@ -730,11 +801,11 @@ impl GclkDivider for GclkDiv16 { } #[inline] - fn divsel_div(&self) -> (Divselselect, u16) { + fn divsel_div(&self) -> (bool, u16) { match self { - GclkDiv16::Div(div) => (Divselselect::Div1, *div), - GclkDiv16::Div2Pow16 => (Divselselect::Div2, 15), - GclkDiv16::Div2Pow17 => (Divselselect::Div2, 16), + GclkDiv16::Div(div) => (false, *div), + GclkDiv16::Div2Pow16 => (true, 15), + GclkDiv16::Div2Pow17 => (true, 16), } } } @@ -821,7 +892,7 @@ pub trait Gclk0Io where Self: Sized, Self: GclkIo, - Self: GclkSourceId>, + Self: GclkSourceId>, { } @@ -851,18 +922,33 @@ pub enum DynGclkSourceId { } impl From for Srcselect { + #[hal_cfg("clock-d5x")] fn from(source: DynGclkSourceId) -> Self { use DynGclkSourceId::*; match source { - Dfll => Self::Dfll, - Dpll0 => Self::Dpll0, - Dpll1 => Self::Dpll1, - Gclk1 => Self::Gclkgen1, - GclkIn => Self::Gclkin, - OscUlp32k => Self::Osculp32k, - Xosc0 => Self::Xosc0, - Xosc1 => Self::Xosc1, - Xosc32k => Self::Xosc32k, + Dfll => Srcselect::Dfll, + Dpll0 => Srcselect::Dpll0, + Dpll1 => Srcselect::Dpll1, + Gclk1 => Srcselect::Gclkgen1, + GclkIn => Srcselect::Gclkin, + OscUlp32k => Srcselect::Osculp32k, + Xosc0 => Srcselect::Xosc0, + Xosc1 => Srcselect::Xosc1, + Xosc32k => Srcselect::Xosc32k, + } + } + + #[hal_cfg(any("clock-d11", "clock-d21"))] + fn from(source: DynGclkSourceId) -> Self { + use DynGclkSourceId::*; + match source { + Dfll => Srcselect::Dfll48m, + Dpll => Srcselect::Dpll96m, + Gclk1 => Srcselect::Gclkgen1, + GclkIn => Srcselect::Gclkin, + OscUlp32k => Srcselect::Osculp32k, + Xosc => Srcselect::Xosc, + Xosc32k => Srcselect::Xosc32k, } } } @@ -900,38 +986,38 @@ impl GclkSourceId for DfllId { const DYN: DynGclkSourceId = DynGclkSourceId::Dfll; type Resource = (); } -impl GclkSourceId for Dpll0Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Dpll0; - type Resource = (); -} -impl GclkSourceId for Dpll1Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; - type Resource = (); -} -impl GclkSourceId for Gclk1Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; - type Resource = (); -} +//impl GclkSourceId for Dpll0Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Dpll0; +// type Resource = (); +//} +//impl GclkSourceId for Dpll1Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; +// type Resource = (); +//} +//impl GclkSourceId for Gclk1Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; +// type Resource = (); +//} impl GclkSourceId for I { const DYN: DynGclkSourceId = DynGclkSourceId::GclkIn; - type Resource = Pin; -} -impl GclkSourceId for OscUlp32kId { - const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; - type Resource = (); -} -impl GclkSourceId for Xosc0Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; - type Resource = (); -} -impl GclkSourceId for Xosc1Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; - type Resource = (); -} -impl GclkSourceId for Xosc32kId { - const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; - type Resource = (); + type Resource = Pin; } +//impl GclkSourceId for OscUlp32kId { +// const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; +// type Resource = (); +//} +//impl GclkSourceId for Xosc0Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; +// type Resource = (); +//} +//impl GclkSourceId for Xosc1Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; +// type Resource = (); +//} +//impl GclkSourceId for Xosc32kId { +// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; +// type Resource = (); +//} //============================================================================== // NotGclkIo @@ -1054,7 +1140,7 @@ pub type Gclk0 = Gclk; /// on [`EnabledGclk0`] to configure the `Gclk` while it is actively running. pub type EnabledGclk0 = EnabledGclk; -seq!(G in 1..=11 { +with_gclk_max!(G in 1..=max { paste! { /// Type alias for the corresponding [`Gclk`] pub type Gclk~G = Gclk<[], I>; @@ -1098,7 +1184,7 @@ where /// /// Freeing a [`Gclk`] returns the corresponding [`GclkToken`] and GPIO /// [`Pin`]. - pub fn free_pin(self) -> (GclkToken, Pin) { + pub fn free_pin(self) -> (GclkToken, Pin) { (self.token, self.resource) } } @@ -1212,10 +1298,10 @@ where /// When calling this function, the new OOV will take effect immediately. /// /// However, remember that the `Pin` is not controlled by the `Gclk` unless - /// the `Pin` is configured in [`AlternateM`] mode. `Pin`s are automatically - /// set to `AlternateM` mode when calling [`enable_gclk_out`], but by that + /// the `Pin` is configured in [`AlternateH`] mode. `Pin`s are automatically + /// set to `AlternateH` mode when calling [`enable_gclk_out`], but by that /// point, the OOV is irrelevant. If you need the `Pin` to be set to its - /// OOV, you must *manually* set it to `AlternateM` mode before constructing + /// OOV, you must *manually* set it to `AlternateH` mode before constructing /// the `GclkOut`. /// /// [`enable_gclk_out`]: EnabledGclk::enable_gclk_out @@ -1237,8 +1323,7 @@ where /// [`Source`] for other clocks. #[inline] pub fn enable(mut self) -> EnabledGclk { - self.token.configure(I::DYN, self.settings); - self.token.enable(); + self.token.enable(I::DYN, self.settings); Enabled::new(self) } } @@ -1296,7 +1381,7 @@ impl EnabledGclk0 { self, pin: P, freq: impl Into, - ) -> (EnabledGclk0, Pin) + ) -> (EnabledGclk0, Pin) where I: Gclk0Io, P: AnyPin, @@ -1337,7 +1422,7 @@ impl EnabledGclk0 { pub fn swap_pin_for_source( self, source: S, - ) -> (EnabledGclk0, Pin, S::Inc) + ) -> (EnabledGclk0, Pin, S::Inc) where I: Gclk0Io, S: Source + Increment, @@ -1403,7 +1488,7 @@ where // Tokens //============================================================================== -seq!(N in 1..=11 { +with_gclk_max!(N in 1..=max { paste! { /// Set of [`GclkToken`]s representing the disabled [`Gclk`]s at /// power-on reset @@ -1423,13 +1508,12 @@ seq!(N in 1..=11 { /// All of the invariants required by `GclkToken::new` must be /// upheld here as well. #[inline] - pub(super) unsafe fn new(nvmctrl: &mut Nvmctrl) -> Self { - unsafe { - // Use auto wait states - nvmctrl.ctrla().modify(|_, w| w.autows().set_bit()); - GclkTokens { - #( gclk~N: GclkToken::new(), )* - } + pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { + // Use auto wait states + //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); + todo!(); + GclkTokens { + #( gclk~N: unsafe {GclkToken::new()}, )* } } } @@ -1448,7 +1532,7 @@ seq!(N in 1..=11 { /// See the [module-level documentation](self) for an example of creating a /// [`GclkOut`] from an [`EnabledGclk`]. pub struct GclkOut { - pin: Pin, + pin: Pin, freq: Hertz, } @@ -1480,7 +1564,7 @@ where /// enforce this requirement. /// /// Finally, when a [`GclkOut`] is disabled, but the [`Pin`] is still in - /// [`AlternateM`] mode, it takes the "output off value" of the `Gclk`. See + /// [`AlternateH`] mode, it takes the "output off value" of the `Gclk`. See /// the [`Gclk::output_off_value`] documentation for more details. #[inline] pub fn enable_gclk_out

(mut self, pin: P) -> (EnabledGclk, GclkOut) @@ -1500,13 +1584,13 @@ where /// /// Disabling [`GclkIo`] output will [`Decrement`] the [`EnabledGclk`] /// counter. When a [`GclkOut`] is disabled, but the [`Pin`] is still in - /// [`AlternateM`] mode, it takes the "output off value" of the `Gclk`. See + /// [`AlternateH`] mode, it takes the "output off value" of the `Gclk`. See /// the [`Gclk::output_off_value`] documentation for more details. #[inline] pub fn disable_gclk_out( mut self, gclk_out: GclkOut, - ) -> (EnabledGclk, Pin) + ) -> (EnabledGclk, Pin) where N: Decrement, I: GclkIo, diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index cd58db8f6cca..59f644b2f91c 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -62,7 +62,7 @@ //! [`clock::v2::types`]: super::types //! [`Sercom`]: crate::sercom::Sercom -use atsamd_hal_macros::hal_macro_helper; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; @@ -70,13 +70,22 @@ use paste::paste; use seq_macro::seq; use crate::pac; + +#[hal_cfg(any("clock-d11", "clock-d21"))] +use crate::pac::gclk::clkctrl::Genselect; +#[hal_cfg("clock-d5x")] use crate::pac::gclk::pchctrl::Genselect; +#[hal_cfg(any("clock-d11", "clock-d21"))] +use crate::pac::gclk::Clkctrl as Ctrl; +#[hal_cfg("clock-d5x")] +use crate::pac::gclk::Pchctrl as Ctrl; + use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; use super::Source; -use super::gclk::{DynGclkId, GclkId}; +use super::gclk::{DynGclkId, GclkId, with_gclk_max_expr}; //============================================================================== // PclkToken @@ -113,31 +122,48 @@ impl PclkToken

{ /// Access the corresponding `PCHCTRL` register #[inline] - fn pchctrl(&self) -> &pac::gclk::Pchctrl { + fn ctrl(&self) -> &Ctrl { // Safety: Each `PclkToken` only has access to a mutually exclusive set // of registers for the corresponding `PclkId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - unsafe { (*pac::Gclk::PTR).pchctrl(P::DYN as usize) } + #[hal_cfg("clock-d5x")] + unsafe { + &(*pac::Gclk::PTR).pchctrl(P::DYN as usize) + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*pac::Gclk::PTR).clkctrl + } } /// Set the [`Pclk`] source #[inline] - fn set_source(&mut self, source: DynPclkSourceId) { - self.pchctrl() - .modify(|_, w| w.r#gen().variant(source.into())); - } - - /// Enable the [`Pclk`] - #[inline] - fn enable(&mut self) { - self.pchctrl().modify(|_, w| w.chen().set_bit()); + fn enable(&mut self, source: DynPclkSourceId) { + self.ctrl().write(|w| { + w.r#gen().variant(source.into()); + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + w.clken().set_bit(); + unsafe { w.id().bits(P::DYN as u8) } + } + #[hal_cfg("clock-d5x")] + w.chen().set_bit() + }); } /// Disable the [`Pclk`] #[inline] fn disable(&mut self) { - self.pchctrl().modify(|_, w| w.chen().clear_bit()); + self.ctrl().modify(|_, w| { + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + w.clken().clear_bit(); + unsafe { w.id().bits(P::DYN as u8) } + } + #[hal_cfg("clock-d5x")] + w.chen().clear_bit() + }); } } @@ -165,6 +191,9 @@ pub mod ids { pub use crate::sercom::Sercom7; pub use super::super::dfll::DfllId; + //pub struct DfllId; + //impl crate::typelevel::Sealed for DfllId {} + #[hal_cfg("clock-d5x")] pub use super::super::dpll::{Dpll0Id, Dpll1Id}; pub use super::super::types::{ @@ -188,7 +217,6 @@ pub mod ids { #[hal_cfg("i2s")] pub use super::super::types::{I2S0, I2S1}; } - use ids::*; /// Append the list of all [`PclkId`] types and `snake_case` id names to the @@ -231,7 +259,9 @@ macro_rules! with_pclk_types_ids { $some_macro!( $( $args )* (DfllId = 0, dfll) + #[hal_cfg("clock-d5x")] (Dpll0Id = 1, dpll0) + #[hal_cfg("clock-d5x")] (Dpll1Id = 2, dpll1) (SlowClk = 3, slow) (Eic = 4, eic) @@ -370,7 +400,7 @@ pub type DynPclkSourceId = DynGclkId; /// Convert from [`DynPclkSourceId`] to the equivalent [PAC](crate::pac) type impl From for Genselect { fn from(source: DynPclkSourceId) -> Self { - seq!(N in 0..=11 { + with_gclk_max_expr!(N in 0..=max { match source { #( DynGclkId::Gclk~N => Genselect::Gclk~N, @@ -472,8 +502,7 @@ where S: Source + Increment, { let freq = gclk.freq(); - token.set_source(I::DYN); - token.enable(); + token.enable(I::DYN); let pclk = Pclk::new(token, freq); (pclk, gclk.inc()) } From 241e08d42a30b1efa8664cf5acca37d24ceda1d7 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 12:23:07 +1200 Subject: [PATCH 042/114] TODO Another hack to compile --- hal/src/clock/v2/gclk.rs | 1 + hal/src/lib.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 4ca2372a3e30..585caeb0b6a9 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -1508,6 +1508,7 @@ with_gclk_max!(N in 1..=max { /// All of the invariants required by `GclkToken::new` must be /// upheld here as well. #[inline] + #[allow(unreachable_code)] // TODO remove when todo is removed pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { // Use auto wait states //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); diff --git a/hal/src/lib.rs b/hal/src/lib.rs index d6b11ea42b72..f5f588c13a1d 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,6 +1,8 @@ #![no_std] // TODO Allows using hal_cfg to gate clock v2 for thumbv6, nightly only #![feature(proc_macro_hygiene)] +// TODO as above +#![feature(stmt_expr_attributes)] pub use embedded_hal_1 as ehal; use embedded_hal_02 as ehal_02; From 2d92ffaa6fcb381ba30ca40fcfd9b15044d5bfdc Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 12:59:00 +1200 Subject: [PATCH 043/114] stash 2 xosc32k --- hal/src/clock/v2/xosc32k.rs | 175 +++++++++++++++++++++++++++--------- 1 file changed, 135 insertions(+), 40 deletions(-) diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index e33c983b3578..92e61ca9bc90 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -341,17 +341,31 @@ //! [`is_switched`]: Xosc32kCfd::is_switched //! [`switch_back`]: Xosc32kCfd::switch_back +use atsamd_hal_macros::hal_cfg; use fugit::RateExtU32; use typenum::U0; -use crate::pac::osc32kctrl::xosc32k::{Cgmselect, Startupselect}; -use crate::pac::osc32kctrl::{self, Cfdctrl, status}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use super::super::osculp32k::OscUlp32kId; + pub use crate::pac::Osc32kctrl as PERIPHERAL; + pub use crate::pac::osc32kctrl::xosc32k::Cgmselect; + pub use crate::pac::osc32kctrl::{Cfdctrl, Xosc32k as PacXosc32k, status::R as STATUS_R}; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::Sysctrl as PERIPHERAL; + pub use crate::pac::sysctrl::Xosc32k as PacXosc32k; + pub use crate::pac::sysctrl::pclksr::R as STATUS_R; +} + +use imports::*; use crate::gpio::{FloatingDisabled, PA00, PA01, Pin}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; -use super::osculp32k::OscUlp32kId; use super::{Enabled, Source}; //============================================================================== @@ -398,8 +412,10 @@ pub struct Xosc32kToken(()); /// /// Clock failure detection is disabled at power-on reset. To use it, you must /// first enable it by exchanging the token with [`Xosc32kCfd::enable`]. +#[hal_cfg("clock-d5x")] pub struct Xosc32kCfdToken(()); +#[hal_cfg("clock-d5x")] /// Set of tokens representing the disabled XOSC32K clocks power-on reset pub struct Xosc32kTokens { pub base: Xosc32kBaseToken, @@ -408,6 +424,7 @@ pub struct Xosc32kTokens { pub cfd: Xosc32kCfdToken, } +#[hal_cfg("clock-d5x")] impl Xosc32kTokens { /// Create the set of tokens /// @@ -426,12 +443,46 @@ impl Xosc32kTokens { } } +#[hal_cfg(any("clock-d11", "clock-d21"))] + +/// Set of tokens representing the disabled XOSC32K clocks power-on reset +pub struct Xosc32kTokens { + pub base: Xosc32kBaseToken, + pub xosc1k: Xosc1kToken, + pub xosc32k: Xosc32kToken, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl Xosc32kTokens { + /// Create the set of tokens + /// + /// # Safety + /// + /// There must never be more than one instance of these tokens at any given + /// time. See the notes on `Token` types and memory safety in the root of + /// the `clock` module for more details. + pub(super) unsafe fn new() -> Self { + Self { + base: Xosc32kBaseToken(()), + xosc1k: Xosc1kToken(()), + xosc32k: Xosc32kToken(()), + } + } +} + impl Xosc32kBaseToken { #[inline] - fn status(&self) -> status::R { + fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. - unsafe { (*crate::pac::Osc32kctrl::PTR).status().read() } + #[hal_cfg("clock-d5x")] + unsafe { + (*PERIPHERAL::PTR).status().read() + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + (*PERIPHERAL::PTR).pclksr().read() + } } /// Check whether the XOSC32K is stable and ready @@ -441,11 +492,11 @@ impl Xosc32kBaseToken { } #[inline] - fn xosc32k(&self) -> &osc32kctrl::Xosc32k { + fn xosc32k(&self) -> &PacXosc32k { // Safety: The `Xosc32kBaseToken` has exclusive access to the `XOSC32K` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { (*crate::pac::Osc32kctrl::PTR).xosc32k() } + unsafe { &(*PERIPHERAL::PTR).xosc32k() } } /// Reset the XOSC32K register @@ -456,21 +507,31 @@ impl Xosc32kBaseToken { /// Set most of the fields in the XOSC32K register #[inline] - fn set_xosc32k(&mut self, settings: Settings) { - let xtalen = settings.mode == DynMode::CrystalMode; - self.xosc32k().modify(|_, w| { + #[hal_cfg("clock-d5x")] + fn enable(&mut self, mode: DynMode, settings: Settings) { + let xtalen = mode == DynMode::CrystalMode; + self.xosc32k().write(|w| { w.cgm().variant(settings.cgm.into()); - w.startup().variant(settings.start_up.into()); + unsafe { w.startup().bits(settings.start_up as u8) }; w.ondemand().bit(settings.on_demand); w.runstdby().bit(settings.run_standby); - w.xtalen().bit(xtalen) + w.xtalen().bit(xtalen); + w.enable().set_bit() }); } - /// Disable the XOSC32K #[inline] - fn enable(&mut self) { - self.xosc32k().modify(|_, w| w.enable().set_bit()); + #[hal_cfg(any("clock-d11", "clock-d21"))] + fn enable(&mut self, mode: DynMode, settings: Settings) { + let xtalen = mode == DynMode::CrystalMode; + self.xosc32k().write(|w| { + w.aampen().bit(settings.aampen); + unsafe { w.startup().bits(settings.start_up as u8) }; + w.ondemand().bit(settings.on_demand); + w.runstdby().bit(settings.run_standby); + w.xtalen().bit(xtalen); + w.enable().set_bit() + }); } /// Disable the XOSC32K @@ -510,12 +571,13 @@ impl Xosc32kBaseToken { } } +#[hal_cfg("clock-d5x")] impl Xosc32kCfdToken { #[inline] - fn status(&self) -> status::R { + fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. - unsafe { (*crate::pac::Osc32kctrl::PTR).status().read() } + unsafe { (*PERIPHERAL::PTR).status().read() } } /// Check whether the XOSC32K has triggered failure detection @@ -535,7 +597,7 @@ impl Xosc32kCfdToken { // Safety: The `Xosc32kCfdToken` has exclusive access to the `Cfdctrl` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { (*crate::pac::Osc32kctrl::PTR).cfdctrl() } + unsafe { &(*PERIPHERAL::PTR).cfdctrl() } } /// Enable clock failure detection and set the safe clock divider @@ -571,13 +633,46 @@ impl Xosc32kCfdToken { // All of these fields are set in a single write to XOSC32K during the call to // [`Xosc32kBase::enable`]. The remaining fields are only modified after it has // been enabled. +#[hal_cfg("clock-d5x")] #[derive(Clone, Copy)] struct Settings { start_up: StartUpDelay, cgm: ControlGainMode, on_demand: bool, run_standby: bool, - mode: DynMode, +} + +#[hal_cfg("clock-d5x")] +impl Default for Settings { + fn default() -> Self { + Settings { + start_up: StartUpDelay::Delay63ms, + cgm: ControlGainMode::Standard, + on_demand: true, + run_standby: false, + } + } +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[derive(Clone, Copy)] +struct Settings { + start_up: StartUpDelay, + aampen: bool, + on_demand: bool, + run_standby: bool, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl Default for Settings { + fn default() -> Self { + Settings { + start_up: StartUpDelay::Delay63ms, + aampen: false, + on_demand: true, + run_standby: false, + } + } } //============================================================================== @@ -631,6 +726,7 @@ impl From for bool { /// The start up delay is counted using the [`OscUlp32k`] clock. /// /// [`OscUlp32k`]: super::osculp32k::OscUlp32k +#[hal_cfg("clock-d5x")] #[repr(u8)] #[derive(Clone, Copy, Default, PartialEq, Eq)] pub enum StartUpDelay { @@ -644,18 +740,19 @@ pub enum StartUpDelay { Delay8s, } -impl From for Startupselect { - fn from(delay: StartUpDelay) -> Self { - match delay { - StartUpDelay::Delay63ms => Startupselect::Cycle2048, - StartUpDelay::Delay125ms => Startupselect::Cycle4096, - StartUpDelay::Delay500ms => Startupselect::Cycle16384, - StartUpDelay::Delay1s => Startupselect::Cycle32768, - StartUpDelay::Delay2s => Startupselect::Cycle65536, - StartUpDelay::Delay4s => Startupselect::Cycle131072, - StartUpDelay::Delay8s => Startupselect::Cycle262144, - } - } +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[repr(u8)] +#[derive(Clone, Copy, Default, PartialEq, Eq)] +pub enum StartUpDelay { + #[default] + Delay122us, + Delay1ms, + Delay63ms, + Delay125ms, + Delay500ms, + Delay1s, + Delay2s, + Delay4s, } //============================================================================== @@ -666,6 +763,7 @@ impl From for Startupselect { /// /// The XOSC32K crystal oscillator control loop has a configurable gain to allow /// users to trade power for speed and stability. +#[hal_cfg("clock-d5x")] #[derive(Copy, Clone, Default, PartialEq, Eq)] pub enum ControlGainMode { #[default] @@ -673,6 +771,7 @@ pub enum ControlGainMode { HighSpeed, } +#[hal_cfg("clock-d5x")] impl From for Cgmselect { fn from(cgm: ControlGainMode) -> Self { match cgm { @@ -843,6 +942,7 @@ impl Xosc32kBase { /// Set the crystal oscillator [`ControlGainMode`] #[inline] + #[hal_cfg("clock-d5x")] pub fn control_gain_mode(mut self, cgm: ControlGainMode) -> Self { self.settings.cgm = cgm; self @@ -852,13 +952,7 @@ impl Xosc32kBase { impl Xosc32kBase { #[inline] fn new(token: Xosc32kBaseToken, pins: M::Pins) -> Self { - let settings = Settings { - start_up: StartUpDelay::Delay63ms, - cgm: ControlGainMode::Standard, - on_demand: true, - run_standby: false, - mode: M::DYN, - }; + let settings = Settings::default(); Self { token, pins, @@ -932,8 +1026,7 @@ impl Xosc32kBase { #[inline] pub fn enable(mut self) -> EnabledXosc32kBase { self.token.reset(); - self.token.set_xosc32k(self.settings); - self.token.enable(); + self.token.enable(M::DYN, self.settings); Enabled::new(self) } } @@ -997,10 +1090,12 @@ impl EnabledXosc32kBase { /// /// [`OscUlp32k`]: super::osculp32k::OscUlp32k /// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k +#[hal_cfg("clock-d5x")] pub struct Xosc32kCfd { token: Xosc32kCfdToken, } +#[hal_cfg("clock-d5x")] impl Xosc32kCfd { /// Enable continuous monitoring of the XOSC32K for clock failure /// From 07cfd7e5dc898a0340f911b57f579251baf9d881 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:28:20 +1200 Subject: [PATCH 044/114] stash 2 xosc --- hal/src/clock/v2/xosc.rs | 231 ++++++++++++++++++++++++++++++--------- 1 file changed, 179 insertions(+), 52 deletions(-) diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 13290f988085..e5b03253263f 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -204,17 +204,32 @@ //! [`Dfll`]: super::dfll::Dfll //! [`EnabledDfll`]: super::dfll::EnabledDfll +use atsamd_hal_macros::hal_cfg; use core::marker::PhantomData; use typenum::U0; -use crate::pac::oscctrl::{self, Xoscctrl}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use super::super::dfll::DfllId; + pub use crate::gpio::{PB22, PB23}; + pub use crate::pac::Oscctrl as Peripheral; + pub use crate::pac::oscctrl::{Xoscctrl, status::R as STATUS_R}; + pub use crate::typelevel::{Decrement, Increment}; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::Sysctrl as Peripheral; + pub use crate::pac::sysctrl::{Xosc as Xoscctrl, pclksr::R as STATUS_R, xosc::Gainselect}; +} -use crate::gpio::{FloatingDisabled, PA14, PA15, PB22, PB23, Pin, PinId}; +use imports::*; + +use crate::gpio::{FloatingDisabled, PA14, PA15, Pin, PinId}; use crate::time::Hertz; -use crate::typelevel::{Decrement, Increment, Sealed}; +use crate::typelevel::Sealed; -use super::dfll::DfllId; use super::{Enabled, Source}; //============================================================================== @@ -257,15 +272,29 @@ impl XoscToken { // of registers for the corresponding `XoscId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - unsafe { (*crate::pac::Oscctrl::PTR).xoscctrl(X::NUM) } + #[hal_cfg("clock-d5x")] + unsafe { + &(*Peripheral::PTR).xoscctrl(X::NUM) + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*Peripheral::PTR).xosc() + } } /// Read the STATUS register #[inline] - fn status(&self) -> oscctrl::status::R { + fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. - unsafe { (*crate::pac::Oscctrl::PTR).status().read() } + #[hal_cfg("clock-d5x")] + unsafe { + (*Peripheral::PTR).status().read() + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + (*Peripheral::PTR).pclksr().read() + } } /// Check whether the XOSC is stable and ready @@ -276,6 +305,7 @@ impl XoscToken { } /// Check whether the XOSC has triggered failure detection + #[hal_cfg("clock-d5x")] #[inline] fn has_failed(&self) -> bool { let mask = 1 << (X::NUM + 2); @@ -283,27 +313,24 @@ impl XoscToken { } /// Check whether the XOSC has been switched to the safe clock + #[hal_cfg("clock-d5x")] #[inline] fn is_switched(&self) -> bool { let mask = 1 << (X::NUM + 4); self.status().bits() & mask != 0 } - /// Reset the XOSCCTRL register - #[inline] - fn reset(&self) { - self.xoscctrl().reset(); - } - /// Switch from the safe clock back to the XOSC clock/oscillator /// /// This bit is cleared by the hardware after successfully switching back + #[hal_cfg("clock-d5x")] #[inline] fn switch_back(&mut self) { self.xoscctrl().modify(|_, w| w.swben().set_bit()); } /// Enable clock failure detection and set the safe clock divider + #[hal_cfg("clock-d5x")] #[inline] fn enable_failure_detection(&mut self, div: SafeClockDiv) { // Safety: The divider is guaranteed to be in the valid range 0..16. @@ -317,6 +344,7 @@ impl XoscToken { } /// Disable clock failure detection + #[hal_cfg("clock-d5x")] #[inline] fn disable_failure_detection(&mut self) { self.xoscctrl().modify(|_, w| w.cfden().clear_bit()); @@ -324,32 +352,35 @@ impl XoscToken { /// Set most of the fields in the XOSCCTRL register #[inline] - fn set_xoscctrl(&mut self, settings: Settings) { - let xtalen = settings.mode == DynMode::CrystalMode; + fn enable(&mut self, mode: DynMode, settings: Settings) { + let xtalen = mode == DynMode::CrystalMode; // Safety: The `IMULT` and `IPTAT` values come from the // `CrystalCurrent`, so they are guaranteed to be valid. - self.xoscctrl().modify(|_, w| unsafe { + self.xoscctrl().write(|w| unsafe { w.startup().bits(settings.start_up as u8); - w.enalc().bit(settings.loop_control); - w.imult().bits(settings.current.imult()); - w.iptat().bits(settings.current.iptat()); - w.lowbufgain().bit(settings.low_buf_gain); + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + w.ampgc().bit(settings.ampgc); + w.gain().variant(settings.gain.into()) + }; + #[hal_cfg("clock-d5x")] + { + w.enalc().bit(settings.loop_control); + w.imult().bits(settings.current.imult()); + w.iptat().bits(settings.current.iptat()); + w.lowbufgain().bit(settings.low_buf_gain); + }; w.ondemand().bit(settings.on_demand); w.runstdby().bit(settings.run_standby); - w.xtalen().bit(xtalen) + w.xtalen().bit(xtalen); + w.enable().set_bit() }); } - /// Enable the XOSC - #[inline] - fn enable(&mut self) { - self.xoscctrl().modify(|_, w| w.enable().set_bit()); - } - /// Disable the XOSC #[inline] fn disable(&mut self) { - self.xoscctrl().modify(|_, w| w.enable().clear_bit()); + self.xoscctrl().write(|w| w.enable().clear_bit()); } } @@ -362,6 +393,7 @@ impl XoscToken { // All of these fields are set in a single write to XOSCCTRL during the call to // [`Xosc::enable`]. The remaining fields are only modified after it has been // enabled. +#[hal_cfg("clock-d5x")] #[derive(Clone, Copy)] struct Settings { start_up: StartUpDelay, @@ -370,7 +402,43 @@ struct Settings { low_buf_gain: bool, on_demand: bool, run_standby: bool, - mode: DynMode, +} + +#[hal_cfg("clock-d5x")] +impl Default for Settings { + fn default() -> Self { + Settings { + start_up: StartUpDelay::default(), + loop_control: false, + current: CrystalCurrent::default(), + low_buf_gain: false, + on_demand: true, + run_standby: false, + } + } +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[derive(Clone, Copy)] +struct Settings { + start_up: StartUpDelay, + ampgc: bool, + gain: Gain, + on_demand: bool, + run_standby: bool, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl Default for Settings { + fn default() -> Self { + Settings { + start_up: StartUpDelay::default(), + ampgc: false, + gain: Gain::default(), + on_demand: true, + run_standby: false, + } + } } //============================================================================== @@ -421,10 +489,13 @@ impl XoscId for Xosc0Id { /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums +#[hal_cfg("clock-d5x")] pub enum Xosc1Id {} +#[hal_cfg("clock-d5x")] impl Sealed for Xosc1Id {} +#[hal_cfg("clock-d5x")] impl XoscId for Xosc1Id { const NUM: usize = 1; type XIn = PB22; @@ -526,6 +597,7 @@ pub enum StartUpDelay { /// each frequency range, it also acknowledges some flexibility in that choice. /// Specifically, it notes that users can save power by selecting the next-lower /// frequency range if the capacitive load is small. +#[hal_cfg("clock-d5x")] #[derive(Clone, Copy, Default, PartialEq, Eq)] pub enum CrystalCurrent { /// Used only in [`ClockMode`] to represent the default register values @@ -541,6 +613,7 @@ pub enum CrystalCurrent { ExtraHigh, } +#[hal_cfg("clock-d5x")] impl CrystalCurrent { #[inline] fn imult(&self) -> u8 { @@ -565,6 +638,34 @@ impl CrystalCurrent { } } +//============================================================================== +// Gain +//============================================================================== + +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[derive(Clone, Copy, Default, PartialEq, Eq)] +pub enum Gain { + #[default] + Zero, + One, + Two, + Three, + Four, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl From for Gainselect { + fn from(gain: Gain) -> Self { + match gain { + Gain::Zero => Gainselect::_0, + Gain::One => Gainselect::_1, + Gain::Two => Gainselect::_2, + Gain::Three => Gainselect::_3, + Gain::Four => Gainselect::_4, + } + } +} + //============================================================================== // DynMode //============================================================================== @@ -692,6 +793,7 @@ where pub type Xosc0 = Xosc; /// Type alias for the corresponding [`Xosc`] +#[hal_cfg("clock-d5x")] pub type Xosc1 = Xosc; /// An [`Enabled`] [`Xosc`] @@ -709,6 +811,7 @@ pub type EnabledXosc = Enabled, N>; pub type EnabledXosc0 = EnabledXosc; /// Type alias for the corresponding [`EnabledXosc`] +#[hal_cfg("clock-d5x")] pub type EnabledXosc1 = EnabledXosc; impl Xosc { @@ -768,6 +871,7 @@ impl Xosc { } /// Set the [`CrystalCurrent`] drive strength + #[hal_cfg("clock-d5x")] #[inline] pub fn current(mut self, current: CrystalCurrent) -> Self { self.settings.current = current; @@ -778,6 +882,7 @@ impl Xosc { /// /// If enabled, the hardware will automatically adjust the oscillator /// amplitude. In most cases, this will lower power consumption. + #[hal_cfg("clock-d5x")] #[inline] pub fn loop_control(mut self, loop_control: bool) -> Self { self.settings.loop_control = loop_control; @@ -790,11 +895,26 @@ impl Xosc { /// loop control is enabled, setting the `LOWBUFGAIN` field to `1` will /// _increase_ the oscillator amplitude by a factor of appoximately 2. This /// can help solve stability issues. + #[hal_cfg("clock-d5x")] #[inline] pub fn low_buf_gain(mut self, low_buf_gain: bool) -> Self { self.settings.low_buf_gain = low_buf_gain; self } + + #[hal_cfg(any("clock-d11", "clock-d21"))] + #[inline] + pub fn amplitude_gain_control(mut self, enabled: bool) -> Self { + self.settings.ampgc = enabled; + self + } + + #[hal_cfg(any("clock-d11", "clock-d21"))] + #[inline] + pub fn gain(mut self, gain: Gain) -> Self { + self.settings.gain = gain; + self + } } impl Xosc @@ -802,28 +922,19 @@ where X: XoscId, M: Mode, { + #[hal_cfg("clock-d5x")] #[inline] fn new(token: XoscToken, pins: M::Pins, freq: Hertz) -> Self { - let current = match freq.to_Hz() { - 8_000_000 => CrystalCurrent::Low, - 8_000_001..=16_000_000 => CrystalCurrent::Medium, - 16_000_001..=24_000_000 => CrystalCurrent::High, - 24_000_001..=48_000_000 => CrystalCurrent::ExtraHigh, - _ => panic!("The XOSC input frequency must be 8-48 MHz"), - }; - let current = match M::DYN { - DynMode::ClockMode => CrystalCurrent::Zero, - DynMode::CrystalMode => current, - }; - let settings = Settings { - start_up: StartUpDelay::Delay31us, - loop_control: false, - current, - low_buf_gain: false, - on_demand: true, - run_standby: false, - mode: M::DYN, - }; + let mut settings = Settings::default(); + if M::DYN == DynMode::CrystalMode { + settings.current = match freq.to_Hz() { + 8_000_000 => CrystalCurrent::Low, + 8_000_001..=16_000_000 => CrystalCurrent::Medium, + 16_000_001..=24_000_000 => CrystalCurrent::High, + 24_000_001..=48_000_000 => CrystalCurrent::ExtraHigh, + _ => panic!("The XOSC input frequency must be 8-48 MHz"), + }; + } Self { token, pins, @@ -832,6 +943,17 @@ where } } + #[hal_cfg(any("clock-d11", "clock-d21"))] + #[inline] + fn new(token: XoscToken, pins: M::Pins, freq: Hertz) -> Self { + Self { + token, + pins, + freq, + settings: Settings::default(), + } + } + /// Return the clock or crystal frequency #[inline] pub fn freq(&self) -> Hertz { @@ -885,9 +1007,7 @@ where /// [`Source`] for other clocks. #[inline] pub fn enable(mut self) -> EnabledXosc { - self.token.reset(); - self.token.set_xoscctrl(self.settings); - self.token.enable(); + self.token.enable(M::DYN, self.settings); Enabled::new(self) } } @@ -919,7 +1039,14 @@ where pub fn is_ready(&self) -> bool { self.0.token.is_ready() } +} +#[hal_cfg("clock-d5x")] +impl EnabledXosc +where + X: XoscId, + M: Mode, +{ /// Enable continuous monitoring of the [`Xosc`] for clock failure /// /// Failure detection will continuously monitor the [`Xosc`] to verify it is From 8c81edeb2c55a24037d0961d28e4ea6a57436868 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:45:32 +1200 Subject: [PATCH 045/114] stash 2 osculp32k --- hal/src/clock/v2/osculp32k.rs | 47 ++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index 1b4e1c30d99b..b4bc968b71ea 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -161,13 +161,25 @@ //! [`clock_system_at_reset`]: super::clock_system_at_reset //! [`Clocks`]: super::Clocks +use atsamd_hal_macros::hal_cfg; use fugit::RateExtU32; use typenum::U0; -use crate::pac::osc32kctrl::Osculp32k; +#[hal_cfg("clock-d5x")] +mod imports { + pub use crate::pac::osc32kctrl::Osculp32k; + pub use crate::typelevel::{Decrement, Increment}; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::sysctrl::Osculp32k; +} + +use imports::*; use crate::time::Hertz; -use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; +use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; use super::{Enabled, Source}; @@ -239,27 +251,38 @@ impl OscUlp32kBaseToken { // Safety: The `OscUlp32kBaseToken` has exclusive access to the // `OSCULP32K` register. See the notes on `Token` types and memory // safety in the root of the `clock` module for more details. - unsafe { (*crate::pac::Osc32kctrl::PTR).osculp32k() } + #[hal_cfg("clock-d5x")] + unsafe { + &(*crate::pac::Osc32kctrl::PTR).osculp32k() + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*crate::pac::Sysctrl::PTR).osculp32k() + } } + #[hal_cfg("clock-d5x")] /// Enable the 1 kHz output #[inline] fn enable_1k(&mut self) { self.osculp32k().modify(|_, w| w.en1k().set_bit()); } + #[hal_cfg("clock-d5x")] /// Disable the 1 kHz output #[inline] fn disable_1k(&mut self) { self.osculp32k().modify(|_, w| w.en1k().clear_bit()); } + #[hal_cfg("clock-d5x")] /// Enable the 32 kHz output #[inline] fn enable_32k(&mut self) { self.osculp32k().modify(|_, w| w.en32k().set_bit()); } + #[hal_cfg("clock-d5x")] /// Disable the 32 kHz output #[inline] fn disable_32k(&mut self) { @@ -362,6 +385,7 @@ impl Sealed for OscUlp32kId {} /// derived from the [`OscUlp32kBase`] clock. See the /// [module-level documentation](super) for details and examples. pub struct OscUlp1k { + #[allow(unused)] token: OscUlp1kToken, } @@ -377,9 +401,16 @@ pub struct OscUlp1k { pub type EnabledOscUlp1k = Enabled; impl OscUlp1k { + #[hal_cfg(any("clock-d11", "clock-d21"))] + pub(super) unsafe fn new() -> Self { + let token = OscUlp1kToken(()); + Self { token } + } + /// Enable 1 kHz output from the [`OscUlp32kBase`] clock /// /// This will [`Increment`] the [`EnabledOscUlp32kBase`] counter. + #[hal_cfg("clock-d5x")] #[inline] pub fn enable( token: OscUlp1kToken, @@ -394,6 +425,7 @@ impl EnabledOscUlp1k { /// Disable 1 kHz output from the [`OscUlp32kBase`] clock /// /// This will [`Decrement`] the [`EnabledOscUlp32kBase`] counter. + #[hal_cfg("clock-d5x")] #[inline] pub fn disable( self, @@ -425,6 +457,7 @@ impl Source for EnabledOscUlp1k { /// derived from the [`OscUlp32kBase`] clock. See the /// [module-level documentation](super) for details and examples. pub struct OscUlp32k { + #[allow(unused)] token: OscUlp32kToken, } @@ -440,9 +473,16 @@ pub struct OscUlp32k { pub type EnabledOscUlp32k = Enabled; impl OscUlp32k { + #[hal_cfg(any("clock-d11", "clock-d21"))] + pub(super) unsafe fn new() -> Self { + let token = OscUlp32kToken(()); + Self { token } + } + /// Enable 32 kHz output from the [`OscUlp32kBase`] clock /// /// This will [`Increment`] the [`EnabledOscUlp32kBase`] counter. + #[hal_cfg("clock-d5x")] #[inline] pub fn enable( token: OscUlp32kToken, @@ -457,6 +497,7 @@ impl EnabledOscUlp32k { /// Disable 32 kHz output from the [`OscUlp32kBase`] clock /// /// This will [`Decrement`] the [`EnabledOscUlp32kBase`] counter. + #[hal_cfg("clock-d5x")] #[inline] pub fn disable( self, From 1fce97fec9be947d6483f46ee22e09a6155f54b5 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:29:23 +1200 Subject: [PATCH 046/114] stash 2 reset --- hal/src/clock/v2/reset.rs | 101 +++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/hal/src/clock/v2/reset.rs b/hal/src/clock/v2/reset.rs index dda29b0e6479..3736da7bbf99 100644 --- a/hal/src/clock/v2/reset.rs +++ b/hal/src/clock/v2/reset.rs @@ -2,6 +2,7 @@ //! from the `v2` module, which is where the corresponding documentation will //! appear. +use atsamd_hal_macros::hal_cfg; use typenum::U1; use crate::pac::{Gclk, Mclk, Nvmctrl, Osc32kctrl, Oscctrl}; @@ -57,6 +58,18 @@ pub struct Buses { pub apb: apb::Apb, } +#[hal_cfg("clock-d5x")] +pub struct OscUlp32kClocks { + base: osculp32k::EnabledOscUlp32kBase, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +pub struct OscUlp32kClocks { + base: osculp32k::EnabledOscUlp32kBase, + osculp1k: EnabledOscUlp1k, + osculp32k: EnabledOscUlp32k, +} + /// Enabled clocks at power-on reset /// /// This type is constructed using the [`clock_system_at_reset`] function, which @@ -88,7 +101,7 @@ pub struct Clocks { pub dfll: Enabled, /// Always-enabled base oscillator for the [`OscUlp1k`](osculp32k::OscUlp1k) /// and [`OscUlp32k`](osculp32k::OscUlp32k) clocks. - pub osculp32k_base: Enabled, + pub osculp32k: OscUlp32kClocks, } /// Type-level tokens for unused clocks at power-on reset @@ -100,6 +113,7 @@ pub struct Clocks { /// As described in the [top-level](super::super) documentation for the `clock` /// module, token types are used to guanrantee the uniqueness of each clock. To /// configure or enable a clock, you must provide the corresponding token. +#[hal_cfg("clock-d5x")] pub struct Tokens { /// Tokens to create [`apb::ApbClk`]s pub apbs: apb::ApbTokens, @@ -124,6 +138,29 @@ pub struct Tokens { pub osculp32k: osculp32k::OscUlp32kTokens, } +#[hal_cfg(any("clock-d11", "clock-d21"))] +pub struct Tokens { + /// Tokens to create [`apb::ApbClk`]s + pub apbs: apb::ApbTokens, + /// Token to create [`dpll::Dpll0`] + pub dpll0: dpll::DpllToken, + /// Token to create [`dpll::Dpll1`] + pub dpll1: dpll::DpllToken, + /// Tokens to create [`gclk::Gclk`] + pub gclks: gclk::GclkTokens, + /// Tokens to create [`pclk::Pclk`]s + pub pclks: pclk::PclkTokens, + /// Tokens to create [`rtcosc::RtcOsc`] + pub rtcosc: rtcosc::RtcOscToken, + /// Tokens [`xosc::Xosc0`] + pub xosc0: xosc::XoscToken, + /// Token to create [`xosc::Xosc1`] + pub xosc1: xosc::XoscToken, + /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and + /// [`xosc32k::Xosc32k`] + pub xosc32k: xosc32k::Xosc32kTokens, +} + /// Consume the PAC clocking structs and return a HAL-level /// representation of the clocks at power-on reset /// @@ -131,6 +168,7 @@ pub struct Tokens { /// [`Mclk`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`]. /// /// See the [module-level documentation](super) for more details. +#[hal_cfg("clock-d5x")] #[inline] pub fn clock_system_at_reset( oscctrl: Oscctrl, @@ -154,13 +192,18 @@ pub fn clock_system_at_reset( let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new())); let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll); let gclk0 = Enabled::new(gclk0); + let osculp32k_clocks = { + OscUlp32kClocks { + base: osculp32k::OscUlp32kBase::new(), + } + }; let clocks = Clocks { pac, ahbs: ahb::AhbClks::new(), apbs: apb::ApbClks::new(), gclk0, dfll, - osculp32k_base: osculp32k::OscUlp32kBase::new(), + osculp32k: osculp32k_clocks, }; let tokens = Tokens { apbs: apb::ApbTokens::new(), @@ -177,3 +220,57 @@ pub fn clock_system_at_reset( (buses, clocks, tokens) } } + +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[inline] +pub fn clock_system_at_reset( + oscctrl: Oscctrl, + osc32kctrl: Osc32kctrl, + gclk: Gclk, + mclk: Mclk, + nvmctrl: &mut Nvmctrl, +) -> (Buses, Clocks, Tokens) { + // Safety: No bus, clock or token is instantiated more than once + unsafe { + let buses = Buses { + ahb: ahb::Ahb::new(), + apb: apb::Apb::new(), + }; + let pac = Pac { + oscctrl, + osc32kctrl, + gclk, + mclk, + }; + let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new())); + let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll); + let gclk0 = Enabled::new(gclk0); + let osculp32k_clocks = { + OscUlp32kClocks { + base: osculp32k::OscUlp32kBase::new(), + osculp1k: Enabled::new(osculp32k::OscUlp1k::new()), + osculp32k: Enabled::new(osculp32k::OscUlp32k::new()), + } + }; + let clocks = Clocks { + pac, + ahbs: ahb::AhbClks::new(), + apbs: apb::ApbClks::new(), + gclk0, + dfll, + osculp32k: osculp32k_clocks, + }; + let tokens = Tokens { + apbs: apb::ApbTokens::new(), + dpll0: dpll::DpllToken::new(), + dpll1: dpll::DpllToken::new(), + gclks: gclk::GclkTokens::new(nvmctrl), + pclks: pclk::PclkTokens::new(), + rtcosc: rtcosc::RtcOscToken::new(), + xosc0: xosc::XoscToken::new(), + xosc1: xosc::XoscToken::new(), + xosc32k: xosc32k::Xosc32kTokens::new(), + }; + (buses, clocks, tokens) + } +} From 28afdb3b5824e02317a7033bf940f208f0f52368 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 15:00:05 +1200 Subject: [PATCH 047/114] TODO squash warnings --- hal/src/clock/v2/reset.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/src/clock/v2/reset.rs b/hal/src/clock/v2/reset.rs index 3736da7bbf99..6cc535a263a7 100644 --- a/hal/src/clock/v2/reset.rs +++ b/hal/src/clock/v2/reset.rs @@ -59,11 +59,13 @@ pub struct Buses { } #[hal_cfg("clock-d5x")] +#[allow(dead_code)] pub struct OscUlp32kClocks { base: osculp32k::EnabledOscUlp32kBase, } #[hal_cfg(any("clock-d11", "clock-d21"))] +#[allow(dead_code)] pub struct OscUlp32kClocks { base: osculp32k::EnabledOscUlp32kBase, osculp1k: EnabledOscUlp1k, From 2f3e8161a957faee7ed287c2c293b4ac12c56480 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:32:11 +1200 Subject: [PATCH 048/114] stash 2 pclk --- hal/src/clock/v2/pclk.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 59f644b2f91c..205f06fc1685 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -71,15 +71,19 @@ use seq_macro::seq; use crate::pac; -#[hal_cfg(any("clock-d11", "clock-d21"))] -use crate::pac::gclk::clkctrl::Genselect; #[hal_cfg("clock-d5x")] -use crate::pac::gclk::pchctrl::Genselect; +mod imports { + pub use crate::pac::gclk::Pchctrl as Ctrl; + pub use crate::pac::gclk::pchctrl::Genselect; +} #[hal_cfg(any("clock-d11", "clock-d21"))] -use crate::pac::gclk::Clkctrl as Ctrl; -#[hal_cfg("clock-d5x")] -use crate::pac::gclk::Pchctrl as Ctrl; +mod imports { + pub use crate::pac::gclk::Clkctrl as Ctrl; + pub use crate::pac::gclk::clkctrl::Genselect; +} + +use imports::*; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; @@ -133,7 +137,7 @@ impl PclkToken

{ } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*pac::Gclk::PTR).clkctrl + &(*pac::Gclk::PTR).clkctrl() } } @@ -191,8 +195,6 @@ pub mod ids { pub use crate::sercom::Sercom7; pub use super::super::dfll::DfllId; - //pub struct DfllId; - //impl crate::typelevel::Sealed for DfllId {} #[hal_cfg("clock-d5x")] pub use super::super::dpll::{Dpll0Id, Dpll1Id}; From 1f272cf4a4affe52eca5950813d42f7933161e2e Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:46:27 +1200 Subject: [PATCH 049/114] stash 2 gclk --- hal/src/clock/v2/gclk.rs | 55 +++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 585caeb0b6a9..01d45f60f903 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -356,9 +356,11 @@ use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, use super::dfll::DfllId; // use super::dpll::{Dpll0Id, Dpll1Id}; -// use super::osculp32k::OscUlp32kId; -// use super::xosc::{Xosc0Id, Xosc1Id}; -// use super::xosc32k::Xosc32kId; +use super::osculp32k::OscUlp32kId; +use super::xosc::Xosc0Id; +#[hal_cfg("clock-d5x")] +use super::xosc::Xosc1Id; +use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; //============================================================================== @@ -412,14 +414,14 @@ impl GclkToken { } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*pac::Gclk::PTR).genctrl + &(*pac::Gclk::PTR).genctrl() } } #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] fn gendiv(&self) -> &Gendiv { - unsafe { &(*pac::Gclk::PTR).gendiv } + unsafe { &(*pac::Gclk::PTR).gendiv() } } /// Block until synchronization has completed @@ -438,7 +440,7 @@ impl GclkToken { } #[hal_cfg(any("clock-d11", "clock-d21"))] { - let status = unsafe { &(*pac::Gclk::PTR).status }; + let status = unsafe { &(*pac::Gclk::PTR).status() }; while status.read().syncbusy().bit() {} } } @@ -994,30 +996,31 @@ impl GclkSourceId for DfllId { // const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; // type Resource = (); //} -//impl GclkSourceId for Gclk1Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; -// type Resource = (); -//} +impl GclkSourceId for Gclk1Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; + type Resource = (); +} impl GclkSourceId for I { const DYN: DynGclkSourceId = DynGclkSourceId::GclkIn; type Resource = Pin; } -//impl GclkSourceId for OscUlp32kId { -// const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; -// type Resource = (); -//} -//impl GclkSourceId for Xosc0Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; -// type Resource = (); -//} -//impl GclkSourceId for Xosc1Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; -// type Resource = (); -//} -//impl GclkSourceId for Xosc32kId { -// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; -// type Resource = (); -//} +impl GclkSourceId for OscUlp32kId { + const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; + type Resource = (); +} +impl GclkSourceId for Xosc0Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; + type Resource = (); +} +#[hal_cfg("clock-d5x")] +impl GclkSourceId for Xosc1Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; + type Resource = (); +} +impl GclkSourceId for Xosc32kId { + const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; + type Resource = (); +} //============================================================================== // NotGclkIo From 1d5948df47bcaa8043c67804ecba2946d29bb872 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:49:59 +1200 Subject: [PATCH 050/114] stash 2 dpll --- hal/src/clock/v2/dpll.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 7f20db8a820c..ce58ff12fa3f 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -237,22 +237,38 @@ //! [`GclkDivider`]: super::gclk::GclkDivider //! [`Pclk`]: super::pclk::Pclk +use atsamd_hal_macros::hal_cfg; use core::marker::PhantomData; use fugit::RateExtU32; use typenum::U0; -use crate::pac::oscctrl; -use crate::pac::oscctrl::dpll::{Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus, dpllsyncbusy}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use super::super::xosc::Xosc1Id; + pub use crate::pac::oscctrl::{ + Dpll as PacDpll, + dpll::dpllctrlb::Refclkselect, + dpll::{Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus, dpllsyncbusy}, + }; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::sysctrl::{ + dpllctrlb::Refclkselect, + {Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus}, + }; +} -use crate::pac::oscctrl::dpll::dpllctrlb::Refclkselect; +use imports::*; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; use super::gclk::GclkId; use super::pclk::{Pclk, PclkId}; -use super::xosc::{Xosc0Id, Xosc1Id, XoscId}; +use super::xosc::{Xosc0Id, XoscId}; use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -292,7 +308,7 @@ impl DpllToken { /// Access the corresponding PAC `DPLL` struct #[inline] - fn dpll(&self) -> &oscctrl::Dpll { + fn dpll(&self) -> &PacDpll { // Safety: Each `DpllToken` only has access to a mutually exclusive set // of registers for the corresponding `DpllId`, and we use a shared // reference to the register block. See the notes on `Token` types and From 848a4514a5ee664605f2b4a40c7b3f36d4146064 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:53:30 +1200 Subject: [PATCH 051/114] stash 2 dfll --- hal/src/clock/v2/dfll.rs | 104 +++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 20 deletions(-) diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index 58cbceef6af7..f10f725922e4 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -272,7 +272,22 @@ //! [`from_usb`]: Dfll::from_usb //! [`into_mode`]: EnabledDfll::into_mode +use atsamd_hal_macros::hal_cfg; + +#[hal_cfg("clock-d5x")] +mod imports { + pub use crate::pac::oscctrl::{ + Dfllctrla as Dfllctrl, Dfllctrlb, Dfllmul, Dfllsync, RegisterBlock, + }; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::sysctrl::{Dfllctrl, Dfllmul, Dfllsync, RegisterBlock}; +} + use fugit::RateExtU32; +use imports::*; use typenum::U0; use crate::time::Hertz; @@ -309,51 +324,71 @@ impl DfllToken { } #[inline] - fn oscctrl(&self) -> &crate::pac::oscctrl::RegisterBlock { + fn reg_block(&self) -> &RegisterBlock { // Safety: The `DfllToken` only has access to a mutually exclusive set // of registers for the DFLL, and we use a shared reference to the // register block. See the notes on `Token` types and memory safety in // the root of the `clock` module for more details. - unsafe { &*crate::pac::Oscctrl::PTR } + #[hal_cfg("clock-d5x")] + unsafe { + &*crate::pac::Oscctrl::PTR + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &*crate::pac::Sysctrl::PTR + } } + #[hal_cfg("clock-d5x")] #[inline] - fn dfllctrla(&self) -> &crate::pac::oscctrl::Dfllctrla { - self.oscctrl().dfllctrla() + fn dfllctrl(&self) -> &Dfllctrl { + &self.reg_block().dfllctrla() } + #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] - fn dfllctrlb(&self) -> &crate::pac::oscctrl::Dfllctrlb { - self.oscctrl().dfllctrlb() + fn dfllctrl(&self) -> &Dfllctrl { + &self.reg_block().dfllctrl() } + #[hal_cfg("clock-d5x")] #[inline] - fn dfllmul(&self) -> &crate::pac::oscctrl::Dfllmul { - self.oscctrl().dfllmul() + fn dfllctrlb(&self) -> &Dfllctrlb { + self.reg_block().dfllctrlb() } #[inline] - fn dfllsync(&self) -> &crate::pac::oscctrl::Dfllsync { - self.oscctrl().dfllsync() + fn dfllmul(&self) -> &Dfllmul { + &self.reg_block().dfllmul() } + #[hal_cfg("clock-d5x")] + #[inline] + fn dfllsync(&self) -> &Dfllsync { + &self.reg_block().dfllsync() + } + + #[hal_cfg("clock-d5x")] #[inline] fn wait_sync_enable(&self) { while self.dfllsync().read().enable().bit() {} } + #[hal_cfg("clock-d5x")] #[inline] fn wait_sync_dfllmul(&self) { while self.dfllsync().read().dfllmul().bit() {} } + #[hal_cfg("clock-d5x")] #[inline] fn wait_sync_dfllctrlb(&self) { while self.dfllsync().read().dfllctrlb().bit() {} } + #[hal_cfg("clock-d5x")] #[inline] - fn configure(&mut self, settings: settings::All) { + fn enable(&mut self, settings: settings::All) { self.dfllctrlb().modify(|_, w| { w.mode().bit(settings.closed_loop); w.usbcrm().bit(settings.usb_recovery); @@ -371,27 +406,54 @@ impl DfllToken { }); self.wait_sync_dfllmul(); } - self.dfllctrla().modify(|_, w| { + self.dfllctrl().modify(|_, w| { w.runstdby().bit(settings.run_standby); - w.ondemand().bit(settings.on_demand) + w.ondemand().bit(settings.on_demand); + w.enable().set_bit() }); + self.wait_sync_enable(); } + #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] - fn enable(&mut self) { - self.dfllctrla().modify(|_, w| w.enable().set_bit()); - self.wait_sync_enable(); + fn enable(&mut self, settings: settings::All) { + if settings.closed_loop { + self.dfllmul().write(|w| + // Safety: All bit patterns are valid for these fields + unsafe { + w.mul().bits(settings.mult_factor); + w.cstep().bits(settings.coarse_max_step); + w.fstep().bits(settings.fine_max_step) + }); + } + self.dfllctrl().write(|w| { + w.mode().bit(settings.closed_loop); + w.usbcrm().bit(settings.usb_recovery); + w.ccdis().bit(!settings.chill_cycle); + w.qldis().bit(!settings.quick_lock); + w.runstdby().bit(settings.run_standby); + w.ondemand().bit(settings.on_demand); + w.enable().set_bit() + }); } #[inline] fn disable(&mut self) { - self.dfllctrla().modify(|_, w| w.enable().clear_bit()); + self.dfllctrl().write(|w| w.enable().clear_bit()); + #[hal_cfg("clock-d5x")] self.wait_sync_enable(); } + #[hal_cfg("clock-d5x")] + #[inline] + fn is_ready(&self) -> bool { + self.reg_block().status().read().dfllrdy().bit() + } + + #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] fn is_ready(&self) -> bool { - self.oscctrl().status().read().dfllrdy().bit() + self.reg_block().pclksr().read().dfllrdy().bit() } } @@ -401,7 +463,10 @@ impl DfllToken { type MultFactor = u16; type CoarseMaxStep = u8; +#[hal_cfg("clock-d5x")] type FineMaxStep = u8; +#[hal_cfg(any("clock-d11", "clock-d21"))] +type FineMaxStep = u16; //============================================================================== // DfllId @@ -1122,8 +1187,7 @@ impl Dfll { /// [`Source`] for other clocks. #[inline] pub fn enable(mut self) -> EnabledDfll { - self.token.configure(self.settings.all()); - self.token.enable(); + self.token.enable(self.settings.all()); Enabled::new(self) } } From c110413a622e651c9afa9d92d72f066bd4754762 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 16:06:28 +1200 Subject: [PATCH 052/114] Only enable RTC for D5x --- hal/src/clock/v2.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index c815762c2298..1afc58c8ed8f 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -854,6 +854,8 @@ #![allow(clippy::manual_range_contains)] +use atsamd_hal_macros::hal_module; + use typenum::U0; use crate::time::Hertz; @@ -866,7 +868,10 @@ pub mod dpll; pub mod gclk; pub mod osculp32k; pub mod pclk; -pub mod rtcosc; +#[hal_module( + "clock-d5x" => "v2/rtcosc.rs", +)] +pub mod rtcosc {} pub mod types; pub mod xosc; pub mod xosc32k; From 82b73ebec064105e04250beb2bf50eef7acf1fc4 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:54:34 +1200 Subject: [PATCH 053/114] WIP stash 2 enable v2 for thumbv6m --- hal/src/clock.rs | 3 +-- hal/src/clock/v2.rs | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hal/src/clock.rs b/hal/src/clock.rs index 830b82b36470..df8cc9e27495 100644 --- a/hal/src/clock.rs +++ b/hal/src/clock.rs @@ -2,7 +2,7 @@ //! //! Users are encouraged to use [`v2`] variant of an API because of the richer //! feature set and safety. -use atsamd_hal_macros::{hal_cfg, hal_module}; +use atsamd_hal_macros::hal_module; #[hal_module( any("clock-d11", "clock-d21") => "clock/v1_thumbv6m.rs", @@ -12,5 +12,4 @@ pub mod v1 {} pub use v1::*; -#[hal_cfg("clock-d5x")] pub mod v2; diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 1afc58c8ed8f..da718a4aca46 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -861,10 +861,10 @@ use typenum::U0; use crate::time::Hertz; use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; -pub mod ahb; -pub mod apb; +// pub mod ahb; +// pub mod apb; pub mod dfll; -pub mod dpll; +// pub mod dpll; pub mod gclk; pub mod osculp32k; pub mod pclk; @@ -876,8 +876,8 @@ pub mod types; pub mod xosc; pub mod xosc32k; -mod reset; -pub use reset::*; +// mod reset; +// pub use reset::*; // `Token` types and memory safety // From f0bf86eb52f947fa05dd850e65e058cc7c73efa0 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 11:18:30 +1200 Subject: [PATCH 054/114] stash 3 ahb --- hal/src/clock/v2.rs | 2 +- hal/src/clock/v2/ahb.rs | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index da718a4aca46..aaaa7645326a 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -861,7 +861,7 @@ use typenum::U0; use crate::time::Hertz; use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; -// pub mod ahb; +pub mod ahb; // pub mod apb; pub mod dfll; // pub mod dpll; diff --git a/hal/src/clock/v2/ahb.rs b/hal/src/clock/v2/ahb.rs index 75b7ee27bd14..abf0e988b612 100644 --- a/hal/src/clock/v2/ahb.rs +++ b/hal/src/clock/v2/ahb.rs @@ -122,14 +122,24 @@ //! [`Clocks`]: super::Clocks //! [`Buses`]: super::Buses -use atsamd_hal_macros::hal_macro_helper; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use bitflags; use paste::paste; -use crate::pac::{Mclk, mclk}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use crate::pac::{Mclk as Peripheral, mclk::Ahbmask}; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::{Pm as Peripheral, pm::Ahbmask}; +} + +use imports::*; use super::types::*; @@ -160,11 +170,11 @@ impl Ahb { } #[inline] - fn ahbmask(&mut self) -> &mclk::Ahbmask { + fn ahbmask(&mut self) -> &Ahbmask { // Safety: The `Ahb` type has exclusive access to the `AHBMASK` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { (*Mclk::PTR).ahbmask() } + unsafe { (*Peripheral::PTR).ahbmask() } } #[inline] From 283a2b15c18a4ae4e0fa54241fdccd5e3782b9b0 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:09:41 +1200 Subject: [PATCH 055/114] Rename Pac -> Pac0 --- hal/src/clock/v2/ahb.rs | 2 +- hal/src/clock/v2/types.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/clock/v2/ahb.rs b/hal/src/clock/v2/ahb.rs index abf0e988b612..a860445e4ba9 100644 --- a/hal/src/clock/v2/ahb.rs +++ b/hal/src/clock/v2/ahb.rs @@ -393,7 +393,7 @@ define_ahb_types!( Cmcc = 8, Dmac = 9, Usb = 10, - Pac = 12, + Pac0 = 12, Qspi = 13, #[hal_cfg("gmac")] Gmac = 14, diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index 88bfc43ee225..96afd9f85db2 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -95,7 +95,7 @@ create_types!(NvmCtrl, NvmCtrlSmeeProm, NvmCtrlCache); create_types!(I2S, I2S0, I2S1); create_types!(OscCtrl); create_types!(Osc32kCtrl); -create_types!(Pac); +create_types!(Pac0); create_types!(Pcc); create_types!(PDec); create_types!(Pm); From feb90c2de67327924e28f805903a0edda1253d75 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 12:00:53 +1200 Subject: [PATCH 056/114] stash 3 pclk --- hal/src/clock/v2/pclk.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 205f06fc1685..6d08067957d0 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -195,8 +195,9 @@ pub mod ids { pub use crate::sercom::Sercom7; pub use super::super::dfll::DfllId; + pub use super::super::dpll::Dpll0Id; #[hal_cfg("clock-d5x")] - pub use super::super::dpll::{Dpll0Id, Dpll1Id}; + pub use super::super::dpll::Dpll1Id; pub use super::super::types::{ Ac, Adc0, Adc1, CM4Trace, Ccl, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, @@ -261,7 +262,6 @@ macro_rules! with_pclk_types_ids { $some_macro!( $( $args )* (DfllId = 0, dfll) - #[hal_cfg("clock-d5x")] (Dpll0Id = 1, dpll0) #[hal_cfg("clock-d5x")] (Dpll1Id = 2, dpll1) From c9582aa53c0bdae974faf7281ae86f8308f1bf57 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 10:58:40 +1200 Subject: [PATCH 057/114] stash 3 dpll --- hal/src/clock/v2.rs | 2 +- hal/src/clock/v2/dpll.rs | 87 ++++++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index aaaa7645326a..22ee6790e522 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -864,7 +864,7 @@ use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; pub mod ahb; // pub mod apb; pub mod dfll; -// pub mod dpll; +pub mod dpll; pub mod gclk; pub mod osculp32k; pub mod pclk; diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index ce58ff12fa3f..1e2fb265a88a 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -246,6 +246,7 @@ use typenum::U0; #[hal_cfg("clock-d5x")] mod imports { pub use super::super::xosc::Xosc1Id; + pub use crate::pac::Oscctrl as Peripheral; pub use crate::pac::oscctrl::{ Dpll as PacDpll, dpll::dpllctrlb::Refclkselect, @@ -255,7 +256,9 @@ mod imports { #[hal_cfg(any("clock-d11", "clock-d21"))] mod imports { + pub use crate::pac::Sysctrl as Peripheral; pub use crate::pac::sysctrl::{ + RegisterBlock as PacDpll, dpllctrlb::Refclkselect, {Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus}, }; @@ -313,7 +316,14 @@ impl DpllToken { // of registers for the corresponding `DpllId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - unsafe { (*crate::pac::Oscctrl::PTR).dpll(D::NUM) } + #[hal_cfg("clock-d5x")] + unsafe { + &(*Peripheral::PTR).dpll(D::NUM) + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*Peripheral::PTR) + } } /// Access the corresponding Dpllctrla register @@ -334,6 +344,7 @@ impl DpllToken { self.dpll().dpllratio() } + #[hal_cfg("clock-d5x")] /// Access the corresponding DPLLSYNCBUSY register for reading only #[inline] fn syncbusy(&self) -> dpllsyncbusy::R { @@ -347,13 +358,22 @@ impl DpllToken { } #[inline] - fn configure(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) { + fn enable(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) { // Convert the actual predivider to the `div` register field value + #[hal_cfg("clock-d5x")] + let div = match id { + DynDpllSourceId::Xosc0 => prediv / 2 - 1, + DynDpllSourceId::Xosc1 => prediv / 2 - 1, + _ => 0, + }; + + #[hal_cfg(any("clock-d11", "clock-d21"))] let div = match id { - DynDpllSourceId::Xosc0 | DynDpllSourceId::Xosc1 => prediv / 2 - 1, + DynDpllSourceId::Xosc0 => prediv / 2 - 1, _ => 0, }; - self.ctrlb().modify(|_, w| { + + self.ctrlb().write(|w| { // Safety: The value is masked to the correct bit width by the PAC. // An invalid value could produce an invalid clock frequency, but // that does not break memory safety. @@ -378,25 +398,37 @@ impl DpllToken { w.ldr().bits(settings.mult - 1); w.ldrfrac().bits(settings.frac) }); + #[hal_cfg("clock-d5x")] while self.syncbusy().dpllratio().bit_is_set() {} self.ctrla().modify(|_, w| { w.ondemand().bit(settings.on_demand); - w.runstdby().bit(settings.run_standby) + w.runstdby().bit(settings.run_standby); + w.enable().set_bit() }); + self.wait_enabled(); + } + + /// Disable the [`Dpll`] + #[inline] + fn disable(&mut self) { + self.ctrla().modify(|_, w| w.enable().clear_bit()); + self.wait_disabled(); } - /// Enable the [`Dpll`] #[inline] - fn enable(&mut self) { - self.ctrla().modify(|_, w| w.enable().set_bit()); + fn wait_enabled(&self) { + #[hal_cfg("clock-d5x")] while self.syncbusy().enable().bit_is_set() {} + #[hal_cfg(any("clock-d11", "clock-d21"))] + while self.status().enable().bit_is_clear() {} } - /// Disable the [`Dpll`] #[inline] - fn disable(&mut self) { - self.ctrla().modify(|_, w| w.enable().clear_bit()); + fn wait_disabled(&self) { + #[hal_cfg("clock-d5x")] while self.syncbusy().enable().bit_is_set() {} + #[hal_cfg(any("clock-d11", "clock-d21"))] + while self.status().enable().bit_is_set() {} } /// Check the STATUS register to see if the clock is locked @@ -473,10 +505,13 @@ impl DpllId for Dpll0Id { /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums +#[hal_cfg("clock-d5x")] pub enum Dpll1Id {} +#[hal_cfg("clock-d5x")] impl Sealed for Dpll1Id {} +#[hal_cfg("clock-d5x")] impl DpllId for Dpll1Id { const DYN: DynDpllId = DynDpllId::Dpll1; const NUM: usize = 1; @@ -492,6 +527,7 @@ impl DpllId for Dpll1Id { /// a given [`Dpll`]. /// /// `DynDpllSourceId` is the value-level equivalent of [`DpllSourceId`]. +#[hal_cfg("clock-d5x")] #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DynDpllSourceId { /// The DPLL is driven by a [`Pclk`] @@ -504,6 +540,7 @@ pub enum DynDpllSourceId { Xosc32k, } +#[hal_cfg("clock-d5x")] impl From for Refclkselect { fn from(source: DynDpllSourceId) -> Self { match source { @@ -515,6 +552,28 @@ impl From for Refclkselect { } } +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum DynDpllSourceId { + /// The DPLL is driven by a [`Pclk`] + Pclk, + /// The DPLL is driven by [`Xosc0`](super::xosc::Xosc0) + Xosc0, + /// The DPLL is driven by [`Xosc32k`](super::xosc32k::Xosc32k) + Xosc32k, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl From for Refclkselect { + fn from(source: DynDpllSourceId) -> Self { + match source { + DynDpllSourceId::Pclk => Refclkselect::Gclk, + DynDpllSourceId::Xosc0 => Refclkselect::Ref1, + DynDpllSourceId::Xosc32k => Refclkselect::Ref0, + } + } +} + //============================================================================== // DpllSourceId //============================================================================== @@ -549,6 +608,7 @@ impl DpllSourceId for Xosc0Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc0; type Reference = settings::Xosc; } +#[hal_cfg("clock-d5x")] impl DpllSourceId for Xosc1Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc1; type Reference = settings::Xosc; @@ -749,6 +809,7 @@ where pub type Dpll0 = Dpll; /// Type alias for the corresponding [`Dpll`] +#[hal_cfg("clock-d5x")] pub type Dpll1 = Dpll; impl Dpll @@ -1065,8 +1126,7 @@ where pub fn enable_unchecked(mut self) -> EnabledDpll { use settings::Reference; let prediv = self.reference.prediv(); - self.token.configure(I::DYN, self.settings, prediv); - self.token.enable(); + self.token.enable(I::DYN, self.settings, prediv); Enabled::new(self) } } @@ -1090,6 +1150,7 @@ pub type EnabledDpll = Enabled, N>; pub type EnabledDpll0 = EnabledDpll; /// Type alias for the corresponding [`EnabledDpll`] +#[hal_cfg("clock-d5x")] pub type EnabledDpll1 = EnabledDpll; impl EnabledDpll From 1711accb26a40d093d22ac3fe1e03211745688c2 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 12:08:28 +1200 Subject: [PATCH 058/114] TODO Hacky disable of DPLL DCO for thumbv6m The smaller chips use a simpler digital phase-locked oop, which doesn't support the DCO filter options that the larger chips do. --- hal/src/clock/v2/dpll.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 1e2fb265a88a..ba8b886b86e3 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -381,6 +381,7 @@ impl DpllToken { w.refclk().variant(id.into()); w.lbypass().bit(settings.lock_bypass); w.wuf().bit(settings.wake_up_fast); + #[hal_cfg("clock-d5x")] if let Some(cap) = settings.dco_filter { w.dcoen().bit(true); unsafe { From 53495503f588f9c45eef5a6c4127bd67b343f10d Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:13:01 +1200 Subject: [PATCH 059/114] stash 3 apb - needs types first --- hal/src/clock/v2.rs | 2 +- hal/src/clock/v2/apb.rs | 122 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 112 insertions(+), 12 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 22ee6790e522..6eb5585c6880 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -862,7 +862,7 @@ use crate::time::Hertz; use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; pub mod ahb; -// pub mod apb; +pub mod apb; pub mod dfll; pub mod dpll; pub mod gclk; diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 57944682144e..08b28797b0f5 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -121,13 +121,25 @@ //! [`Clocks`]: super::Clocks //! [`Buses`]: super::Buses -use atsamd_hal_macros::hal_macro_helper; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use bitflags; use paste::paste; -use crate::pac::{self, mclk}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use crate::pac::mclk::{RegisterBlock as BLOCK, Apbamask, Apbbmask, Apbcmask, Apbdmask}; + pub use crate::pac::Mclk as Peripheral; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::pm::{RegisterBlock as BLOCK, Apbamask, Apbbmask, Apbcmask}; + pub use crate::pac::Pm as Peripheral; +} + +use imports::*; use crate::typelevel::Sealed; @@ -160,35 +172,37 @@ impl Apb { } #[inline] - fn mclk(&self) -> &mclk::RegisterBlock { + fn mclk(&self) -> &BLOCK { // Safety: The `Apb` type has exclusive access to the `APBXMASK` // registers, and it uses a shared reference to the register block. See // the notes on `Token` types and memory safety in the root of the // `clock` module for more details. - unsafe { &*pac::Mclk::PTR } + unsafe { &*Peripheral::PTR } } #[inline] - fn apbamask(&mut self) -> &mclk::Apbamask { + fn apbamask(&mut self) -> &Apbamask { self.mclk().apbamask() } #[inline] - fn apbbmask(&mut self) -> &mclk::Apbbmask { + fn apbbmask(&mut self) -> &Apbbmask { self.mclk().apbbmask() } #[inline] - fn apbcmask(&mut self) -> &mclk::Apbcmask { + fn apbcmask(&mut self) -> &Apbcmask { self.mclk().apbcmask() } #[inline] - fn apbdmask(&mut self) -> &mclk::Apbdmask { - self.mclk().apbdmask() + #[hal_cfg("clock-d5x")] + fn apbdmask(&mut self) -> &Apbdmask { + &self.mclk().apbdmask() } #[inline] + #[hal_macro_helper] fn enable_mask(&mut self, mask: ApbMask) { // Safety: The mask bits are derived from a `bitflags` struct, so they // are guaranteed to be valid. @@ -206,6 +220,7 @@ impl Apb { self.apbcmask() .modify(|r, w| w.bits(r.bits() | mask.bits())); } + #[hal_cfg("clock-d5x")] ApbMask::D(mask) => { self.apbdmask() .modify(|r, w| w.bits(r.bits() | mask.bits())); @@ -215,6 +230,7 @@ impl Apb { } #[inline] + #[hal_macro_helper] fn disable_mask(&mut self, mask: ApbMask) { // Safety: The mask bits are derived from a `bitflags` struct, so they // are guaranteed to be valid. @@ -232,6 +248,7 @@ impl Apb { self.apbcmask() .modify(|r, w| w.bits(r.bits() & !mask.bits())); } + #[hal_cfg("clock-d5x")] ApbMask::D(mask) => { self.apbdmask() .modify(|r, w| w.bits(r.bits() & !mask.bits())); @@ -270,10 +287,12 @@ impl Apb { /// /// Each variant is a [`bitflags`] struct with a binary representation exactly /// matching the corresponding APB `MASK` register. +#[hal_macro_helper] enum ApbMask { A(ApbAMask), B(ApbBMask), C(ApbCMask), + #[hal_cfg("clock-d5x")] D(ApbDMask), } @@ -353,9 +372,10 @@ macro_rules! define_apb_types { } #[hal_macro_helper] +#[hal_cfg("clock-d5x")] define_apb_types!( A { - Pac = 0, + Pac0 = 0, Pm = 1, Mclk = 2, RstC = 3, @@ -426,6 +446,52 @@ define_apb_types!( } ); +#[hal_cfg(any("clock-d11", "clock-d21"))] +define_apb_types!( + A { + Pac0 = 0, + Pm = 1, + SysCtrl = 2, + Gclk = 3, + Wdt = 4, + Rtc = 5, + Eic = 6, + } + B { + Pac1 = 0, + Dsu = 1, + NvmCtrl = 2, + Port = 3, + Dmac = 4, + Usb = 5, + } + C { + Pac2 = 0, + EvSys = 1, + Sercom0 = 2, + Sercom1 = 3, + Sercom2 = 4, + Sercom3 = 5, + Sercom4 = 6, + Sercom5 = 7, + Tcc0 = 8, + Tcc1 = 9, + Tcc2 = 10, + Tc3 = 11, + Tc4 = 12, + Tc5 = 13, + Tc6 = 14, + Tc7 = 15, + Adc0 = 16, + Ac = 17, + Dac = 18, + Ptc = 19, + I2S = 20, + Ac1 = 21, + Tcc3 = 24, + } +); + //============================================================================== // ApbId //============================================================================== @@ -509,12 +575,16 @@ impl ApbClk { //============================================================================== /// Set of [`ApbToken`]s for APB clocks that are disabled at power-on reset + #[hal_macro_helper] pub struct ApbTokens { + #[hal_cfg("clock-d5x")] pub freq_m: ApbToken, pub sercom0: ApbToken, pub sercom1: ApbToken, + #[hal_cfg("clock-d5x")] pub tc0: ApbToken, + #[hal_cfg("clock-d5x")] pub tc1: ApbToken, pub usb: ApbToken, pub ev_sys: ApbToken, @@ -522,6 +592,7 @@ pub struct ApbTokens { pub sercom3: ApbToken, pub tcc0: ApbToken, pub tcc1: ApbToken, + #[hal_cfg("clock-d5x")] pub tc2: ApbToken, pub tc3: ApbToken, #[hal_cfg("tc4")] @@ -531,11 +602,16 @@ pub struct ApbTokens { pub tcc3: ApbToken, #[hal_cfg("tc5")] pub tc5: ApbToken, + #[hal_cfg("clock-d5x")] pub p_dec: ApbToken, pub ac: ApbToken, + #[hal_cfg("clock-d5x")] pub aes: ApbToken, + #[hal_cfg("clock-d5x")] pub trng: ApbToken, + #[hal_cfg("clock-d5x")] pub icm: ApbToken, + #[hal_cfg("clock-d5x")] pub ccl: ApbToken, pub sercom4: ApbToken, pub sercom5: ApbToken, @@ -550,10 +626,12 @@ pub struct ApbTokens { #[hal_cfg("tc7")] pub tc7: ApbToken, pub adc0: ApbToken, + #[hal_cfg("clock-d5x")] pub adc1: ApbToken, pub dac: ApbToken, #[hal_cfg("i2s")] pub i2s: ApbToken, + #[hal_cfg("clock-d5x")] pub pcc: ApbToken, } @@ -568,6 +646,7 @@ impl ApbTokens { pub(super) unsafe fn new() -> Self { unsafe { Self { + #[hal_cfg("clock-d5x")] freq_m: ApbToken::new(), sercom0: ApbToken::new(), sercom1: ApbToken::new(), @@ -588,11 +667,16 @@ impl ApbTokens { tcc3: ApbToken::new(), #[hal_cfg("tc5")] tc5: ApbToken::new(), + #[hal_cfg("clock-d5x")] p_dec: ApbToken::new(), ac: ApbToken::new(), + #[hal_cfg("clock-d5x")] aes: ApbToken::new(), + #[hal_cfg("clock-d5x")] trng: ApbToken::new(), + #[hal_cfg("clock-d5x")] icm: ApbToken::new(), + #[hal_cfg("clock-d5x")] ccl: ApbToken::new(), sercom4: ApbToken::new(), sercom5: ApbToken::new(), @@ -607,10 +691,12 @@ impl ApbTokens { #[hal_cfg("tc7")] tc7: ApbToken::new(), adc0: ApbToken::new(), + #[hal_cfg("clock-d5x")] adc1: ApbToken::new(), dac: ApbToken::new(), #[hal_cfg("i2s")] i2s: ApbToken::new(), + #[hal_cfg("clock-d5x")] pcc: ApbToken::new(), } } @@ -624,12 +710,17 @@ impl ApbTokens { /// Set of [`ApbClk`]s for APB clocks that are enabled at power-on reset #[hal_macro_helper] pub struct ApbClks { - pub pac: ApbClk, + pub pac: ApbClk, pub pm: ApbClk, + #[hal_cfg("clock-d5x")] pub mclk: ApbClk, + #[hal_cfg("clock-d5x")] pub rst_c: ApbClk, + #[hal_cfg("clock-d5x")] pub osc_ctrl: ApbClk, + #[hal_cfg("clock-d5x")] pub osc32k_ctrl: ApbClk, + #[hal_cfg("clock-d5x")] pub sup_c: ApbClk, pub gclk: ApbClk, pub wdt: ApbClk, @@ -638,9 +729,11 @@ pub struct ApbClks { pub dsu: ApbClk, pub nvm_ctrl: ApbClk, pub port: ApbClk, + #[hal_cfg("clock-d5x")] pub ram_ecc: ApbClk, #[hal_cfg("gmac")] pub gmac: ApbClk, + #[hal_cfg("clock-d5x")] pub qspi: ApbClk, } @@ -657,10 +750,15 @@ impl ApbClks { ApbClks { pac: ApbClk::new(ApbToken::new()), pm: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] mclk: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] rst_c: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] osc_ctrl: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] osc32k_ctrl: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] sup_c: ApbClk::new(ApbToken::new()), gclk: ApbClk::new(ApbToken::new()), wdt: ApbClk::new(ApbToken::new()), @@ -669,9 +767,11 @@ impl ApbClks { dsu: ApbClk::new(ApbToken::new()), nvm_ctrl: ApbClk::new(ApbToken::new()), port: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] ram_ecc: ApbClk::new(ApbToken::new()), #[hal_cfg("gmac")] gmac: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] qspi: ApbClk::new(ApbToken::new()), } } From 4ab564b2e1ddd549426caedcba59ecc3c04e2a71 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:55:56 +1200 Subject: [PATCH 060/114] More work on ahb --- hal/src/clock/v2/ahb.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hal/src/clock/v2/ahb.rs b/hal/src/clock/v2/ahb.rs index a860445e4ba9..5b0f92c42cf5 100644 --- a/hal/src/clock/v2/ahb.rs +++ b/hal/src/clock/v2/ahb.rs @@ -383,6 +383,7 @@ macro_rules! define_ahb_types { } #[hal_macro_helper] +#[hal_cfg("clock-d5x")] define_ahb_types!( Hpb0 = 0, Hpb1 = 1, @@ -410,3 +411,14 @@ define_ahb_types!( NvmCtrlSmeeProm = 22, NvmCtrlCache = 23, ); + +#[hal_cfg(any("clock-d11", "clock-d21"))] +define_ahb_types!( + Hpb0 = 0, + Hpb1 = 1, + Hpb2 = 2, + Dsu = 3, + NvmCtrl = 4, + Dmac = 5, + Usb = 6, +); From b50ffd52abb318bb964db0019c2553becf3fe4ad Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:56:27 +1200 Subject: [PATCH 061/114] stash 3 types --- hal/src/clock/v2/types.rs | 43 +++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index 96afd9f85db2..2dca13a9a3da 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -64,14 +64,20 @@ macro_rules! create_types { } create_types!(Ac); -create_types!(Adc0, Adc1); +create_types!(Adc0); +#[hal_cfg("clock-d5x")] +create_types!(Adc1); +#[hal_cfg("clock-d5x")] create_types!(Aes); #[hal_cfg("can0")] create_types!(Can0); #[hal_cfg("can1")] create_types!(Can1); +#[hal_cfg("clock-d5x")] create_types!(Ccl); +#[hal_cfg("clock-d5x")] create_types!(Cmcc); +#[hal_cfg("clock-d5x")] create_types!(CM4Trace); create_types!(Dac); create_types!(Dmac); @@ -81,47 +87,76 @@ create_types!( EvSys, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, EvSys11 ); +#[hal_cfg("clock-d5x")] create_types!(FreqM); +#[hal_cfg("clock-d5x")] create_types!(FreqMMeasure); +#[hal_cfg("clock-d5x")] create_types!(FreqMReference); create_types!(Gclk); #[hal_cfg("gmac")] create_types!(Gmac); -create_types!(Hpb0, Hpb1, Hpb2, Hpb3); +create_types!(Hpb0, Hpb1, Hpb2); +#[hal_cfg("clock-d5x")] +create_types!(Hpb3); +#[hal_cfg("clock-d5x")] create_types!(Icm); +#[hal_cfg("clock-d5x")] create_types!(Mclk); -create_types!(NvmCtrl, NvmCtrlSmeeProm, NvmCtrlCache); -#[hal_cfg("i2s")] +create_types!(NvmCtrl); +#[hal_cfg("clock-d5x")] +create_types!(NvmCtrlSmeeProm, NvmCtrlCache); +#[hal_cfg("clock-d5x")] // TODO was min-samd51j in Bradley's work create_types!(I2S, I2S0, I2S1); +#[hal_cfg("clock-d5x")] create_types!(OscCtrl); +#[hal_cfg("clock-d5x")] create_types!(Osc32kCtrl); create_types!(Pac0); +#[hal_cfg(any("clock-d11", "clock-d21"))] +create_types!(Pac1, Pac2); +#[hal_cfg("clock-d5x")] create_types!(Pcc); +#[hal_cfg("clock-d5x")] create_types!(PDec); create_types!(Pm); create_types!(Port); +#[hal_cfg("clock-d5x")] create_types!(Pukcc); +#[hal_cfg("clock-d5x")] create_types!(Qspi, Qspi2x); +#[hal_cfg("clock-d5x")] create_types!(RamEcc); +#[hal_cfg("clock-d5x")] create_types!(RstC); create_types!(Rtc); +#[hal_cfg("clock-d5x")] create_types!(Sdhc0); #[hal_cfg("sdhc1")] create_types!(Sdhc1); create_types!(SlowClk); +#[hal_cfg("clock-d5x")] create_types!(SupC); +#[hal_cfg(any("clock-d11", "clock-d21"))] +create_types!(SysCtrl); +#[hal_cfg("clock-d5x")] create_types!(Tc0Tc1, Tc0, Tc1); +#[hal_cfg("clock-d5x")] create_types!(Tc2Tc3, Tc2, Tc3); #[hal_cfg(all("tc4", "tc5"))] create_types!(Tc4Tc5, Tc4, Tc5); #[hal_cfg(all("tc6", "tc7"))] create_types!(Tc6Tc7, Tc6, Tc7); create_types!(Tcc0Tcc1, Tcc0, Tcc1); +#[hal_cfg("clock-d5x")] create_types!(Tcc2Tcc3, Tcc2); #[hal_cfg("tcc3")] create_types!(Tcc3); #[hal_cfg("tcc4")] create_types!(Tcc4); +#[hal_cfg(any("clock-d11", "clock-d21"))] +create_types!(Tcc2Tc3, Tcc2, Tc3); +#[hal_cfg("clock-d5x")] create_types!(Trng); create_types!(Usb); create_types!(Wdt); From b0b472d2b2b04e45dbea1ad7d221795686c62a1e Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:56:51 +1200 Subject: [PATCH 062/114] stash 3 pclk --- hal/src/clock/v2/pclk.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 6d08067957d0..cc82ef1d41d3 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -199,12 +199,20 @@ pub mod ids { #[hal_cfg("clock-d5x")] pub use super::super::dpll::Dpll1Id; + // TODO crude hack + #[hal_cfg("clock-d5x")] pub use super::super::types::{ Ac, Adc0, Adc1, CM4Trace, Ccl, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, FreqMMeasure, FreqMReference, PDec, Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Tcc0Tcc1, Tcc2Tcc3, Usb, }; + #[hal_cfg(any("clock-d11", "clock-d21"))] + pub use super::super::types::{ + Ac, Adc0, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, + EvSys9, EvSys10, EvSys11, SlowClk, Tcc0Tcc1, Usb, + }; + #[hal_cfg("can0")] pub use super::super::types::Can0; #[hal_cfg("can1")] @@ -217,6 +225,7 @@ pub mod ids { pub use super::super::types::Tc6Tc7; #[hal_cfg("tcc4")] pub use super::super::types::Tcc4; + #[hal_cfg("clock-d5x")] // TODO #[hal_cfg("i2s")] pub use super::super::types::{I2S0, I2S1}; } @@ -267,10 +276,13 @@ macro_rules! with_pclk_types_ids { (Dpll1Id = 2, dpll1) (SlowClk = 3, slow) (Eic = 4, eic) + #[hal_cfg("clock-d5x")] (FreqMMeasure = 5, freq_m_measure) + #[hal_cfg("clock-d5x")] (FreqMReference = 6, freq_m_reference) (Sercom0 = 7, sercom0) (Sercom1 = 8, sercom1) + #[hal_cfg("clock-d5x")] (Tc0Tc1 = 9, tc0_tc1) (Usb = 10, usb) (EvSys0 = 11, ev_sys0) @@ -288,16 +300,20 @@ macro_rules! with_pclk_types_ids { (Sercom2 = 23, sercom2) (Sercom3 = 24, sercom3) (Tcc0Tcc1 = 25, tcc0_tcc1) + #[hal_cfg("clock-d5x")] (Tc2Tc3 = 26, tc2_tc3) #[hal_cfg("can0")] (Can0 = 27, can0) #[hal_cfg("can1")] (Can1 = 28, can1) + #[hal_cfg("clock-d5x")] (Tcc2Tcc3 = 29, tcc2_tcc3) #[hal_cfg(all("tc4", "tc5"))] (Tc4Tc5 = 30, tc4_tc5) + #[hal_cfg("clock-d5x")] (PDec = 31, pdec) (Ac = 32, ac) + #[hal_cfg("clock-d5x")] (Ccl = 33, ccl) (Sercom4 = 34, sercom4) (Sercom5 = 35, sercom5) @@ -310,15 +326,18 @@ macro_rules! with_pclk_types_ids { #[hal_cfg(all("tc6", "tc7"))] (Tc6Tc7 = 39, tc6_tc7) (Adc0 = 40, adc0) + #[hal_cfg("clock-d5x")] (Adc1 = 41, adc1) (Dac = 42, dac) - #[hal_cfg("i2s")] + #[hal_cfg(all("i2s", "clock-d5x"))] (I2S0 = 43, i2s0) - #[hal_cfg("i2s")] + #[hal_cfg(all("i2s", "clock-d5x"))] (I2S1 = 44, i2s1) + #[hal_cfg("clock-d5x")] (Sdhc0 = 45, sdhc0) #[hal_cfg("sdhc1")] (Sdhc1 = 46, sdhc1) + #[hal_cfg("clock-d5x")] (CM4Trace = 47, cm4_trace) ); }; From d327af0a9c12851d91b835946d123c7a293f6cac Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:56:56 +1200 Subject: [PATCH 063/114] stash 3 apb --- hal/src/clock/v2/apb.rs | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 08b28797b0f5..517c300cd91c 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -129,14 +129,14 @@ use paste::paste; #[hal_cfg("clock-d5x")] mod imports { - pub use crate::pac::mclk::{RegisterBlock as BLOCK, Apbamask, Apbbmask, Apbcmask, Apbdmask}; pub use crate::pac::Mclk as Peripheral; + pub use crate::pac::mclk::{Apbamask, Apbbmask, Apbcmask, Apbdmask, RegisterBlock as BLOCK}; } #[hal_cfg(any("clock-d11", "clock-d21"))] mod imports { - pub use crate::pac::pm::{RegisterBlock as BLOCK, Apbamask, Apbbmask, Apbcmask}; pub use crate::pac::Pm as Peripheral; + pub use crate::pac::pm::{Apbamask, Apbbmask, Apbcmask, RegisterBlock as BLOCK}; } use imports::*; @@ -480,15 +480,9 @@ define_apb_types!( Tc3 = 11, Tc4 = 12, Tc5 = 13, - Tc6 = 14, - Tc7 = 15, Adc0 = 16, Ac = 17, Dac = 18, - Ptc = 19, - I2S = 20, - Ac1 = 21, - Tcc3 = 24, } ); @@ -629,7 +623,7 @@ pub struct ApbTokens { #[hal_cfg("clock-d5x")] pub adc1: ApbToken, pub dac: ApbToken, - #[hal_cfg("i2s")] + #[hal_cfg(all("clock-d5x", "i2s"))] // TODO pub i2s: ApbToken, #[hal_cfg("clock-d5x")] pub pcc: ApbToken, @@ -646,11 +640,13 @@ impl ApbTokens { pub(super) unsafe fn new() -> Self { unsafe { Self { - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] freq_m: ApbToken::new(), sercom0: ApbToken::new(), sercom1: ApbToken::new(), + #[hal_cfg("tc0")] tc0: ApbToken::new(), + #[hal_cfg("tc1")] tc1: ApbToken::new(), usb: ApbToken::new(), ev_sys: ApbToken::new(), @@ -658,6 +654,7 @@ impl ApbTokens { sercom3: ApbToken::new(), tcc0: ApbToken::new(), tcc1: ApbToken::new(), + #[hal_cfg("tc2")] tc2: ApbToken::new(), tc3: ApbToken::new(), #[hal_cfg("tc4")] @@ -694,7 +691,7 @@ impl ApbTokens { #[hal_cfg("clock-d5x")] adc1: ApbToken::new(), dac: ApbToken::new(), - #[hal_cfg("i2s")] + #[hal_cfg(all("clock-d5x", "i2s"))] // TODO i2s: ApbToken::new(), #[hal_cfg("clock-d5x")] pcc: ApbToken::new(), @@ -750,15 +747,15 @@ impl ApbClks { ApbClks { pac: ApbClk::new(ApbToken::new()), pm: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] mclk: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] rst_c: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] osc_ctrl: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] osc32k_ctrl: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] sup_c: ApbClk::new(ApbToken::new()), gclk: ApbClk::new(ApbToken::new()), wdt: ApbClk::new(ApbToken::new()), @@ -767,11 +764,11 @@ impl ApbClks { dsu: ApbClk::new(ApbToken::new()), nvm_ctrl: ApbClk::new(ApbToken::new()), port: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] ram_ecc: ApbClk::new(ApbToken::new()), #[hal_cfg("gmac")] gmac: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] qspi: ApbClk::new(ApbToken::new()), } } From 809d3318b2fab45cf38be9a1c9fa3ff2e651c859 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 14:19:00 +1200 Subject: [PATCH 064/114] stash 4 reset. TODO: Remove thumbv6 from v7 file --- hal/src/clock/v2.rs | 8 +- hal/src/clock/v2/reset_thumbv6m.rs | 177 ++++++++++++++++++ .../clock/v2/{reset.rs => reset_thumbv7em.rs} | 0 3 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 hal/src/clock/v2/reset_thumbv6m.rs rename hal/src/clock/v2/{reset.rs => reset_thumbv7em.rs} (100%) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 6eb5585c6880..0e36b34e010d 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -876,8 +876,12 @@ pub mod types; pub mod xosc; pub mod xosc32k; -// mod reset; -// pub use reset::*; +#[hal_module( + any("clock-d11", "clock-d21") => "v2/reset_thumbv6m.rs", + "clock-d5x" => "v2/reset_thumbv7em.rs", +)] +mod reset {} +pub use reset::*; // `Token` types and memory safety // diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs new file mode 100644 index 000000000000..854a1b16b6b8 --- /dev/null +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -0,0 +1,177 @@ +//! This module is intentionally private. Its contents are publicly exported +//! from the `v2` module, which is where the corresponding documentation will +//! appear. + +use typenum::U1; + +use crate::pac::{Gclk, Pm, Sysctrl}; + +use super::*; + +/// Collection of low-level PAC structs +/// +/// This struct serves to guard access to the low-level PAC structs. It places +/// them behind an `unsafe` barrier. +/// +/// Normally, users trade the low-level PAC structs for the higher-level +/// `clock::v2` API. However, in some cases, the `clock::v2` API may not be +/// sufficient. In these cases, users can access the registers directly by +/// calling [`Pac::steal`] to recover the PAC structs. +pub struct Pac { + gclk: Gclk, + pm: Pm, + sysctrl: Syctrl, +} + +impl Pac { + /// Escape hatch allowing to access low-level PAC structs + /// + /// Consume the [`Pac`] and return the low-level PAC structs. This is + /// useful when the `clock::v2` API does not provide a necessary feature, or + /// when dealing with the legacy `clock::v1` API. For example, many of the + /// `clock::v1` functions require access to the [`MCLK`] peripheral. + /// + /// # Safety + /// + /// Directly configuring clocks through the PAC API can invalidate the + /// type-level guarantees of the `clock` module API. + pub unsafe fn steal(self) -> (Gclk, Pm, Syctrl) { + (self.gclk, self.pm, self.sysctrl) + } +} + +/// Bus clock objects +/// +/// This type is constructed using the [`clock_system_at_reset`] function, which +/// consumes the PAC-level clocking structs and returns the HAL-level clocking +/// structs in their reset state. +/// +/// This type contains the [bus clocks](super#bus-clocks), which are a necessary +/// to implement memory safety for the [`AhbClk`]s and [`ApbClk`]s. +/// +/// [`AhbClk`]: super::ahb::AhbClk +/// [`ApbClk`]: super::apb::ApbClk +pub struct Buses { + pub ahb: ahb::Ahb, + pub apb: apb::Apb, +} + +pub struct OscUlp32kClocks { + pub base: osculp32k::EnabledOscUlp32kBase, + pub osculp1k: osculp32k::EnabledOscUlp1k, + pub osculp32k: osculp32k::EnabledOscUlp32k, +} + +/// Enabled clocks at power-on reset +/// +/// This type is constructed using the [`clock_system_at_reset`] function, which +/// consumes the PAC-level clocking structs and returns the HAL-level clocking +/// structs in their reset state. +/// +/// This type represents the clocks as they are configured at power-on reset. +/// The main clock, [`Gclk0`](gclk::Gclk0), runs at 48 MHz using the +/// [`Dfll`](dfll::Dfll) in open-loop mode. The ultra-low power +/// [base oscillator](osculp32k::OscUlp32kBase) is also enabled and running, as +/// it can never be disabled. +/// +/// As described in the [top-level](super::super) documentation for the `clock` +/// module, only [`Enabled`] clocks can be used as a [`Source`] for downstream +/// clocks. This struct contains all of the `Enabled` clocks at reset. +/// +/// This struct also contains the [`Pac`] wrapper struct, which provides +/// `unsafe` access to the low-level PAC structs. +pub struct Clocks { + /// Wrapper providing `unsafe` access to low-level PAC structs + pub pac: Pac, + /// Enabled AHB clocks + pub ahbs: ahb::AhbClks, + /// Enabled APB clocks + pub apbs: apb::ApbClks, + /// Main system clock, driven at 1 MHz by the OSC8M divided by 8 + pub gclk0: Enabled, U1>, + /// GCLK2, driven at 32 kHz by the OSCULP + pub gclk2: Enabled, U1>, + /// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2) + pub wdt: pclk::Pclk, + /// Always-enabled OSCULP oscillators + pub osculp32k: OscUlp32kClocks, +} + +/// Type-level tokens for unused clocks at power-on reset +/// +/// This type is constructed using the [`clock_system_at_reset`] function, which +/// consumes the PAC-level clocking structs and returns the HAL-level clocking +/// structs in their reset state. +/// +/// As described in the [top-level](super::super) documentation for the `clock` +/// module, token types are used to guanrantee the uniqueness of each clock. To +/// configure or enable a clock, you must provide the corresponding token. +pub struct Tokens { + /// Tokens to create [`apb::ApbClk`]s + pub apbs: apb::ApbTokens, + /// Token to create [`dfll::Dfll`] + pub dfll: dfll::DfllToken, + /// Token to create [`dpll::Dpll0`] + pub dpll: dpll::DpllToken, + /// Tokens to create [`gclk::Gclk`] + pub gclks: gclk::GclkTokens, + /// Tokens to create [`pclk::Pclk`]s + pub pclks: pclk::PclkTokens, + /// Tokens [`xosc::Xosc0`] + pub xosc: xosc::XoscToken, + /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and + /// [`xosc32k::Xosc32k`] + pub xosc32k: xosc32k::Xosc32kTokens, +} + +/// Consume the PAC clocking structs and return a HAL-level +/// representation of the clocks at power-on reset +/// +/// This function consumes the [`OSCCTRL`], [`OSC32KCTRL`], [`Gclk`] and +/// [`MCLK`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`]. +/// +/// See the [module-level documentation](super) for more details. +#[inline] +pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Syctrl) -> (Buses, Clocks, Tokens) { + // Safety: No bus, clock or token is instantiated more than once + unsafe { + let buses = Buses { + ahb: ahb::Ahb::new(), + apb: apb::Apb::new(), + }; + let pac = Pac { gclk, pm, sysctrl }; + let osc8m = Enabled::new(osc8m::Osc8m::new(osc8m::Osc8mToken::new())); + let (gclk0, osc8m) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc8m); + let gclk0 = Enabled::new(gclk0); + let base = osculp32k::OscUlp32kBase::new(); + let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); + let osculp32k = Enabled::new(osculp32k::OscUlp32k::new()); + let (gclk2, osculp32k) = gclk::Gclk2::from_source(gclk::GclkToken::new(), osculp32k); + let gclk2 = Enabled::new(gclk2); + let wdt = pclk::Pclk::new(pclk::PclkToken::new(), gclk2.freq()); + let osculp32k = OscUlp32kClocks { + base, + osculp1k, + osculp32k, + }; + let clocks = Clocks { + pac, + ahbs: ahb::AhbClks::new(), + apbs: apb::ApbClks::new(), + gclk0, + gclk2, + wdt, + osculp32k, + }; + let tokens = Tokens { + apbs: apb::ApbTokens::new(), + dfll: dfll::DfllToken::new(), + dpll: dpll::DpllToken::new(), + gclks: gclk::GclkTokens::new(), + pclks: pclk::PclkTokens::new(), + xosc: xosc::XoscToken::new(), + xosc32k: xosc32k::Xosc32kTokens::new(), + }; + (buses, clocks, tokens) + } +} diff --git a/hal/src/clock/v2/reset.rs b/hal/src/clock/v2/reset_thumbv7em.rs similarity index 100% rename from hal/src/clock/v2/reset.rs rename to hal/src/clock/v2/reset_thumbv7em.rs From 56d40172c4fa928db439051d5190e9b152d9cbff Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jul 2025 12:46:02 +1200 Subject: [PATCH 065/114] TODO notes --- hal/src/clock/v2/ahb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/clock/v2/ahb.rs b/hal/src/clock/v2/ahb.rs index 5b0f92c42cf5..76b7ead58f5d 100644 --- a/hal/src/clock/v2/ahb.rs +++ b/hal/src/clock/v2/ahb.rs @@ -420,5 +420,5 @@ define_ahb_types!( Dsu = 3, NvmCtrl = 4, Dmac = 5, - Usb = 6, + Usb = 6, // TODO this should be conditional. Others? ); From a0e4cd915534d07ea92da7b8e715257ade024e84 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jul 2025 13:42:26 +1200 Subject: [PATCH 066/114] stash 4 APB startup state using macro This could use further work - the macro now takes two booleans to indicate whether the type should be in the ApbTokens and ApbClocks structs, however each type should be in exactly one of those so it would be better for the macro to take a single boolean. --- hal/src/clock/v2/apb.rs | 451 ++++++++++++++-------------------------- 1 file changed, 157 insertions(+), 294 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 517c300cd91c..7f7a7e7fbf8d 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -296,13 +296,22 @@ enum ApbMask { D(ApbDMask), } +/// Define several APB-related types +/// +/// Define the [`DynApbId`], `ApbXMask`, [`ApbTokens`] and [`ApbClks`] types. +/// +/// This macro uses a slight hack to simplify its implementation. It uses +/// `#[cfg(all())]` and `#[cfg(any())]` to represent `#[cfg(true)]` and +/// `#[cfg(false)]`, respectively. We can use this to selectively place each +/// APB type into the [`ApbTokens`] struct or the [`ApbClks`] struct, depending +/// on whether or not the corresponding bit is enabled at power-on reset. macro_rules! define_apb_types { ( $( $Reg:ident { $( $( #[$( $cfg:tt )+] )? - $Type:ident = $BIT:literal, + $Type:ident = ($BIT:literal, $token:ident, $clk:ident) )+ } )+ @@ -367,122 +376,187 @@ macro_rules! define_apb_types { } } } + + /// Set of [`ApbToken`]s for APB clocks that are disabled at power-on reset + pub struct ApbTokens { + $( + $( + $( #[$( $cfg )+] )? + #[cfg($token())] + pub [<$Type:snake>]: ApbToken<$Type>, + )+ + )+ + } + + impl ApbTokens { + /// Create the set of [`ApbToken`]s + /// + /// # Safety + /// + /// All invariants required by `ApbToken::new` must be upheld here as well. + #[inline] + pub(super) unsafe fn new() -> Self { + Self { + $( + $( + $( #[$( $cfg )+] )? + #[cfg($token())] + [<$Type:snake>]: unsafe { ApbToken::new() }, + )+ + )+ + } + } + } + + /// Set of [`ApbClk`]s for APB clocks that are enabled at power-on reset + pub struct ApbClks { + $( + $( + $( #[$( $cfg )+] )? + #[cfg($clk())] + pub [<$Type:snake>]: ApbClk<$Type>, + )+ + )+ + } + + impl ApbClks { + /// Create the set of [`ApbClk`]s + /// + /// # Safety + /// + /// All invariants required by `ApbToken::new` must be upheld here as well. + #[inline] + pub(super) unsafe fn new() -> Self { + Self { + $( + $( + $( #[$( $cfg )+] )? + #[cfg($clk())] + [<$Type:snake>]: ApbClk::new( unsafe { ApbToken::new() } ), + )+ + )+ + } + } + } } }; } +// (N, all, any) => include in clocks not tokens = enabled at power-on #[hal_macro_helper] #[hal_cfg("clock-d5x")] define_apb_types!( A { - Pac0 = 0, - Pm = 1, - Mclk = 2, - RstC = 3, - OscCtrl = 4, - Osc32kCtrl = 5, - SupC = 6, - Gclk = 7, - Wdt = 8, - Rtc = 9, - Eic = 10, - FreqM = 11, - Sercom0 = 12, - Sercom1 = 13, - Tc0 = 14, - Tc1 = 15, + Pac0 = (0, all, any) + Pm = (1, all, any) + Mclk = (2, all, any) + RstC = (3, all, any) + OscCtrl = (4, all, any) + Osc32kCtrl = (5, all, any) + SupC = (6, all, any) + Gclk = (7, all, any) + Wdt = (8, all, any) + Rtc = (9, all, any) + Eic = (10, all, any) + FreqM = (11, any, all) + Sercom0 = (12, any, all) + Sercom1 = (13, any, all) + Tc0 = (14, any, all) + Tc1 = (15, any, all) } B { - Usb = 0, - Dsu = 1, - NvmCtrl = 2, - Port = 4, - EvSys = 7, - Sercom2 = 9, - Sercom3 = 10, - Tcc0 = 11, - Tcc1 = 12, - Tc2 = 13, - Tc3 = 14, - RamEcc = 16, + Usb = (0, any, all) + Dsu = (1, all, any) + NvmCtrl = (2, all, any) + Port = (4, all, any) + EvSys = (7, any, all) + Sercom2 = (9, any, all) + Sercom3 = (10, any, all) + Tcc0 = (11, any, all) + Tcc1 = (12, any, all) + Tc2 = (13, any, all) + Tc3 = (14, any, all) + RamEcc = (16, all, any) } C { #[hal_cfg("gmac")] - Gmac = 2, - Tcc2 = 3, + Gmac = (2, all, any) + Tcc2 = (3, any, all) #[hal_cfg("tcc3")] - Tcc3 = 4, + Tcc3 = (4, any, all) #[hal_cfg("tc4")] - Tc4 = 5, + Tc4 = (5, any, all) // TODO double check this is correct #[hal_cfg("tc5")] - Tc5 = 6, - PDec = 7, - Ac = 8, - Aes = 9, - Trng = 10, - Icm = 11, - Qspi = 13, - Ccl = 14, + Tc5 = (6, any, all) + PDec = (7, any, all) + Ac = (8, any, all) + Aes = (9, any, all) + Trng = (10, any, all) + Icm = (11, any, all) + Qspi = (13, all, any) + Ccl = (14, any, all) } D { - Sercom4 = 0, - Sercom5 = 1, + Sercom4 = (0, all, any) + Sercom5 = (1, all, any) #[hal_cfg("sercom6")] - Sercom6 = 2, + Sercom6 = (2, all, any) #[hal_cfg("sercom7")] - Sercom7 = 3, + Sercom7 = (3, all, any) #[hal_cfg("tcc4")] - Tcc4 = 4, + Tcc4 = (4, all, any) #[hal_cfg("tc6")] - Tc6 = 5, + Tc6 = (5, all, any) #[hal_cfg("tc7")] - Tc7 = 6, - Adc0 = 7, - Adc1 = 8, - Dac = 9, + Tc7 = (6, all, any) + Adc0 = (7, all, any) + Adc1 = (8, all, any) + Dac = (9, all, any) #[hal_cfg("i2s")] - I2S = 10, - Pcc = 11, + I2S = (10, all, any) + Pcc = (11, all, any) } ); +// See SAMD21/DA1 datasheet DS40001882H, 16.6.2.6 Peripheral Clock Masking +// TODO I2S needs to be added (disabled on startup) #[hal_cfg(any("clock-d11", "clock-d21"))] define_apb_types!( A { - Pac0 = 0, - Pm = 1, - SysCtrl = 2, - Gclk = 3, - Wdt = 4, - Rtc = 5, - Eic = 6, + Pac0 = (0, all, any) + Pm = (1, all, any) + SysCtrl = (2, all, any) + Gclk = (3, all, any) + Wdt = (4, all, any) + Rtc = (5, all, any) + Eic = (6, all, any) } B { - Pac1 = 0, - Dsu = 1, - NvmCtrl = 2, - Port = 3, - Dmac = 4, - Usb = 5, + Pac1 = (0, all, any) + Dsu = (1, all, any) + NvmCtrl = (2, all, any) + Port = (3, all, any) + Dmac = (4, all, any) + Usb = (5, all, any) // TODO should be conditional } C { - Pac2 = 0, - EvSys = 1, - Sercom0 = 2, - Sercom1 = 3, - Sercom2 = 4, - Sercom3 = 5, - Sercom4 = 6, - Sercom5 = 7, - Tcc0 = 8, - Tcc1 = 9, - Tcc2 = 10, - Tc3 = 11, - Tc4 = 12, - Tc5 = 13, - Adc0 = 16, - Ac = 17, - Dac = 18, + Pac2 = (0, any, all) + EvSys = (1, all, any) // TODO presume this is HMATRIX in data sheet DS40001882H + Sercom0 = (2, any, all) + Sercom1 = (3, any, all) + Sercom2 = (4, any, all) + Sercom3 = (5, any, all) + Sercom4 = (6, any, all) + Sercom5 = (7, any, all) + Tcc0 = (8, any, all) + Tcc1 = (9, any, all) + Tcc2 = (10, any, all) + Tc3 = (11, any, all) + Tc4 = (12, any, all) + Tc5 = (13, any, all) + Adc0 = (16, all, any) + Ac = (17, all, any) + Dac = (18, all, any) } ); @@ -563,214 +637,3 @@ impl ApbClk { self.token } } - -//============================================================================== -// ApbTokens -//============================================================================== - -/// Set of [`ApbToken`]s for APB clocks that are disabled at power-on reset - -#[hal_macro_helper] -pub struct ApbTokens { - #[hal_cfg("clock-d5x")] - pub freq_m: ApbToken, - pub sercom0: ApbToken, - pub sercom1: ApbToken, - #[hal_cfg("clock-d5x")] - pub tc0: ApbToken, - #[hal_cfg("clock-d5x")] - pub tc1: ApbToken, - pub usb: ApbToken, - pub ev_sys: ApbToken, - pub sercom2: ApbToken, - pub sercom3: ApbToken, - pub tcc0: ApbToken, - pub tcc1: ApbToken, - #[hal_cfg("clock-d5x")] - pub tc2: ApbToken, - pub tc3: ApbToken, - #[hal_cfg("tc4")] - pub tc4: ApbToken, - pub tcc2: ApbToken, - #[hal_cfg("tcc3")] - pub tcc3: ApbToken, - #[hal_cfg("tc5")] - pub tc5: ApbToken, - #[hal_cfg("clock-d5x")] - pub p_dec: ApbToken, - pub ac: ApbToken, - #[hal_cfg("clock-d5x")] - pub aes: ApbToken, - #[hal_cfg("clock-d5x")] - pub trng: ApbToken, - #[hal_cfg("clock-d5x")] - pub icm: ApbToken, - #[hal_cfg("clock-d5x")] - pub ccl: ApbToken, - pub sercom4: ApbToken, - pub sercom5: ApbToken, - #[hal_cfg("sercom6")] - pub sercom6: ApbToken, - #[hal_cfg("sercom7")] - pub sercom7: ApbToken, - #[hal_cfg("tcc4")] - pub tcc4: ApbToken, - #[hal_cfg("tc6")] - pub tc6: ApbToken, - #[hal_cfg("tc7")] - pub tc7: ApbToken, - pub adc0: ApbToken, - #[hal_cfg("clock-d5x")] - pub adc1: ApbToken, - pub dac: ApbToken, - #[hal_cfg(all("clock-d5x", "i2s"))] // TODO - pub i2s: ApbToken, - #[hal_cfg("clock-d5x")] - pub pcc: ApbToken, -} - -impl ApbTokens { - /// Create the set of [`ApbToken`]s - /// - /// # Safety - /// - /// All invariants required by `ApbToken::new` must be upheld here as well. - #[inline] - #[hal_macro_helper] - pub(super) unsafe fn new() -> Self { - unsafe { - Self { - #[hal_cfg("clock-d5x")] - freq_m: ApbToken::new(), - sercom0: ApbToken::new(), - sercom1: ApbToken::new(), - #[hal_cfg("tc0")] - tc0: ApbToken::new(), - #[hal_cfg("tc1")] - tc1: ApbToken::new(), - usb: ApbToken::new(), - ev_sys: ApbToken::new(), - sercom2: ApbToken::new(), - sercom3: ApbToken::new(), - tcc0: ApbToken::new(), - tcc1: ApbToken::new(), - #[hal_cfg("tc2")] - tc2: ApbToken::new(), - tc3: ApbToken::new(), - #[hal_cfg("tc4")] - tc4: ApbToken::new(), - tcc2: ApbToken::new(), - #[hal_cfg("tcc3")] - tcc3: ApbToken::new(), - #[hal_cfg("tc5")] - tc5: ApbToken::new(), - #[hal_cfg("clock-d5x")] - p_dec: ApbToken::new(), - ac: ApbToken::new(), - #[hal_cfg("clock-d5x")] - aes: ApbToken::new(), - #[hal_cfg("clock-d5x")] - trng: ApbToken::new(), - #[hal_cfg("clock-d5x")] - icm: ApbToken::new(), - #[hal_cfg("clock-d5x")] - ccl: ApbToken::new(), - sercom4: ApbToken::new(), - sercom5: ApbToken::new(), - #[hal_cfg("sercom6")] - sercom6: ApbToken::new(), - #[hal_cfg("sercom7")] - sercom7: ApbToken::new(), - #[hal_cfg("tcc4")] - tcc4: ApbToken::new(), - #[hal_cfg("tc6")] - tc6: ApbToken::new(), - #[hal_cfg("tc7")] - tc7: ApbToken::new(), - adc0: ApbToken::new(), - #[hal_cfg("clock-d5x")] - adc1: ApbToken::new(), - dac: ApbToken::new(), - #[hal_cfg(all("clock-d5x", "i2s"))] // TODO - i2s: ApbToken::new(), - #[hal_cfg("clock-d5x")] - pcc: ApbToken::new(), - } - } - } -} - -//============================================================================== -// ApbClks -//============================================================================== - -/// Set of [`ApbClk`]s for APB clocks that are enabled at power-on reset -#[hal_macro_helper] -pub struct ApbClks { - pub pac: ApbClk, - pub pm: ApbClk, - #[hal_cfg("clock-d5x")] - pub mclk: ApbClk, - #[hal_cfg("clock-d5x")] - pub rst_c: ApbClk, - #[hal_cfg("clock-d5x")] - pub osc_ctrl: ApbClk, - #[hal_cfg("clock-d5x")] - pub osc32k_ctrl: ApbClk, - #[hal_cfg("clock-d5x")] - pub sup_c: ApbClk, - pub gclk: ApbClk, - pub wdt: ApbClk, - pub rtc: ApbClk, - pub eic: ApbClk, - pub dsu: ApbClk, - pub nvm_ctrl: ApbClk, - pub port: ApbClk, - #[hal_cfg("clock-d5x")] - pub ram_ecc: ApbClk, - #[hal_cfg("gmac")] - pub gmac: ApbClk, - #[hal_cfg("clock-d5x")] - pub qspi: ApbClk, -} - -impl ApbClks { - /// Create the set of [`ApbClk`]s - /// - /// # Safety - /// - /// All invariants required by `ApbToken::new` must be upheld here as well. - #[inline] - #[hal_macro_helper] - pub(super) unsafe fn new() -> Self { - unsafe { - ApbClks { - pac: ApbClk::new(ApbToken::new()), - pm: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - mclk: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - rst_c: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - osc_ctrl: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - osc32k_ctrl: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - sup_c: ApbClk::new(ApbToken::new()), - gclk: ApbClk::new(ApbToken::new()), - wdt: ApbClk::new(ApbToken::new()), - rtc: ApbClk::new(ApbToken::new()), - eic: ApbClk::new(ApbToken::new()), - dsu: ApbClk::new(ApbToken::new()), - nvm_ctrl: ApbClk::new(ApbToken::new()), - port: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - ram_ecc: ApbClk::new(ApbToken::new()), - #[hal_cfg("gmac")] - gmac: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - qspi: ApbClk::new(ApbToken::new()), - } - } - } -} From 51729d44dc1cbb7ce75994c0052b7ee22405cbe1 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 25 Jul 2025 11:06:24 +1200 Subject: [PATCH 067/114] Fixes in APB for D11/D21 --- hal/src/clock/v2/apb.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 7f7a7e7fbf8d..dab3f3e11d76 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -518,8 +518,8 @@ define_apb_types!( } ); -// See SAMD21/DA1 datasheet DS40001882H, 16.6.2.6 Peripheral Clock Masking -// TODO I2S needs to be added (disabled on startup) +// SAMD21/DA1 datasheet DS40001882H, Table 12-1. Peripherals Configuration +// Summary TODO I2S needs to be added (disabled on startup) #[hal_cfg(any("clock-d11", "clock-d21"))] define_apb_types!( A { @@ -541,7 +541,7 @@ define_apb_types!( } C { Pac2 = (0, any, all) - EvSys = (1, all, any) // TODO presume this is HMATRIX in data sheet DS40001882H + EvSys = (1, any, all) Sercom0 = (2, any, all) Sercom1 = (3, any, all) Sercom2 = (4, any, all) @@ -554,9 +554,9 @@ define_apb_types!( Tc3 = (11, any, all) Tc4 = (12, any, all) Tc5 = (13, any, all) - Adc0 = (16, all, any) - Ac = (17, all, any) - Dac = (18, all, any) + Adc0 = (16, any, all) + Ac = (17, any, all) + Dac = (18, any, all) } ); From 1ecd022e0b37517080fae7b969b75e3416ab9073 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 25 Jul 2025 13:17:59 +1200 Subject: [PATCH 068/114] partial! stash 4 - gclk There's still some stuff to do, GclkIo etc. --- atsamd-hal-macros/devices.yaml | 6 +++--- hal/src/clock/v2/gclk.rs | 28 ++++++++++------------------ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/atsamd-hal-macros/devices.yaml b/atsamd-hal-macros/devices.yaml index 763d74a1003b..667c98742e38 100644 --- a/atsamd-hal-macros/devices.yaml +++ b/atsamd-hal-macros/devices.yaml @@ -21,7 +21,7 @@ families: - serial-numbers - dsu - clock - - gclk + - gclk: { count: 6 } - pm - sysctrl - wdt @@ -53,7 +53,7 @@ families: - serial-numbers - dsu - clock - - gclk + - gclk: { count: 8 } - pm - sysctrl - wdt @@ -96,7 +96,7 @@ families: - cmcc - dsu - clock - - gclk + - gclk: { count: 12 } - mclk - rstc - ramecc diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 01d45f60f903..901fe44ebd59 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -335,7 +335,7 @@ //! [`Pins`]: crate::gpio::Pins //! [`Sercom0`]: crate::sercom::Sercom0 -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::cmp::max; use core::marker::PhantomData; @@ -544,26 +544,12 @@ impl GclkToken { // DynGclkId //============================================================================== -/// Value-level enum identifying one of 12 possible [`Gclk`]s +/// Value-level enum identifying one of the possible [`Gclk`]s /// -/// The variants of this enum identify one of the 12 possible generic clock -/// generators. +/// The variants of this enum identify one generic clock generator. /// /// `DynGclkId` is the value-level equivalent of [`GclkId`]. -#[hal_cfg(any("clock-d11", "clock-d21"))] -pub enum DynGclkId { - Gclk0, - Gclk1, - Gclk2, - Gclk3, - Gclk4, - Gclk5, - Gclk6, - Gclk7, - Gclk8, -} - -#[hal_cfg("clock-d5x")] +#[hal_macro_helper] pub enum DynGclkId { Gclk0, Gclk1, @@ -571,11 +557,17 @@ pub enum DynGclkId { Gclk3, Gclk4, Gclk5, + #[hal_cfg("gclk6")] Gclk6, + #[hal_cfg("gclk7")] Gclk7, + #[hal_cfg("gclk8")] Gclk8, + #[hal_cfg("gclk9")] Gclk9, + #[hal_cfg("gclk10")] Gclk10, + #[hal_cfg("gclk11")] Gclk11, } From c559121e285af140553bbdf0a29eb306fcdb232a Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 25 Jul 2025 16:10:20 +1200 Subject: [PATCH 069/114] Remove with_gclk_max_expr!() --- hal/src/clock/v2/gclk.rs | 200 +++++++++++++++++++++++---------------- hal/src/clock/v2/pclk.rs | 30 ++++-- 2 files changed, 142 insertions(+), 88 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 901fe44ebd59..babe4ad1ccd2 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -340,7 +340,6 @@ use core::cmp::max; use core::marker::PhantomData; use paste::paste; -use seq_macro::seq; use typenum::{U0, U1}; use crate::pac; @@ -629,50 +628,43 @@ impl GclkId for Gclk1Id { type Divider = GclkDiv16; } -macro_rules! with_gclk_max { - ($N:ident in $start:literal ..= max $mac:tt) => { - #[hal_cfg("clock-d5x")] - seq!($N in $start..=11 $mac); - #[hal_cfg(any("clock-d11", "clock-d21"))] - seq!($N in $start..=8 $mac); - }; -} - -#[hal_cfg("clock-d5x")] -macro_rules! with_gclk_max_expr { - ($N:ident in $start:literal ..= max $mac:tt) => { - seq!($N in $start..=11 $mac) - }; -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -macro_rules! with_gclk_max_expr { - ($N:ident in $start:literal ..= max $mac:tt) => { - seq!($N in $start..=8 $mac) - }; -} - -pub(super) use with_gclk_max_expr; - -with_gclk_max!(N in 2..=max { - paste! { - /// Type-level variant of [`GclkId`] representing the identity of - #[doc = "GCLK" N] - /// - /// See the documentation on [type-level programming] and specifically - /// [type-level enums] for more details. - /// - /// [type-level programming]: crate::typelevel - /// [type-level enums]: crate::typelevel#type-level-enums - pub enum [] {} - impl Sealed for [] {} - impl GclkId for [] { - const DYN: DynGclkId = DynGclkId::Gclk~N; - const NUM: usize = N; - type Divider = GclkDiv8; +macro_rules! make_gclk_id { + ($num:literal) => { + paste! { + #[doc = GCLK $num] + /// + /// See the documentation on [type-level programming] and specifically + /// [type-level enums] for more details. + /// + /// [type-level programming]: crate::typelevel + /// [type-level enums]: crate::typelevel#type-level-enums + pub enum [] {} + impl Sealed for [] {} + impl GclkId for [] { + const DYN: DynGclkId = DynGclkId::[]; + const NUM: usize = $num; + type Divider = GclkDiv8; + } } } -}); +} + +make_gclk_id!(2); +make_gclk_id!(3); +make_gclk_id!(4); +make_gclk_id!(5); +#[hal_cfg("gclk6")] +make_gclk_id!(6); +#[hal_cfg("gclk7")] +make_gclk_id!(7); +#[hal_cfg("gclk8")] +make_gclk_id!(8); +#[hal_cfg("gclk9")] +make_gclk_id!(9); +#[hal_cfg("gclk10")] +make_gclk_id!(10); +#[hal_cfg("gclk11")] +make_gclk_id!(11); //============================================================================== // GclkDivider @@ -1135,15 +1127,35 @@ pub type Gclk0 = Gclk; /// on [`EnabledGclk0`] to configure the `Gclk` while it is actively running. pub type EnabledGclk0 = EnabledGclk; -with_gclk_max!(G in 1..=max { - paste! { - /// Type alias for the corresponding [`Gclk`] - pub type Gclk~G = Gclk<[], I>; - - /// Type alias for the corresponding [`EnabledGclk`] - pub type EnabledGclk~G = EnabledGclk<[], I, N>; +macro_rules! make_gclk { + ($num:literal) => { + paste! { + /// Type alias for the corresponding [`Gclk`] + pub type [] = Gclk<[], I>; + + /// Type alias for the corresponding [`EnabledGclk`] + pub type [] = EnabledGclk<[], I, N>; + } } -}); +} + +make_gclk!(1); +make_gclk!(2); +make_gclk!(3); +make_gclk!(4); +make_gclk!(5); +#[hal_cfg("gclk6")] +make_gclk!(6); +#[hal_cfg("gclk7")] +make_gclk!(7); +#[hal_cfg("gclk8")] +make_gclk!(8); +#[hal_cfg("gclk9")] +make_gclk!(9); +#[hal_cfg("gclk10")] +make_gclk!(10); +#[hal_cfg("gclk11")] +make_gclk!(11); impl Gclk where @@ -1483,38 +1495,66 @@ where // Tokens //============================================================================== -with_gclk_max!(N in 1..=max { - paste! { - /// Set of [`GclkToken`]s representing the disabled [`Gclk`]s at - /// power-on reset - pub struct GclkTokens { - #( - /// [`GclkToken`] for - #[doc = "[`Gclk" N "`]"] - pub gclk~N: GclkToken<[]>, - )* - } +/// Set of [`GclkToken`]s representing the disabled [`Gclk`]s at +/// power-on reset +#[hal_macro_helper] +pub struct GclkTokens { + pub gclk0: GclkToken, + pub gclk1: GclkToken, + pub gclk2: GclkToken, + pub gclk3: GclkToken, + pub gclk4: GclkToken, + pub gclk5: GclkToken, + #[hal_cfg("gclk6")] + pub gclk6: GclkToken, + #[hal_cfg("gclk7")] + pub gclk7: GclkToken, + #[hal_cfg("gclk8")] + pub gclk8: GclkToken, + #[hal_cfg("gclk9")] + pub gclk9: GclkToken, + #[hal_cfg("gclk10")] + pub gclk10: GclkToken, + #[hal_cfg("gclk11")] + pub gclk11: GclkToken, +} - impl GclkTokens { - /// Create the set of [`GclkToken`]s - /// - /// # Safety - /// - /// All of the invariants required by `GclkToken::new` must be - /// upheld here as well. - #[inline] - #[allow(unreachable_code)] // TODO remove when todo is removed - pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { - // Use auto wait states - //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); - todo!(); - GclkTokens { - #( gclk~N: unsafe {GclkToken::new()}, )* - } - } +#[hal_macro_helper] +impl GclkTokens { + /// Create the set of [`GclkToken`]s + /// + /// # Safety + /// + /// All of the invariants required by `GclkToken::new` must be + /// upheld here as well. + #[inline] + #[allow(unreachable_code)] // TODO remove when todo is removed + pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { + // Use auto wait states + //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); + todo!(); + GclkTokens { + gclk0: unsafe {GclkToken::new()}, + gclk1: unsafe {GclkToken::new()}, + gclk2: unsafe {GclkToken::new()}, + gclk3: unsafe {GclkToken::new()}, + gclk4: unsafe {GclkToken::new()}, + gclk5: unsafe {GclkToken::new()}, + #[hal_cfg("gclk6")] + gclk6: unsafe {GclkToken::new()}, + #[hal_cfg("gclk7")] + gclk7: unsafe {GclkToken::new()}, + #[hal_cfg("gclk8")] + gclk8: unsafe {GclkToken::new()}, + #[hal_cfg("gclk9")] + gclk9: unsafe {GclkToken::new()}, + #[hal_cfg("gclk10")] + gclk10: unsafe {GclkToken::new()}, + #[hal_cfg("gclk11")] + gclk11: unsafe {GclkToken::new()}, } } -}); +} //============================================================================== // GclkOut diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index cc82ef1d41d3..b19402d381da 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -89,7 +89,7 @@ use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; use super::Source; -use super::gclk::{DynGclkId, GclkId, with_gclk_max_expr}; +use super::gclk::{DynGclkId, GclkId}; //============================================================================== // PclkToken @@ -419,15 +419,29 @@ pub trait PclkId: Sealed { pub type DynPclkSourceId = DynGclkId; /// Convert from [`DynPclkSourceId`] to the equivalent [PAC](crate::pac) type +#[hal_macro_helper] impl From for Genselect { fn from(source: DynPclkSourceId) -> Self { - with_gclk_max_expr!(N in 0..=max { - match source { - #( - DynGclkId::Gclk~N => Genselect::Gclk~N, - )* - } - }) + match source { + DynPclkSourceId::Gclk0 => Genselect::Gclk0, + DynPclkSourceId::Gclk1 => Genselect::Gclk1, + DynPclkSourceId::Gclk2 => Genselect::Gclk2, + DynPclkSourceId::Gclk3 => Genselect::Gclk3, + DynPclkSourceId::Gclk4 => Genselect::Gclk4, + DynPclkSourceId::Gclk5 => Genselect::Gclk5, + #[hal_cfg("gclk6")] + DynPclkSourceId::Gclk6 => Genselect::Gclk6, + #[hal_cfg("gclk7")] + DynPclkSourceId::Gclk7 => Genselect::Gclk7, + #[hal_cfg("gclk8")] + DynPclkSourceId::Gclk8 => Genselect::Gclk8, + #[hal_cfg("gclk9")] + DynPclkSourceId::Gclk9 => Genselect::Gclk9, + #[hal_cfg("gclk10")] + DynPclkSourceId::Gclk10 => Genselect::Gclk10, + #[hal_cfg("gclk11")] + DynPclkSourceId::Gclk11 => Genselect::Gclk11, + } } } From 18bc0aba71256997db3159e3b27fb80e426ebe52 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jul 2025 15:28:24 +1200 Subject: [PATCH 070/114] stash 5 - osc --- hal/src/clock/v2/osc.rs | 168 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 hal/src/clock/v2/osc.rs diff --git a/hal/src/clock/v2/osc.rs b/hal/src/clock/v2/osc.rs new file mode 100644 index 000000000000..1f13f4552410 --- /dev/null +++ b/hal/src/clock/v2/osc.rs @@ -0,0 +1,168 @@ +use crate::pac::sysctrl::osc8m::{FRANGESELECT_A, PRESCSELECT_A}; +use crate::pac::sysctrl::OSC8M; +use crate::pac::SYSCTRL; + +use fugit::RateExtU32; +use crate::time::Hertz; +use crate::typelevel::Sealed; + +use super::{Enabled, Source}; + +pub struct OscToken(()); + +impl OscToken { + pub(super) unsafe fn new() -> Self { + Self(()) + } + + fn osc8m(&self) -> &OSC8M { + unsafe { &(*SYSCTRL::PTR).osc8m } + } + + fn enable(&mut self, settings: Settings) { + self.osc8m().modify(|_, w| { + if let Some(freq_range) = settings.freq_range { + w.frange().variant(freq_range.into()); + } + if let Some(calibration) = settings.calibration { + // Safety: The PAC will truncate the value to 12 bits, + // and all 12-bit values are valid + unsafe { w.calib().bits(calibration) }; + } + w.presc().variant(settings.prescaler.into()); + w.ondemand().bit(settings.on_demand); + w.runstdby().bit(settings.run_standby); + w.enable().set_bit() + }); + } + + fn disable(&mut self) { + self.osc8m().modify(|_, w| w.enable().clear_bit()) + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +struct Settings { + freq_range: Option, + calibration: Option, + prescaler: Prescaler, + on_demand: bool, + run_standby: bool, +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum FreqRange { + FourToSix, + SixToEight, + EightToEleven, + ElevenToFifteen, +} + +impl From for FRANGESELECT_A { + fn from(freq_range: FreqRange) -> Self { + match freq_range { + FreqRange::FourToSix => Self::_0, + FreqRange::SixToEight => Self::_1, + FreqRange::EightToEleven => Self::_2, + FreqRange::ElevenToFifteen => Self::_3, + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Prescaler { + One, + Two, + Four, + Eight, +} + +impl From for PRESCSELECT_A { + fn from(prescaler: Prescaler) -> Self { + match prescaler { + Prescaler::One => Self::_0, + Prescaler::Two => Self::_1, + Prescaler::Four => Self::_2, + Prescaler::Eight => Self::_3, + } + } +} + +pub enum OscId {} + +impl Sealed for OscId {} + +pub struct Osc { + token: OscToken, + settings: Settings, +} + +impl Osc { + pub fn new(token: OscToken) -> Self { + let settings = Settings { + freq_range: None, + calibration: None, + prescaler: Prescaler::Eight, + on_demand: true, + run_standby: false, + }; + Self { token, settings } + } + + pub fn freq_range(mut self, freq_range: FreqRange) -> Self { + self.settings.freq_range = Some(freq_range); + self + } + + pub fn calibration(mut self, calibration: u16) -> Self { + self.settings.calibration = Some(calibration); + self + } + + pub fn prescaler(mut self, prescaler: Prescaler) -> Self { + self.settings.prescaler = prescaler; + self + } + + pub fn on_demand(mut self, on_demand: bool) -> Self { + self.settings.on_demand = on_demand; + self + } + + pub fn run_standby(mut self, run_standby: bool) -> Self { + self.settings.run_standby = run_standby; + self + } + + pub fn freq(&self) -> Hertz { + let div = match self.settings.prescaler { + Prescaler::One => 1, + Prescaler::Two => 2, + Prescaler::Four => 4, + Prescaler::Eight => 8, + }; + (8_000_000u32 / div).Hz() + } + + pub fn enable(mut self) -> Enabled { + self.token.enable(self.settings); + Enabled::new(self) + } +} + +pub type EnabledOsc = Enabled; + +impl EnabledOsc { + pub fn disable(mut self) -> Osc { + self.0.token.disable(); + self.0 + } +} + +impl Source for EnabledOsc { + type Id = OscId; + + fn freq(&self) -> Hertz { + self.0.freq() + } +} From 428064fb8fb8531dad16cbe0d7b12e9a294660f4 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 25 Jul 2025 14:15:38 +1200 Subject: [PATCH 071/114] osc fixes and partial stash 5 - reset --- hal/src/clock/v2.rs | 4 ++++ hal/src/clock/v2/osc.rs | 17 ++++++++++------- hal/src/clock/v2/reset_thumbv6m.rs | 15 +++++++++------ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 0e36b34e010d..a998a14d758f 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -866,6 +866,10 @@ pub mod apb; pub mod dfll; pub mod dpll; pub mod gclk; +#[hal_module( + any("clock-d11", "clock-d21") => "v2/osc.rs", +)] +pub mod osc {} pub mod osculp32k; pub mod pclk; #[hal_module( diff --git a/hal/src/clock/v2/osc.rs b/hal/src/clock/v2/osc.rs index 1f13f4552410..71fb9013e354 100644 --- a/hal/src/clock/v2/osc.rs +++ b/hal/src/clock/v2/osc.rs @@ -1,6 +1,8 @@ -use crate::pac::sysctrl::osc8m::{FRANGESELECT_A, PRESCSELECT_A}; -use crate::pac::sysctrl::OSC8M; -use crate::pac::SYSCTRL; +//! Open-loop 8MHz oscillator + +use crate::pac::sysctrl::osc8m::{Frangeselect, Prescselect}; +use crate::pac::sysctrl::Osc8m; +use crate::pac::Sysctrl; use fugit::RateExtU32; use crate::time::Hertz; @@ -15,8 +17,8 @@ impl OscToken { Self(()) } - fn osc8m(&self) -> &OSC8M { - unsafe { &(*SYSCTRL::PTR).osc8m } + fn osc8m(&self) -> &Osc8m { + unsafe { &(*Sysctrl::PTR).osc8m() } } fn enable(&mut self, settings: Settings) { @@ -51,6 +53,7 @@ struct Settings { } #[derive(Clone, Copy, PartialEq, Eq)] +/// Frequency ranges in Megahertz pub enum FreqRange { FourToSix, SixToEight, @@ -58,7 +61,7 @@ pub enum FreqRange { ElevenToFifteen, } -impl From for FRANGESELECT_A { +impl From for Frangeselect { fn from(freq_range: FreqRange) -> Self { match freq_range { FreqRange::FourToSix => Self::_0, @@ -77,7 +80,7 @@ pub enum Prescaler { Eight, } -impl From for PRESCSELECT_A { +impl From for Prescselect { fn from(prescaler: Prescaler) -> Self { match prescaler { Prescaler::One => Self::_0, diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index 854a1b16b6b8..ead7f4a858d1 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -20,7 +20,7 @@ use super::*; pub struct Pac { gclk: Gclk, pm: Pm, - sysctrl: Syctrl, + sysctrl: Sysctrl, } impl Pac { @@ -35,7 +35,7 @@ impl Pac { /// /// Directly configuring clocks through the PAC API can invalidate the /// type-level guarantees of the `clock` module API. - pub unsafe fn steal(self) -> (Gclk, Pm, Syctrl) { + pub unsafe fn steal(self) -> (Gclk, Pm, Sysctrl) { (self.gclk, self.pm, self.sysctrl) } } @@ -88,9 +88,11 @@ pub struct Clocks { /// Enabled APB clocks pub apbs: apb::ApbClks, /// Main system clock, driven at 1 MHz by the OSC8M divided by 8 - pub gclk0: Enabled, U1>, + pub gclk0: Enabled, U1>, /// GCLK2, driven at 32 kHz by the OSCULP pub gclk2: Enabled, U1>, + /// 8 MHz internal oscillator, divided by 8 for a 1 MHz output + pub osc: Enabled, /// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2) pub wdt: pclk::Pclk, /// Always-enabled OSCULP oscillators @@ -132,7 +134,7 @@ pub struct Tokens { /// /// See the [module-level documentation](super) for more details. #[inline] -pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Syctrl) -> (Buses, Clocks, Tokens) { +pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Clocks, Tokens) { // Safety: No bus, clock or token is instantiated more than once unsafe { let buses = Buses { @@ -140,8 +142,8 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Syctrl) -> (Buses, Clo apb: apb::Apb::new(), }; let pac = Pac { gclk, pm, sysctrl }; - let osc8m = Enabled::new(osc8m::Osc8m::new(osc8m::Osc8mToken::new())); - let (gclk0, osc8m) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc8m); + let osc = Enabled::<_, U0>::new(osc::Osc::new(osc::OscToken::new())); + let (gclk0, osc8m) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc); let gclk0 = Enabled::new(gclk0); let base = osculp32k::OscUlp32kBase::new(); let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); @@ -160,6 +162,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Syctrl) -> (Buses, Clo apbs: apb::ApbClks::new(), gclk0, gclk2, + osc, wdt, osculp32k, }; From a7020583bc72af9750a6c1fd21e88b5a26ecebcf Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 26 Jul 2025 10:35:20 +1200 Subject: [PATCH 072/114] stash 4 - dfll --- hal/src/clock/v2/dfll.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index f10f725922e4..daa623f139d3 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -276,6 +276,7 @@ use atsamd_hal_macros::hal_cfg; #[hal_cfg("clock-d5x")] mod imports { + pub use crate::pac::Oscctrl as PERIPHERAL; pub use crate::pac::oscctrl::{ Dfllctrla as Dfllctrl, Dfllctrlb, Dfllmul, Dfllsync, RegisterBlock, }; @@ -283,6 +284,7 @@ mod imports { #[hal_cfg(any("clock-d11", "clock-d21"))] mod imports { + pub use crate::pac::Sysctrl as PERIPHERAL; pub use crate::pac::sysctrl::{Dfllctrl, Dfllmul, Dfllsync, RegisterBlock}; } @@ -329,14 +331,7 @@ impl DfllToken { // of registers for the DFLL, and we use a shared reference to the // register block. See the notes on `Token` types and memory safety in // the root of the `clock` module for more details. - #[hal_cfg("clock-d5x")] - unsafe { - &*crate::pac::Oscctrl::PTR - } - #[hal_cfg(any("clock-d11", "clock-d21"))] - unsafe { - &*crate::pac::Sysctrl::PTR - } + unsafe { &*PERIPHERAL::PTR } } #[hal_cfg("clock-d5x")] From 9947b96026a76ca07349ce1a96eb8a8108bc7ef5 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 26 Jul 2025 16:15:29 +1200 Subject: [PATCH 073/114] fixup gclk --- hal/src/clock/v2/gclk.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index babe4ad1ccd2..ac6ac474a123 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -646,7 +646,7 @@ macro_rules! make_gclk_id { type Divider = GclkDiv8; } } - } + }; } make_gclk_id!(2); @@ -1132,11 +1132,11 @@ macro_rules! make_gclk { paste! { /// Type alias for the corresponding [`Gclk`] pub type [] = Gclk<[], I>; - + /// Type alias for the corresponding [`EnabledGclk`] pub type [] = EnabledGclk<[], I, N>; } - } + }; } make_gclk!(1); @@ -1534,24 +1534,24 @@ impl GclkTokens { //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); todo!(); GclkTokens { - gclk0: unsafe {GclkToken::new()}, - gclk1: unsafe {GclkToken::new()}, - gclk2: unsafe {GclkToken::new()}, - gclk3: unsafe {GclkToken::new()}, - gclk4: unsafe {GclkToken::new()}, - gclk5: unsafe {GclkToken::new()}, + gclk0: unsafe { GclkToken::new() }, + gclk1: unsafe { GclkToken::new() }, + gclk2: unsafe { GclkToken::new() }, + gclk3: unsafe { GclkToken::new() }, + gclk4: unsafe { GclkToken::new() }, + gclk5: unsafe { GclkToken::new() }, #[hal_cfg("gclk6")] - gclk6: unsafe {GclkToken::new()}, + gclk6: unsafe { GclkToken::new() }, #[hal_cfg("gclk7")] - gclk7: unsafe {GclkToken::new()}, + gclk7: unsafe { GclkToken::new() }, #[hal_cfg("gclk8")] - gclk8: unsafe {GclkToken::new()}, + gclk8: unsafe { GclkToken::new() }, #[hal_cfg("gclk9")] - gclk9: unsafe {GclkToken::new()}, + gclk9: unsafe { GclkToken::new() }, #[hal_cfg("gclk10")] - gclk10: unsafe {GclkToken::new()}, + gclk10: unsafe { GclkToken::new() }, #[hal_cfg("gclk11")] - gclk11: unsafe {GclkToken::new()}, + gclk11: unsafe { GclkToken::new() }, } } } From 6dc113f9dadb3a53c8b24afc86bbb82d59552e07 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 26 Jul 2025 20:09:54 +1200 Subject: [PATCH 074/114] stash 4 - types --- hal/src/clock/v2/types.rs | 260 ++++++++++++++++++++++---------------- 1 file changed, 154 insertions(+), 106 deletions(-) diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index 2dca13a9a3da..0ff95ac3a475 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -21,30 +21,6 @@ use atsamd_hal_macros::hal_cfg; use crate::typelevel::Sealed; -#[hal_cfg("sercom0")] -pub use crate::sercom::Sercom0; - -#[hal_cfg("sercom1")] -pub use crate::sercom::Sercom1; - -#[hal_cfg("sercom2")] -pub use crate::sercom::Sercom2; - -#[hal_cfg("sercom3")] -pub use crate::sercom::Sercom3; - -#[hal_cfg("sercom4")] -pub use crate::sercom::Sercom4; - -#[hal_cfg("sercom5")] -pub use crate::sercom::Sercom5; - -#[hal_cfg("sercom6")] -pub use crate::sercom::Sercom6; - -#[hal_cfg("sercom7")] -pub use crate::sercom::Sercom7; - macro_rules! create_types { ( $( @@ -63,100 +39,172 @@ macro_rules! create_types { }; } +// AHB types +create_types!(Dmac); +create_types!(Dsu); +create_types!(Hpb0, Hpb1, Hpb2); +create_types!(NvmCtrl); +create_types!(Usb); + +// APB types create_types!(Ac); create_types!(Adc0); -#[hal_cfg("clock-d5x")] -create_types!(Adc1); -#[hal_cfg("clock-d5x")] -create_types!(Aes); -#[hal_cfg("can0")] -create_types!(Can0); -#[hal_cfg("can1")] -create_types!(Can1); -#[hal_cfg("clock-d5x")] -create_types!(Ccl); -#[hal_cfg("clock-d5x")] -create_types!(Cmcc); -#[hal_cfg("clock-d5x")] -create_types!(CM4Trace); create_types!(Dac); -create_types!(Dmac); -create_types!(Dsu); create_types!(Eic); -create_types!( - EvSys, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, - EvSys11 -); -#[hal_cfg("clock-d5x")] -create_types!(FreqM); -#[hal_cfg("clock-d5x")] -create_types!(FreqMMeasure); -#[hal_cfg("clock-d5x")] -create_types!(FreqMReference); +create_types!(EvSys); create_types!(Gclk); -#[hal_cfg("gmac")] -create_types!(Gmac); -create_types!(Hpb0, Hpb1, Hpb2); -#[hal_cfg("clock-d5x")] -create_types!(Hpb3); -#[hal_cfg("clock-d5x")] -create_types!(Icm); -#[hal_cfg("clock-d5x")] -create_types!(Mclk); -create_types!(NvmCtrl); -#[hal_cfg("clock-d5x")] -create_types!(NvmCtrlSmeeProm, NvmCtrlCache); -#[hal_cfg("clock-d5x")] // TODO was min-samd51j in Bradley's work -create_types!(I2S, I2S0, I2S1); -#[hal_cfg("clock-d5x")] -create_types!(OscCtrl); -#[hal_cfg("clock-d5x")] -create_types!(Osc32kCtrl); +#[hal_cfg("i2s")] +create_types!(I2S); create_types!(Pac0); -#[hal_cfg(any("clock-d11", "clock-d21"))] -create_types!(Pac1, Pac2); -#[hal_cfg("clock-d5x")] -create_types!(Pcc); -#[hal_cfg("clock-d5x")] -create_types!(PDec); create_types!(Pm); create_types!(Port); -#[hal_cfg("clock-d5x")] -create_types!(Pukcc); -#[hal_cfg("clock-d5x")] -create_types!(Qspi, Qspi2x); -#[hal_cfg("clock-d5x")] -create_types!(RamEcc); -#[hal_cfg("clock-d5x")] -create_types!(RstC); create_types!(Rtc); -#[hal_cfg("clock-d5x")] -create_types!(Sdhc0); -#[hal_cfg("sdhc1")] -create_types!(Sdhc1); -create_types!(SlowClk); -#[hal_cfg("clock-d5x")] -create_types!(SupC); -#[hal_cfg(any("clock-d11", "clock-d21"))] -create_types!(SysCtrl); -#[hal_cfg("clock-d5x")] -create_types!(Tc0Tc1, Tc0, Tc1); -#[hal_cfg("clock-d5x")] -create_types!(Tc2Tc3, Tc2, Tc3); -#[hal_cfg(all("tc4", "tc5"))] -create_types!(Tc4Tc5, Tc4, Tc5); -#[hal_cfg(all("tc6", "tc7"))] -create_types!(Tc6Tc7, Tc6, Tc7); -create_types!(Tcc0Tcc1, Tcc0, Tcc1); -#[hal_cfg("clock-d5x")] -create_types!(Tcc2Tcc3, Tcc2); +#[hal_cfg("sercom0")] +pub use crate::sercom::Sercom0; +#[hal_cfg("sercom1")] +pub use crate::sercom::Sercom1; +#[hal_cfg("sercom2")] +pub use crate::sercom::Sercom2; +#[hal_cfg("sercom3")] +pub use crate::sercom::Sercom3; +#[hal_cfg("sercom4")] +pub use crate::sercom::Sercom4; +#[hal_cfg("sercom5")] +pub use crate::sercom::Sercom5; +#[hal_cfg("sercom6")] +pub use crate::sercom::Sercom6; +#[hal_cfg("sercom7")] +pub use crate::sercom::Sercom7; + +#[hal_cfg("tc0")] +create_types!(Tc0); +#[hal_cfg("tc1")] +create_types!(Tc1); +#[hal_cfg("tc2")] +create_types!(Tc2); +#[hal_cfg("tc3")] +create_types!(Tc3); +#[hal_cfg("tc4")] +create_types!(Tc4); +#[hal_cfg("tc5")] +create_types!(Tc5); +#[hal_cfg("tc6")] +create_types!(Tc6); +#[hal_cfg("tc7")] +create_types!(Tc7); + +#[hal_cfg("tcc0")] +create_types!(Tcc0); +#[hal_cfg("tcc1")] +create_types!(Tcc1); +#[hal_cfg("tcc2")] +create_types!(Tcc2); #[hal_cfg("tcc3")] create_types!(Tcc3); #[hal_cfg("tcc4")] create_types!(Tcc4); + +// TODO +#[hal_cfg(all("tc0", "tc1"))] +create_types!(Tc0Tc1); +#[hal_cfg(all("tc2", "tc3"))] +create_types!(Tc2Tc3); +#[hal_cfg(all("tc4", "tc5"))] +create_types!(Tc4Tc5); +#[hal_cfg(all("tc6", "tc7"))] +create_types!(Tc6Tc7); + +#[hal_cfg(all("tcc0", "tcc1"))] +create_types!(Tcc0Tcc1); +#[hal_cfg(all("tcc2", "tcc3"))] +create_types!(Tcc2Tcc3); + +#[hal_cfg(all("tcc2", "tc3-d21"))] +create_types!(Tcc2Tc3); + +create_types!(Wdt); + +// PCLK types +// TODO set channel numbers in devices.yaml +create_types!( + EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, + EvSys11 +); +#[hal_cfg("i2s")] +create_types!(I2S0, I2S1); +create_types!(SlowClk); + +#[hal_cfg("clock-d5x")] +mod variant_ahb_types { + use super::{Sealed, hal_cfg}; + + #[hal_cfg("can0")] + create_types!(Can0); + #[hal_cfg("can1")] + create_types!(Can1); + create_types!(Cmcc); + #[hal_cfg("gmac")] + create_types!(Gmac); + create_types!(Hpb3); + create_types!(Icm); + create_types!(NvmCtrlSmeeProm, NvmCtrlCache); + create_types!(Pukcc); + create_types!(Qspi, Qspi2x); + #[hal_cfg("sdhc0")] + create_types!(Sdhc0); + #[hal_cfg("sdhc1")] + create_types!(Sdhc1); +} + +#[hal_cfg("clock-d5x")] +mod variant_apb_types { + use super::Sealed; + + create_types!(Adc1); + create_types!(Aes); + create_types!(Ccl); + create_types!(FreqM); + create_types!(Mclk); + create_types!(OscCtrl); + create_types!(Osc32kCtrl); + create_types!(Pcc); + create_types!(PDec); + create_types!(RamEcc); + create_types!(RstC); + create_types!(SupC); + create_types!(Trng); +} + +#[hal_cfg("clock-d5x")] +mod variant_pclk_types { + use super::Sealed; + + create_types!(CM4Trace); + create_types!(FreqMMeasure); + create_types!(FreqMReference); +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod variant_apb_types { + use super::{Sealed, hal_cfg}; + + #[hal_cfg("clock-d21")] + create_types!(Ac1); + create_types!(Pac1, Pac2); + create_types!(Ptc); + create_types!(SysCtrl); +} + #[hal_cfg(any("clock-d11", "clock-d21"))] -create_types!(Tcc2Tc3, Tcc2, Tc3); +mod variant_pclk_types { + use super::Sealed; + + create_types!(AcDig); + create_types!(AcAna); + create_types!(SercomSlow); +} + #[hal_cfg("clock-d5x")] -create_types!(Trng); -create_types!(Usb); -create_types!(Wdt); +pub use variant_ahb_types::*; +pub use variant_apb_types::*; +pub use variant_pclk_types::*; From 3827acb5149d3ca5f59bd119351cc84ff7fdf845 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 26 Jul 2025 16:16:44 +1200 Subject: [PATCH 075/114] stash 4 - pclk --- hal/src/clock/v2/pclk.rs | 119 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 8 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index b19402d381da..61e038463ea7 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -67,7 +67,6 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use paste::paste; -use seq_macro::seq; use crate::pac; @@ -184,11 +183,20 @@ impl PclkToken

{ /// ``` /// use atsamd_hal::clock::v2::pclk::ids::*; /// ``` + pub mod ids { use atsamd_hal_macros::hal_cfg; - pub use crate::sercom::{Sercom0, Sercom1, Sercom2, Sercom3, Sercom4, Sercom5}; + pub use crate::sercom::{Sercom0, Sercom1}; + #[hal_cfg("sercom2")] + pub use crate::sercom::Sercom2; + #[hal_cfg("sercom3")] + pub use crate::sercom::Sercom3; + #[hal_cfg("sercom4")] + pub use crate::sercom::Sercom4; + #[hal_cfg("sercom5")] + pub use crate::sercom::Sercom5; #[hal_cfg("sercom6")] pub use crate::sercom::Sercom6; #[hal_cfg("sercom7")] @@ -209,8 +217,9 @@ pub mod ids { #[hal_cfg(any("clock-d11", "clock-d21"))] pub use super::super::types::{ - Ac, Adc0, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, - EvSys9, EvSys10, EvSys11, SlowClk, Tcc0Tcc1, Usb, + Ac, AcAna, AcDig, Adc0, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, + EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, Ptc, Rtc, SercomSlow, SlowClk, Tcc0Tcc1, Usb, + Wdt, }; #[hal_cfg("can0")] @@ -225,7 +234,12 @@ pub mod ids { pub use super::super::types::Tc6Tc7; #[hal_cfg("tcc4")] pub use super::super::types::Tcc4; - #[hal_cfg("clock-d5x")] // TODO + + // TODO would it make sense to just pub use super::super::types::* and + // conditionally restrict what types we make there? + #[hal_cfg(all("tcc2", "tc3-d21"))] + pub use super::super::types::Tcc2Tc3; + #[hal_cfg("i2s")] pub use super::super::types::{I2S0, I2S1}; } @@ -265,6 +279,7 @@ use ids::*; /// /// with_pclk_types_ids!(some_macro!(first, second)); /// ``` +#[hal_cfg("clock-d5x")] #[hal_macro_helper] macro_rules! with_pclk_types_ids { ( $some_macro:ident ! ( $( $args:tt )* ) ) => { @@ -272,7 +287,6 @@ macro_rules! with_pclk_types_ids { $( $args )* (DfllId = 0, dfll) (Dpll0Id = 1, dpll0) - #[hal_cfg("clock-d5x")] (Dpll1Id = 2, dpll1) (SlowClk = 3, slow) (Eic = 4, eic) @@ -329,9 +343,9 @@ macro_rules! with_pclk_types_ids { #[hal_cfg("clock-d5x")] (Adc1 = 41, adc1) (Dac = 42, dac) - #[hal_cfg(all("i2s", "clock-d5x"))] + #[hal_cfg("i2s")] (I2S0 = 43, i2s0) - #[hal_cfg(all("i2s", "clock-d5x"))] + #[hal_cfg("i2s")] (I2S1 = 44, i2s1) #[hal_cfg("clock-d5x")] (Sdhc0 = 45, sdhc0) @@ -343,6 +357,95 @@ macro_rules! with_pclk_types_ids { }; } +#[hal_cfg("clock-d21")] +#[hal_macro_helper] +macro_rules! with_pclk_types_ids { + ( $some_macro:ident ! ( $( $args:tt )* ) ) => { + $some_macro!( + $( $args )* + (DfllId = 0, dfll) + (Dpll0Id = 1, dpll) + (SlowClk = 2, slow) + (Wdt = 3, wdt) + (Rtc = 4, rtc) + (Eic = 5, eic) + (Usb = 6, usb) + (EvSys0 = 7, ev_sys0) + (EvSys1 = 8, ev_sys1) + (EvSys2 = 9, ev_sys2) + (EvSys3 = 10, ev_sys3) + (EvSys4 = 11, ev_sys4) + (EvSys5 = 12, ev_sys5) + (EvSys6 = 13, ev_sys6) + (EvSys7 = 14, ev_sys7) + (EvSys8 = 15, ev_sys8) + (EvSys9 = 16, ev_sys9) + (EvSys10 = 17, ev_sys10) + (EvSys11 = 18, ev_sys11) + (SercomSlow = 19, sercom_slow) + (Sercom0 = 20, sercom0) + (Sercom1 = 21, sercom1) + #[hal_cfg("sercom2")] + (Sercom2 = 22, sercom2) + #[hal_cfg("sercom3")] + (Sercom3 = 23, sercom3) + #[hal_cfg("sercom4")] + (Sercom4 = 24, sercom4) + #[hal_cfg("sercom5")] + (Sercom5 = 25, sercom5) + (Tcc0Tcc1 = 26, tcc0_tcc1) + (Tcc2Tc3 = 27, tcc2_tc3) + (Tc4Tc5 = 28, tc4_tc5) + #[hal_cfg(all("tc6", "tc7"))] + (Tc6Tc7 = 29, tc6_tc7) + (Adc0 = 30, adc) + (AcDig = 31, ac_dig) + (AcAna = 32, ac_ana) + (Dac = 33, dac) + (Ptc = 34, ptc) + #[hal_cfg("i2s")] + (I2S0 = 35, i2s0) + #[hal_cfg("i2s")] + (I2S1 = 36, i2s1) + ); + }; +} + +#[hal_cfg("clock-d11")] +#[hal_macro_helper] +macro_rules! with_pclk_types_ids { + ( $some_macro:ident ! ( $( $args:tt )* ) ) => { + $some_macro!( + $( $args )* + (DfllId = 0, dfll) + (Dpll0Id = 1, dpll) + (SlowClk = 2, slow) + (Wdt = 3, wdt) + (Rtc = 4, rtc) + (Eic = 5, eic) + (Usb = 6, usb) + (EvSys0 = 7, ev_sys0) + (EvSys1 = 8, ev_sys1) + (EvSys2 = 9, ev_sys2) + (EvSys3 = 10, ev_sys3) + (EvSys4 = 11, ev_sys4) + (EvSys5 = 12, ev_sys5) + (SercomSlow = 13, sercom_slow) + (Sercom0 = 14, sercom0) + (Sercom1 = 15, sercom1) + #[hal_cfg("sercom2")] + (Sercom2 = 16, sercom2) + (Tcc0 = 17, tcc0) + (Tc1Tc2 = 18, tc1_tc2) + (Adc0 = 19, adc) + (AcDig = 20, ac_dig) + (AcAna = 21, ac_ana) + (Dac = 22, dac) + (Ptc = 23, ptc) + ); + }; +} + //============================================================================== // DynPclkId //============================================================================== From 9e188d4e2508859450c4deecf1917afb3e600c86 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 27 Jul 2025 19:24:53 +1200 Subject: [PATCH 076/114] stash 4 - xosc and xosc32k --- hal/src/clock/v2/xosc.rs | 18 ++++++++++++------ hal/src/clock/v2/xosc32k.rs | 13 ++++++++++--- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index e5b03253263f..55ac7e2c0ec7 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -212,7 +212,6 @@ use typenum::U0; #[hal_cfg("clock-d5x")] mod imports { pub use super::super::dfll::DfllId; - pub use crate::gpio::{PB22, PB23}; pub use crate::pac::Oscctrl as Peripheral; pub use crate::pac::oscctrl::{Xoscctrl, status::R as STATUS_R}; pub use crate::typelevel::{Decrement, Increment}; @@ -226,7 +225,14 @@ mod imports { use imports::*; -use crate::gpio::{FloatingDisabled, PA14, PA15, Pin, PinId}; +#[hal_cfg("clock-d11")] +pub use crate::gpio::{PA08 as XIn0Id, PA09 as XOut0Id}; +#[hal_cfg("clock-d21")] +pub use crate::gpio::{PA14 as XIn0Id, PA15 as XOut0Id}; +#[hal_cfg("clock-d5x")] +pub use crate::gpio::{PA14 as XIn0Id, PA15 as XOut0Id, PB22 as XIn1Id, PB23 as XOut1Id}; + +use crate::gpio::{FloatingDisabled, Pin, PinId}; use crate::time::Hertz; use crate::typelevel::Sealed; @@ -478,8 +484,8 @@ impl Sealed for Xosc0Id {} impl XoscId for Xosc0Id { const NUM: usize = 0; - type XIn = PA14; - type XOut = PA15; + type XIn = XIn0Id; + type XOut = XOut0Id; } /// Type-level variant of [`XoscId`] representing the identity of XOSC1 @@ -498,8 +504,8 @@ impl Sealed for Xosc1Id {} #[hal_cfg("clock-d5x")] impl XoscId for Xosc1Id { const NUM: usize = 1; - type XIn = PB22; - type XOut = PB23; + type XIn = XIn1Id; + type XOut = XOut1Id; } //============================================================================== diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index 92e61ca9bc90..4df5386e3157 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -362,7 +362,14 @@ mod imports { use imports::*; -use crate::gpio::{FloatingDisabled, PA00, PA01, Pin}; +#[hal_cfg("clock-d21")] +pub use crate::gpio::{PA00 as XIn32Id, PA01 as XOut32Id}; +#[hal_cfg("clock-d5x")] +pub use crate::gpio::{PA00 as XIn32Id, PA01 as XOut32Id}; +#[hal_cfg("clock-d11")] +pub use crate::gpio::{PA08 as XIn32Id, PA09 as XOut32Id}; + +use crate::gpio::{FloatingDisabled, Pin}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; @@ -680,10 +687,10 @@ impl Default for Settings { //============================================================================== /// Type alias for the XOSC32K input [`Pin`] -pub type XIn32 = Pin; +pub type XIn32 = Pin; /// Type alias for the XOSC32K output [`Pin`] -pub type XOut32 = Pin; +pub type XOut32 = Pin; //============================================================================== // SafeClockDiv From 2e74a2e659ef11644058efe3e1b062c58454541d Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 27 Jul 2025 21:59:08 +1200 Subject: [PATCH 077/114] Remove nvmctrl from GCLK init f/u stash 4 reset --- hal/src/clock/v2/gclk.rs | 7 +------ hal/src/clock/v2/reset_thumbv7em.rs | 8 +++----- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index ac6ac474a123..7ad12d059e64 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -343,7 +343,6 @@ use paste::paste; use typenum::{U0, U1}; use crate::pac; -use crate::pac::Nvmctrl; use crate::gpio::{self, AlternateH, AnyPin, Pin, PinId}; use crate::pac::gclk::Genctrl; @@ -1528,11 +1527,7 @@ impl GclkTokens { /// All of the invariants required by `GclkToken::new` must be /// upheld here as well. #[inline] - #[allow(unreachable_code)] // TODO remove when todo is removed - pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { - // Use auto wait states - //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); - todo!(); + pub(super) unsafe fn new() -> Self { GclkTokens { gclk0: unsafe { GclkToken::new() }, gclk1: unsafe { GclkToken::new() }, diff --git a/hal/src/clock/v2/reset_thumbv7em.rs b/hal/src/clock/v2/reset_thumbv7em.rs index 6cc535a263a7..b18f607c744f 100644 --- a/hal/src/clock/v2/reset_thumbv7em.rs +++ b/hal/src/clock/v2/reset_thumbv7em.rs @@ -5,7 +5,7 @@ use atsamd_hal_macros::hal_cfg; use typenum::U1; -use crate::pac::{Gclk, Mclk, Nvmctrl, Osc32kctrl, Oscctrl}; +use crate::pac::{Gclk, Mclk, Osc32kctrl, Oscctrl}; use super::*; @@ -177,7 +177,6 @@ pub fn clock_system_at_reset( osc32kctrl: Osc32kctrl, gclk: Gclk, mclk: Mclk, - nvmctrl: &mut Nvmctrl, ) -> (Buses, Clocks, Tokens) { // Safety: No bus, clock or token is instantiated more than once unsafe { @@ -211,7 +210,7 @@ pub fn clock_system_at_reset( apbs: apb::ApbTokens::new(), dpll0: dpll::DpllToken::new(), dpll1: dpll::DpllToken::new(), - gclks: gclk::GclkTokens::new(nvmctrl), + gclks: gclk::GclkTokens::new(), pclks: pclk::PclkTokens::new(), rtcosc: rtcosc::RtcOscToken::new(), xosc0: xosc::XoscToken::new(), @@ -230,7 +229,6 @@ pub fn clock_system_at_reset( osc32kctrl: Osc32kctrl, gclk: Gclk, mclk: Mclk, - nvmctrl: &mut Nvmctrl, ) -> (Buses, Clocks, Tokens) { // Safety: No bus, clock or token is instantiated more than once unsafe { @@ -266,7 +264,7 @@ pub fn clock_system_at_reset( apbs: apb::ApbTokens::new(), dpll0: dpll::DpllToken::new(), dpll1: dpll::DpllToken::new(), - gclks: gclk::GclkTokens::new(nvmctrl), + gclks: gclk::GclkTokens::new(), pclks: pclk::PclkTokens::new(), rtcosc: rtcosc::RtcOscToken::new(), xosc0: xosc::XoscToken::new(), From 2cd47c2ecc8141d5e87aa04c089eefb7b0c10143 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 27 Jul 2025 22:14:24 +1200 Subject: [PATCH 078/114] Fix thumbv6 reset detail --- hal/src/clock/v2/reset_thumbv6m.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index ead7f4a858d1..b2dc0b419ace 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -143,7 +143,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl }; let pac = Pac { gclk, pm, sysctrl }; let osc = Enabled::<_, U0>::new(osc::Osc::new(osc::OscToken::new())); - let (gclk0, osc8m) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc); + let (gclk0, osc) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc); let gclk0 = Enabled::new(gclk0); let base = osculp32k::OscUlp32kBase::new(); let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); From 4c5afb9a65e869ee6a8024c3d20fe480ddcb8366 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 27 Jul 2025 22:16:29 +1200 Subject: [PATCH 079/114] more stash 4 - gclk --- hal/src/clock/v2/gclk.rs | 50 +++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 7ad12d059e64..f67d7c9928d9 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -354,6 +354,8 @@ use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, use super::dfll::DfllId; // use super::dpll::{Dpll0Id, Dpll1Id}; +#[hal_cfg(any("clock-d11", "clock-d21"))] +use super::osc::OscId; use super::osculp32k::OscUlp32kId; use super::xosc::Xosc0Id; #[hal_cfg("clock-d5x")] @@ -893,15 +895,22 @@ impl> Gclk0Io for I {} /// a given [`Gclk`]. /// /// `DynGclkSourceId` is the value-level equivalent of [`GclkSourceId`]. +#[hal_macro_helper] #[derive(Copy, Clone, PartialEq, Eq)] pub enum DynGclkSourceId { Dfll, Dpll0, + #[hal_cfg("clock-d5x")] Dpll1, Gclk1, GclkIn, + #[hal_cfg(any("clock-d11", "clock-d21"))] + Osc8M, + #[hal_cfg(any("clock-d11", "clock-d21"))] + Osc32k, OscUlp32k, Xosc0, + #[hal_cfg("clock-d5x")] Xosc1, Xosc32k, } @@ -909,31 +918,31 @@ pub enum DynGclkSourceId { impl From for Srcselect { #[hal_cfg("clock-d5x")] fn from(source: DynGclkSourceId) -> Self { - use DynGclkSourceId::*; match source { - Dfll => Srcselect::Dfll, - Dpll0 => Srcselect::Dpll0, - Dpll1 => Srcselect::Dpll1, - Gclk1 => Srcselect::Gclkgen1, - GclkIn => Srcselect::Gclkin, - OscUlp32k => Srcselect::Osculp32k, - Xosc0 => Srcselect::Xosc0, - Xosc1 => Srcselect::Xosc1, - Xosc32k => Srcselect::Xosc32k, + DynGclkSourceId::Dfll => Srcselect::Dfll, + DynGclkSourceId::Dpll0 => Srcselect::Dpll0, + DynGclkSourceId::Dpll1 => Srcselect::Dpll1, + DynGclkSourceId::Gclk1 => Srcselect::Gclkgen1, + DynGclkSourceId::GclkIn => Srcselect::Gclkin, + DynGclkSourceId::OscUlp32k => Srcselect::Osculp32k, + DynGclkSourceId::Xosc0 => Srcselect::Xosc0, + DynGclkSourceId::Xosc1 => Srcselect::Xosc1, + DynGclkSourceId::Xosc32k => Srcselect::Xosc32k, } } #[hal_cfg(any("clock-d11", "clock-d21"))] fn from(source: DynGclkSourceId) -> Self { - use DynGclkSourceId::*; match source { - Dfll => Srcselect::Dfll48m, - Dpll => Srcselect::Dpll96m, - Gclk1 => Srcselect::Gclkgen1, - GclkIn => Srcselect::Gclkin, - OscUlp32k => Srcselect::Osculp32k, - Xosc => Srcselect::Xosc, - Xosc32k => Srcselect::Xosc32k, + DynGclkSourceId::Dfll => Srcselect::Dfll48m, + DynGclkSourceId::Dpll0 => Srcselect::Dpll96m, + DynGclkSourceId::Gclk1 => Srcselect::Gclkgen1, + DynGclkSourceId::GclkIn => Srcselect::Gclkin, + DynGclkSourceId::Osc8M => Srcselect::Osc8m, + DynGclkSourceId::Osc32k => Srcselect::Osc32k, + DynGclkSourceId::OscUlp32k => Srcselect::Osculp32k, + DynGclkSourceId::Xosc0 => Srcselect::Xosc, + DynGclkSourceId::Xosc32k => Srcselect::Xosc32k, } } } @@ -991,6 +1000,11 @@ impl GclkSourceId for OscUlp32kId { const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; type Resource = (); } +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl GclkSourceId for OscId { + const DYN: DynGclkSourceId = DynGclkSourceId::Osc8M; + type Resource = (); +} impl GclkSourceId for Xosc0Id { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; type Resource = (); From c547c3b5fe15410c93450c06e0e76d91c7d0f461 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jul 2025 15:42:05 +1200 Subject: [PATCH 080/114] stash 5 - osc32k --- hal/src/clock/v2.rs | 4 + hal/src/clock/v2/osc32k.rs | 591 +++++++++++++++++++++++++++++ hal/src/clock/v2/reset_thumbv6m.rs | 3 + 3 files changed, 598 insertions(+) create mode 100644 hal/src/clock/v2/osc32k.rs diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index a998a14d758f..eb689d63b6cb 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -870,6 +870,10 @@ pub mod gclk; any("clock-d11", "clock-d21") => "v2/osc.rs", )] pub mod osc {} +#[hal_module( + "sysctrl" => "v2/osc32k.rs", +)] +pub mod osc32k {} pub mod osculp32k; pub mod pclk; #[hal_module( diff --git a/hal/src/clock/v2/osc32k.rs b/hal/src/clock/v2/osc32k.rs new file mode 100644 index 000000000000..7e1c49f0b698 --- /dev/null +++ b/hal/src/clock/v2/osc32k.rs @@ -0,0 +1,591 @@ +//! # Tunable, low-speed and low-power clock source +//! +//! ## Overview +//! +//! TODO this documentation is for the SAMD51 version, not the SYSCTRL sub-peripheral +//! +//! The `osc32k` module provides access to the 32 kHz ultra low power +//! internal oscillator (OSC32K) within the `OSC32KCTRL` peripheral. +//! +//! The `OSC32K` clock is unlike most other clocks. First, it is an internal +//! clock that is always enabled and can't be disabled. And second, it has two +//! separate outputs, one at 32 kHz and another divided down to 1 kHz. Moreover, +//! none, either or both of these outputs can be enabled at any given time. +//! +//! We can see, then, that the `OSC32K` peripheral forms its own, miniature +//! clock tree. There is a 1:N producer clock that is always enabled; and there +//! are two possible consumer clocks that can be independently and optionally +//! enabled. In fact, this structure is illustrated by the `OSC32K` +//! register, which has no regular `ENABLE` bit and two different enable bits +//! for clock output, `EN32K` and `EN1K`. +//! +//! To represent this structure in the type system, we divide the `OSC32K` +//! peripheral into these three clocks. Users get access to the 1:N +//! [`EnabledOsc32kBase`] clock [`Source`] at power-on reset, which can be +//! consumed by both the [`Osc32k`] and [`Osc1k`] clocks. Note that +//! `Osc32k` and `Osc1k` are themselves 1:N clocks as well. +//! +//! ## Write lock +//! +//! Rhe `OSC32K` register has a dedicated write lock bit that will freeze its +//! configuration until the next power-on reset. We implement this by simply +//! dropping the [`Osc32kBase`] clock, which prevents any further access to +//! the `OSC32K` register. +//! +//! ## Example +//! +//! Creating and configuring the OSC32K clocks proceeds according to the +//! principles outlined in the [`clock` module documentation]. It is best shown +//! with an example. +//! +//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking +//! structs. +//! +//! ```no_run +//! use atsamd_hal::{ +//! clock::v2::{ +//! clock_system_at_reset, +//! osc32k::{Osc1k, Osc32k}, +//! }, +//! pac::Peripherals, +//! }; +//! let mut pac = Peripherals::take().unwrap(); +//! let (buses, clocks, tokens) = clock_system_at_reset( +//! pac.OSCCTRL, +//! pac.OSC32KCTRL, +//! pac.GCLK, +//! pac.MCLK, +//! &mut pac.NVMCTRL, +//! ); +//! ``` +//! +//! Next, we can extract the [`EnabledOsc32kBase`] clock from the [`Clocks`] +//! struct and use it to enable the [`Osc1k`] and [`Osc32k`] clocks. +//! +//! ```no_run +//! # use atsamd_hal::{ +//! # clock::v2::{ +//! # clock_system_at_reset, +//! # osc32k::{Osc1k, Osc32k}, +//! # }, +//! # pac::Peripherals, +//! # }; +//! # let mut pac = Peripherals::take().unwrap(); +//! # let (buses, clocks, tokens) = clock_system_at_reset( +//! # pac.OSCCTRL, +//! # pac.OSC32KCTRL, +//! # pac.GCLK, +//! # pac.MCLK, +//! # &mut pac.NVMCTRL, +//! # ); +//! let base = clocks.osc32k_base; +//! let (osc1k, base) = Osc1k::enable(tokens.osc32k.osc1k, base); +//! let (osc32k, base) = Osc32k::enable(tokens.osc32k.osc32k, base); +//! ``` +//! +//! We can then override the calibration value read from flash at start up. +//! +//! ```no_run +//! # use atsamd_hal::{ +//! # clock::v2::{ +//! # clock_system_at_reset, +//! # osc32k::{Osc1k, Osc32k}, +//! # }, +//! # pac::Peripherals, +//! # }; +//! # let mut pac = Peripherals::take().unwrap(); +//! # let (buses, clocks, tokens) = clock_system_at_reset( +//! # pac.OSCCTRL, +//! # pac.OSC32KCTRL, +//! # pac.GCLK, +//! # pac.MCLK, +//! # &mut pac.NVMCTRL, +//! # ); +//! # let base = clocks.osc32k_base; +//! # let (osc1k, base) = Osc1k::enable(tokens.osc32k.osc1k, base); +//! # let (osc32k, mut base) = Osc32k::enable(tokens.osc32k.osc32k, base); +//! base.set_calibration(128); +//! ``` +//! +//! And finally, we can set the write lock bit to freeze the configuation until +//! the next power-on reset. Doing so also drops the `EnabledOsc32kBase` +//! clock. +//! +//! ```no_run +//! # use atsamd_hal::{ +//! # clock::v2::{ +//! # clock_system_at_reset, +//! # osc32k::{Osc1k, Osc32k}, +//! # }, +//! # pac::Peripherals, +//! # }; +//! # let mut pac = Peripherals::take().unwrap(); +//! # let (buses, clocks, tokens) = clock_system_at_reset( +//! # pac.OSCCTRL, +//! # pac.OSC32KCTRL, +//! # pac.GCLK, +//! # pac.MCLK, +//! # &mut pac.NVMCTRL, +//! # ); +//! # let base = clocks.osc32k_base; +//! # let (osc1k, base) = Osc1k::enable(tokens.osc32k.osc1k, base); +//! # let (osc32k, mut base) = Osc32k::enable(tokens.osc32k.osc32k, base); +//! # base.set_calibration(128); +//! base.write_lock(); +//! ``` +//! +//! The complete example is shown below. +//! +//! ```no_run +//! use atsamd_hal::{ +//! clock::v2::{ +//! clock_system_at_reset, +//! osc32k::{Osc1k, Osc32k}, +//! }, +//! pac::Peripherals, +//! }; +//! let mut pac = Peripherals::take().unwrap(); +//! let (buses, clocks, tokens) = clock_system_at_reset( +//! pac.OSCCTRL, +//! pac.OSC32KCTRL, +//! pac.GCLK, +//! pac.MCLK, +//! &mut pac.NVMCTRL, +//! ); +//! let base = clocks.osc32k_base; +//! let (osc1k, base) = Osc1k::enable(tokens.osc32k.osc1k, base); +//! let (osc32k, mut base) = Osc32k::enable(tokens.osc32k.osc32k, base); +//! base.set_calibration(128); +//! base.write_lock(); +//! ``` +//! +//! [`clock` module documentation]: super +//! [`clock_system_at_reset`]: super::clock_system_at_reset +//! [`Clocks`]: super::Clocks + +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; + +use typenum::U0; + +use crate::pac::sysctrl::Osc32k as OSC32K; + +use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement}; + +use fugit::RateExtU32; +use crate::time::Hertz; +use crate::typelevel::Sealed; + +use super::{Enabled, Source}; + +//============================================================================== +// Tokens +//============================================================================== + +/// Singleton token for the [`Osc32kBase`] clock +// +// There should never be more than one instance of `Osc32kBaseToken`, because +// it relies on that fact for memory safety. +// +// Users never see `Osc32kBaseToken`, because the OSC32K base oscillator +// is always enabled. Internally, however, it is used as a register interface. +// The token is zero-sized, so it can be carried by clock types without +// introducing any memory bloat. +// +// As part of that register interface, the `Osc32kBaseToken` can access the +// `OSC32K` register. That the token is a singleton guarantees the register +// is written from only one location. This allows the token to be `Sync`, even +// though the PAC `OSC32KCTRL` struct is not. +pub struct Osc32kBaseToken(()); + +/// Singleton token that can be exchanged for [`Osc1k`] +/// +/// As explained in the [`clock` module documentation](super), instances of +/// various `Token` types can be exchanged for actual clock types. They +/// typically represent clocks that are disabled at power-on reset. +/// +/// The [`Osc1k`] clock is disabled at power-on reset. To use it, you must +/// first exchange the token for an actual clock with [`Osc1k::enable`]. + +#[hal_cfg("sysctrl-d11")] +pub struct Osc1kToken(()); + +/// Singleton token that can be exchanged for [`Osc32k`] +/// +/// As explained in the [`clock` module documentation](super), instances of +/// various `Token` types can be exchanged for actual clock types. They +/// typically represent clocks that are disabled at power-on reset. +/// +/// The [`Osc32k`] clock is disabled at power-on reset. To use it, you must +/// first exchange the token for an actual clock with [`Osc32k::enable`]. +pub struct Osc32kToken(()); + +/// Set of tokens representing the disabled OSC32K clocks power-on reset +#[hal_macro_helper] +pub struct Osc32kTokens { + pub base: Osc32kBaseToken, + #[hal_cfg("sysctrl-d11")] + pub osc1k: Osc1kToken, + pub osc32k: Osc32kToken, +} + +impl Osc32kTokens { + /// Create the set of tokens + /// + /// # Safety + /// + /// There must never be more than one instance of each token at any given + /// time. See the notes on `Token` types and memory safety in the root of + /// the `clock` module for more details. + #[allow(unused)] + #[hal_macro_helper] + pub(super) unsafe fn new() -> Self { + Self { + base: Osc32kBaseToken(()), + #[hal_cfg("sysctrl-d11")] + osc1k: Osc1kToken(()), + osc32k: Osc32kToken(()), + } + } +} + +impl Osc32kBaseToken { + #[inline] + fn osc32k(&self) -> &OSC32K { + // Safety: The `Osc32kBaseToken` has exclusive access to the + // `OSC32K` register. See the notes on `Token` types and memory + // safety in the root of the `clock` module for more details. + unsafe { &(*crate::pac::Sysctrl::PTR).osc32k() } + } + + /// Set the calibration + #[inline] + fn set_calibration(&mut self, calib: u8) { + // Safety: All bit patterns are valid for this field + self.osc32k() + .modify(|_, w| unsafe { w.calib().bits(calib) }); + } + + #[inline] + fn enable(&mut self, settings: Settings) { + self.osc32k().modify(|_, w| { + // Safety: The value comes from the `StartUpDelay` enum, + // so the value is guaranteed to be valid + unsafe { w.startup().bits(settings.start_up as u8) }; + w.ondemand().bit(settings.on_demand); + w.runstdby().bit(settings.run_standby); + w.enable().set_bit() + }); + } + + #[inline] + fn disable(&mut self) { + self.osc32k().modify(|_, w| w.enable().clear_bit()); + } + + /// Enable the 1 kHz output + #[hal_cfg("sysctrl-d11")] + #[inline] + fn enable_1k(&mut self) { + self.osc32k().modify(|_, w| w.en1k().set_bit()); + } + + /// Disable the 1 kHz output + #[hal_cfg("sysctrl-d11")] + #[inline] + fn disable_1k(&mut self) { + self.osc32k().modify(|_, w| w.en1k().clear_bit()); + } + + /// Enable the 32 kHz output + #[inline] + fn enable_32k(&mut self) { + self.osc32k().modify(|_, w| w.en32k().set_bit()); + } + + /// Disable the 32 kHz output + #[inline] + fn disable_32k(&mut self) { + self.osc32k().modify(|_, w| w.en32k().clear_bit()); + } + + /// Enable the write lock + #[inline] + fn write_lock(&mut self) { + self.osc32k().modify(|_, w| w.wrtlock().set_bit()); + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +struct Settings { + start_up: StartUpDelay, + on_demand: bool, + run_standby: bool, +} + +//============================================================================== +// StartUpDelay +//============================================================================== + +#[repr(u8)] +#[derive(Clone, Copy, Default, PartialEq, Eq)] +pub enum StartUpDelay { + #[default] + Delay92us, + Delay122us, + Delay183us, + Delay305us, + Delay549us, + Delay1ms, + Delay2ms, + Delay4ms, +} + +//============================================================================== +// OscBase +//============================================================================== + +/// OSC3ULP2K base clock, which feeds the [`Osc1k`] and [`Osc32k`] clocks +/// +/// The OSC32K peripheral has two possible clock outputs, one at 32 kHz and +/// another at 1 kHz. This structure is represented in the type system as a set +/// of three clocks forming a small clock tree. The [`Osc32kBase`] clock +/// represents the base oscillator that feeds the optional [`Osc1k`] and +/// [`Osc32k`] output clocks. See the [module-level documentation](super) for +/// details and examples. +pub struct Osc32kBase { + token: Osc32kBaseToken, + settings: Settings, +} + +/// The [`Enabled`] [`Osc32kBase`] clock +/// +/// As described in the [`clock` module documentation](super), the [`Enabled`] +/// wrapper implements compile-time clock tree safety by tracking the number of +/// clocks consuming the [`Osc32kBase`] clock and restricts access to the +/// underlying type to prevent misuse. +/// +/// **NOTE:** The `Osc32kBase` clock is internal and can never be disabled, +/// so we do not provide a `disable` method. +/// +/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified, +/// the counter is assumed to be zero. +pub type EnabledOsc32kBase = Enabled; + +impl Osc32kBase { + /// Create the ultra-low power base oscillator + /// + /// # Safety + /// + /// Because an `Osc32kBase` contains an `Osc32kBaseToken`, there must + /// never be more than one instance of this struct at any given time. See + /// the notes on `Token` types and memory safety in the root of the `clock` + /// module for more details. + #[inline] + pub fn new(token: Osc32kBaseToken) -> Self { + let settings = Settings { + start_up: StartUpDelay::Delay92us, + on_demand: true, + run_standby: false, + }; + Self { token, settings } + } + + pub fn start_up_delay(mut self, start_up: StartUpDelay) -> Self { + self.settings.start_up = start_up; + self + } + + pub fn on_demand(mut self, on_demand: bool) -> Self { + self.settings.on_demand = on_demand; + self + } + + pub fn run_standby(mut self, run_standby: bool) -> Self { + self.settings.run_standby = run_standby; + self + } + + #[inline] + pub fn enable(mut self) -> EnabledOsc32kBase { + self.token.enable(self.settings); + Enabled::new(self) + } +} + +impl EnabledOsc32kBase { + #[inline] + pub fn disable(mut self) -> Osc32kBase { + self.0.token.disable(); + self.0 + } + + /// Override the factory-default calibration value + #[inline] + pub fn set_calibration(&mut self, calib: u8) { + self.0.token.set_calibration(calib); + } + + /// Freeze the OSC32K configuration until power-on reset + /// + /// This function sets the write-lock bit, which freezes the OSC32K + /// configuration at the hardware level until power-on reset. At the API + /// level, it also consumes and drops the [`Osc32kBase`] clock, which + /// prevents any further modifications. + #[inline] + pub fn write_lock(mut self) { + self.0.token.write_lock(); + } +} + +//============================================================================== +// Ids +//============================================================================== + +/// Type representing the identity of the [`Osc1k`] clock +/// +/// See the discussion on [`Id` types](super#id-types) for more information. +#[hal_cfg("sysctrl-d11")] +pub enum Osc1kId {} + +#[hal_cfg("sysctrl-d11")] +impl Sealed for Osc1kId {} + +/// Type representing the identity of the [`Osc32k`] clock +/// +/// See the discussion on [`Id` types](super#id-types) for more information. +pub enum Osc32kId {} + +impl Sealed for Osc32kId {} + +//============================================================================== +// Osc1k +//============================================================================== + +/// Clock representing the 1 kHz output of the [`Osc32kBase`] clock +/// +/// The OSC32K peripheral has two possible clock outputs, one at 32 kHz and +/// another at 1 kHz. This structure is represented in the type system as a set +/// of three clocks forming a small clock tree. The [`Osc1k`] clock is +/// derived from the [`Osc32kBase`] clock. See the +/// [module-level documentation](super) for details and examples. +#[hal_cfg("sysctrl-d11")] +pub struct Osc1k { + #[allow(unused)] + token: Osc1kToken, +} + +/// The [`Enabled`] [`Osc1k`] clock +/// +/// As described in the [`clock` module documentation](super), the [`Enabled`] +/// wrapper implements compile-time clock tree safety by tracking the number of +/// clocks consuming the [`Osc1k`] clock and restricts access to the +/// underlying type to prevent misuse. +/// +/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified, +/// the counter is assumed to be zero. +#[hal_cfg("sysctrl-d11")] +pub type EnabledOsc1k = Enabled; + +#[hal_cfg("sysctrl-d11")] +impl Osc1k { + /// Enable 1 kHz output from the [`Osc32kBase`] clock + /// + /// This will [`Increment`] the [`EnabledOsc32kBase`] counter. + #[inline] + pub fn enable( + token: Osc1kToken, + mut base: EnabledOsc32kBase, + ) -> (EnabledOsc1k, EnabledOsc32kBase) { + base.0.token.enable_1k(); + (Enabled::new(Self { token }), base.inc()) + } +} + +#[hal_cfg("sysctrl-d11")] +impl EnabledOsc1k { + /// Disable 1 kHz output from the [`Osc32kBase`] clock + /// + /// This will [`Decrement`] the [`EnabledOsc32kBase`] counter. + #[inline] + pub fn disable( + self, + mut base: EnabledOsc32kBase, + ) -> (Osc1kToken, EnabledOsc32kBase) { + base.0.token.disable_1k(); + (self.0.token, base.dec()) + } +} + +#[hal_cfg("sysctrl-d11")] +impl Source for EnabledOsc1k { + type Id = Osc1kId; + + #[inline] + fn freq(&self) -> Hertz { + Hertz(1024) + } +} + +//============================================================================== +// Osc32k +//============================================================================== + +/// Clock representing the 32 kHz output of the [`Osc32kBase`] clock +/// +/// The OSC32K peripheral has two possible clock outputs, one at 32 kHz and +/// another at 1 kHz. This structure is represented in the type system as a set +/// of three clocks forming a small clock tree. The [`Osc32k`] clock is +/// derived from the [`Osc32kBase`] clock. See the +/// [module-level documentation](super) for details and examples. +pub struct Osc32k { + #[allow(unused)] + token: Osc32kToken, +} + +/// The [`Enabled`] [`Osc32k`] clock +/// +/// As described in the [`clock` module documentation](super), the [`Enabled`] +/// wrapper implements compile-time clock tree safety by tracking the number of +/// clocks consuming the [`Osc32k`] clock and restricts access to the +/// underlying type to prevent misuse. +/// +/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified, +/// the counter is assumed to be zero. +pub type EnabledOsc32k = Enabled; + +impl Osc32k { + /// Enable 32 kHz output from the [`Osc32kBase`] clock + /// + /// This will [`Increment`] the [`EnabledOsc32kBase`] counter. + #[inline] + pub fn enable( + token: Osc32kToken, + mut base: EnabledOsc32kBase, + ) -> (EnabledOsc32k, EnabledOsc32kBase) { + base.0.token.enable_32k(); + (Enabled::new(Self { token }), base.inc()) + } +} + +impl EnabledOsc32k { + /// Disable 32 kHz output from the [`Osc32kBase`] clock + /// + /// This will [`Decrement`] the [`EnabledOsc32kBase`] counter. + #[inline] + pub fn disable( + self, + mut base: EnabledOsc32kBase, + ) -> (Osc32kToken, EnabledOsc32kBase) { + base.0.token.disable_32k(); + (self.0.token, base.dec()) + } +} + +impl Source for EnabledOsc32k { + type Id = Osc32kId; + + #[inline] + fn freq(&self) -> Hertz { + 32_768u32.Hz() + } +} diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index b2dc0b419ace..fef3159264e3 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -119,6 +119,8 @@ pub struct Tokens { pub gclks: gclk::GclkTokens, /// Tokens to create [`pclk::Pclk`]s pub pclks: pclk::PclkTokens, + /// Tokens to create the [`osc32k::Osc1k`] and [`osc32k::Osc32k`] clocks + pub osc32k: osc32k::Osc32kTokens, /// Tokens [`xosc::Xosc0`] pub xosc: xosc::XoscToken, /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and @@ -172,6 +174,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl dpll: dpll::DpllToken::new(), gclks: gclk::GclkTokens::new(), pclks: pclk::PclkTokens::new(), + osc32k: osc32k::Osc32kTokens::new(), xosc: xosc::XoscToken::new(), xosc32k: xosc32k::Xosc32kTokens::new(), }; From b3313a6fef626aef7c2ab2c6510461097639ddc3 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Mon, 28 Jul 2025 11:08:29 +1200 Subject: [PATCH 081/114] stash 5 - reset, stash 5 - osculp32k --- hal/src/clock/v2/osculp32k.rs | 78 +++++++++---------- hal/src/clock/v2/reset_thumbv6m.rs | 14 ++-- hal/src/clock/v2/reset_thumbv7em.rs | 113 ++++------------------------ 3 files changed, 54 insertions(+), 151 deletions(-) diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index b4bc968b71ea..916b4383b2e7 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -3,7 +3,8 @@ //! ## Overview //! //! The `osculp32k` module provides access to the 32 kHz ultra low power -//! internal oscillator (OSCULP32K) within the `OSC32KCTRL` peripheral. +//! internal oscillator (OSCULP32K) within the `OSC32KCTRL` or `SYSCTRL` +//! peripheral. //! //! The `OSCULP32K` clock is unlike most other clocks. First, it is an internal //! clock that is always enabled and can't be disabled. And second, it has two @@ -13,9 +14,9 @@ //! We can see, then, that the `OSCULP32K` peripheral forms its own, miniature //! clock tree. There is a 1:N producer clock that is always enabled; and there //! are two possible consumer clocks that can be independently and optionally -//! enabled. In fact, this structure is illustrated by the `OSCULP32K` -//! register, which has no regular `ENABLE` bit and two different enable bits -//! for clock output, `EN32K` and `EN1K`. +//! enabled. In fact, this structure is illustrated by the `OSCULP32K` register, +//! which has no regular `ENABLE` bit and two different enable bits for clock +//! output, `EN32K` and `EN1K`. //! //! To represent this structure in the type system, we divide the `OSCULP32K` //! peripheral into these three clocks. Users get access to the 1:N @@ -165,21 +166,16 @@ use atsamd_hal_macros::hal_cfg; use fugit::RateExtU32; use typenum::U0; -#[hal_cfg("clock-d5x")] -mod imports { - pub use crate::pac::osc32kctrl::Osculp32k; - pub use crate::typelevel::{Decrement, Increment}; -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -mod imports { - pub use crate::pac::sysctrl::Osculp32k; -} +#[hal_cfg("osc32kctrl")] +use crate::pac::osc32kctrl::Osculp32k; +#[hal_cfg("osc32kctrl")] +use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement}; -use imports::*; +#[hal_cfg("sysctrl")] +use crate::pac::sysctrl::Osculp32k; use crate::time::Hertz; -use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; +use crate::typelevel::Sealed; use super::{Enabled, Source}; @@ -223,39 +219,17 @@ pub struct OscUlp1kToken(()); /// first exchange the token for an actual clock with [`OscUlp32k::enable`]. pub struct OscUlp32kToken(()); -/// Set of tokens representing the disabled OSCULP32K clocks power-on reset -pub struct OscUlp32kTokens { - pub osculp1k: OscUlp1kToken, - pub osculp32k: OscUlp32kToken, -} - -impl OscUlp32kTokens { - /// Create the set of tokens - /// - /// # Safety - /// - /// There must never be more than one instance of each token at any given - /// time. See the notes on `Token` types and memory safety in the root of - /// the `clock` module for more details. - pub(super) unsafe fn new() -> Self { - Self { - osculp1k: OscUlp1kToken(()), - osculp32k: OscUlp32kToken(()), - } - } -} - impl OscUlp32kBaseToken { #[inline] fn osculp32k(&self) -> &Osculp32k { // Safety: The `OscUlp32kBaseToken` has exclusive access to the // `OSCULP32K` register. See the notes on `Token` types and memory // safety in the root of the `clock` module for more details. - #[hal_cfg("clock-d5x")] + #[hal_cfg("osc32kctrl")] unsafe { &(*crate::pac::Osc32kctrl::PTR).osculp32k() } - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] unsafe { &(*crate::pac::Sysctrl::PTR).osculp32k() } @@ -336,9 +310,9 @@ impl OscUlp32kBase { /// the notes on `Token` types and memory safety in the root of the `clock` /// module for more details. #[inline] - pub(super) unsafe fn new() -> EnabledOscUlp32kBase { + pub(super) unsafe fn new() -> Self { let token = OscUlp32kBaseToken(()); - Enabled::new(Self { token }) + Self { token } } } @@ -401,7 +375,15 @@ pub struct OscUlp1k { pub type EnabledOscUlp1k = Enabled; impl OscUlp1k { - #[hal_cfg(any("clock-d11", "clock-d21"))] + /// Create the ultra-low power base oscillator + /// + /// # Safety + /// + /// Because an `OscUlp1k` contains an `OscUlp1kToken`, there must never be + /// more than one instance of this struct at any given time. See the notes + /// on `Token` types and memory safety in the root of the `clock` module for + /// more details. + #[inline] pub(super) unsafe fn new() -> Self { let token = OscUlp1kToken(()); Self { token } @@ -473,7 +455,15 @@ pub struct OscUlp32k { pub type EnabledOscUlp32k = Enabled; impl OscUlp32k { - #[hal_cfg(any("clock-d11", "clock-d21"))] + /// Create the ultra-low power base oscillator + /// + /// # Safety + /// + /// Because an `OscUlp32k` contains an `OscUlp32kToken`, there must never be + /// more than one instance of this struct at any given time. See the notes + /// on `Token` types and memory safety in the root of the `clock` module for + /// more details. + #[inline] pub(super) unsafe fn new() -> Self { let token = OscUlp32kToken(()); Self { token } diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index fef3159264e3..ef4ede831cb6 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -56,7 +56,7 @@ pub struct Buses { pub apb: apb::Apb, } -pub struct OscUlp32kClocks { +pub struct OscUlpClocks { pub base: osculp32k::EnabledOscUlp32kBase, pub osculp1k: osculp32k::EnabledOscUlp1k, pub osculp32k: osculp32k::EnabledOscUlp32k, @@ -93,10 +93,10 @@ pub struct Clocks { pub gclk2: Enabled, U1>, /// 8 MHz internal oscillator, divided by 8 for a 1 MHz output pub osc: Enabled, + /// Always-enabled OSCULP oscillators + pub osculp: OscUlpClocks, /// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2) pub wdt: pclk::Pclk, - /// Always-enabled OSCULP oscillators - pub osculp32k: OscUlp32kClocks, } /// Type-level tokens for unused clocks at power-on reset @@ -147,13 +147,13 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl let osc = Enabled::<_, U0>::new(osc::Osc::new(osc::OscToken::new())); let (gclk0, osc) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc); let gclk0 = Enabled::new(gclk0); - let base = osculp32k::OscUlp32kBase::new(); + let base = Enabled::new(osculp32k::OscUlp32kBase::new()); let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); - let osculp32k = Enabled::new(osculp32k::OscUlp32k::new()); + let osculp32k = Enabled::<_, U0>::new(osculp32k::OscUlp32k::new()); let (gclk2, osculp32k) = gclk::Gclk2::from_source(gclk::GclkToken::new(), osculp32k); let gclk2 = Enabled::new(gclk2); let wdt = pclk::Pclk::new(pclk::PclkToken::new(), gclk2.freq()); - let osculp32k = OscUlp32kClocks { + let osculp = OscUlpClocks { base, osculp1k, osculp32k, @@ -166,7 +166,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl gclk2, osc, wdt, - osculp32k, + osculp, }; let tokens = Tokens { apbs: apb::ApbTokens::new(), diff --git a/hal/src/clock/v2/reset_thumbv7em.rs b/hal/src/clock/v2/reset_thumbv7em.rs index b18f607c744f..acac05d7d86d 100644 --- a/hal/src/clock/v2/reset_thumbv7em.rs +++ b/hal/src/clock/v2/reset_thumbv7em.rs @@ -2,7 +2,6 @@ //! from the `v2` module, which is where the corresponding documentation will //! appear. -use atsamd_hal_macros::hal_cfg; use typenum::U1; use crate::pac::{Gclk, Mclk, Osc32kctrl, Oscctrl}; @@ -58,18 +57,10 @@ pub struct Buses { pub apb: apb::Apb, } -#[hal_cfg("clock-d5x")] -#[allow(dead_code)] -pub struct OscUlp32kClocks { - base: osculp32k::EnabledOscUlp32kBase, -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -#[allow(dead_code)] -pub struct OscUlp32kClocks { - base: osculp32k::EnabledOscUlp32kBase, - osculp1k: EnabledOscUlp1k, - osculp32k: EnabledOscUlp32k, +pub struct OscUlpClocks { + pub base: osculp32k::EnabledOscUlp32kBase, + pub osculp1k: osculp32k::EnabledOscUlp1k, + pub osculp32k: osculp32k::EnabledOscUlp32k, } /// Enabled clocks at power-on reset @@ -103,7 +94,7 @@ pub struct Clocks { pub dfll: Enabled, /// Always-enabled base oscillator for the [`OscUlp1k`](osculp32k::OscUlp1k) /// and [`OscUlp32k`](osculp32k::OscUlp32k) clocks. - pub osculp32k: OscUlp32kClocks, + pub osculp: OscUlpClocks, } /// Type-level tokens for unused clocks at power-on reset @@ -115,32 +106,6 @@ pub struct Clocks { /// As described in the [top-level](super::super) documentation for the `clock` /// module, token types are used to guanrantee the uniqueness of each clock. To /// configure or enable a clock, you must provide the corresponding token. -#[hal_cfg("clock-d5x")] -pub struct Tokens { - /// Tokens to create [`apb::ApbClk`]s - pub apbs: apb::ApbTokens, - /// Token to create [`dpll::Dpll0`] - pub dpll0: dpll::DpllToken, - /// Token to create [`dpll::Dpll1`] - pub dpll1: dpll::DpllToken, - /// Tokens to create [`gclk::Gclk`] - pub gclks: gclk::GclkTokens, - /// Tokens to create [`pclk::Pclk`]s - pub pclks: pclk::PclkTokens, - /// Tokens to create [`rtcosc::RtcOsc`] - pub rtcosc: rtcosc::RtcOscToken, - /// Tokens [`xosc::Xosc0`] - pub xosc0: xosc::XoscToken, - /// Token to create [`xosc::Xosc1`] - pub xosc1: xosc::XoscToken, - /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and - /// [`xosc32k::Xosc32k`] - pub xosc32k: xosc32k::Xosc32kTokens, - /// Tokens to create [`osculp32k::OscUlp1k`] and [`osculp32k::OscUlp32k`] - pub osculp32k: osculp32k::OscUlp32kTokens, -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] pub struct Tokens { /// Tokens to create [`apb::ApbClk`]s pub apbs: apb::ApbTokens, @@ -170,59 +135,6 @@ pub struct Tokens { /// [`Mclk`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`]. /// /// See the [module-level documentation](super) for more details. -#[hal_cfg("clock-d5x")] -#[inline] -pub fn clock_system_at_reset( - oscctrl: Oscctrl, - osc32kctrl: Osc32kctrl, - gclk: Gclk, - mclk: Mclk, -) -> (Buses, Clocks, Tokens) { - // Safety: No bus, clock or token is instantiated more than once - unsafe { - let buses = Buses { - ahb: ahb::Ahb::new(), - apb: apb::Apb::new(), - }; - let pac = Pac { - oscctrl, - osc32kctrl, - gclk, - mclk, - }; - let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new())); - let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll); - let gclk0 = Enabled::new(gclk0); - let osculp32k_clocks = { - OscUlp32kClocks { - base: osculp32k::OscUlp32kBase::new(), - } - }; - let clocks = Clocks { - pac, - ahbs: ahb::AhbClks::new(), - apbs: apb::ApbClks::new(), - gclk0, - dfll, - osculp32k: osculp32k_clocks, - }; - let tokens = Tokens { - apbs: apb::ApbTokens::new(), - dpll0: dpll::DpllToken::new(), - dpll1: dpll::DpllToken::new(), - gclks: gclk::GclkTokens::new(), - pclks: pclk::PclkTokens::new(), - rtcosc: rtcosc::RtcOscToken::new(), - xosc0: xosc::XoscToken::new(), - xosc1: xosc::XoscToken::new(), - xosc32k: xosc32k::Xosc32kTokens::new(), - osculp32k: osculp32k::OscUlp32kTokens::new(), - }; - (buses, clocks, tokens) - } -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] pub fn clock_system_at_reset( oscctrl: Oscctrl, @@ -245,12 +157,13 @@ pub fn clock_system_at_reset( let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new())); let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll); let gclk0 = Enabled::new(gclk0); - let osculp32k_clocks = { - OscUlp32kClocks { - base: osculp32k::OscUlp32kBase::new(), - osculp1k: Enabled::new(osculp32k::OscUlp1k::new()), - osculp32k: Enabled::new(osculp32k::OscUlp32k::new()), - } + let base = Enabled::new(osculp32k::OscUlp32kBase::new()); + let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); + let osculp32k = Enabled::new(osculp32k::OscUlp32k::new()); + let osculp = OscUlpClocks { + base, + osculp1k, + osculp32k, }; let clocks = Clocks { pac, @@ -258,7 +171,7 @@ pub fn clock_system_at_reset( apbs: apb::ApbClks::new(), gclk0, dfll, - osculp32k: osculp32k_clocks, + osculp, }; let tokens = Tokens { apbs: apb::ApbTokens::new(), From 52555a6ba32c49fa072803d7bdf3fa43124b24db Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Mon, 28 Jul 2025 11:31:54 +1200 Subject: [PATCH 082/114] remainder of stash 4 - gclk --- hal/src/clock/v2/gclk.rs | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index f67d7c9928d9..65646e014af1 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -399,6 +399,7 @@ impl GclkToken { } /// SYNCBUSY register mask for the corresponding GCLK + #[hal_cfg("clock-d5x")] const MASK: u16 = 1 << G::NUM; /// Provide a reference to the corresponding [`Genctrl`] register @@ -814,6 +815,7 @@ pub trait GclkIo: PinId { // These implementations are much easier to read with `#[rustfmt::skip]` #[rustfmt::skip] +#[hal_cfg("clock-d5x")] mod gclkio_impl { use atsamd_hal_macros::hal_cfg; @@ -865,6 +867,80 @@ mod gclkio_impl { impl GclkIo for gpio::PB23 { type GclkId = Gclk1Id; } } +#[rustfmt::skip] +#[hal_cfg("clock-d21")] +mod gclkio_impl { + use super::*; + + impl GclkIo for gpio::PA10 { type GclkId = Gclk4Id; } + impl GclkIo for gpio::PA11 { type GclkId = Gclk5Id; } + impl GclkIo for gpio::PA14 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA15 { type GclkId = Gclk1Id; } + impl GclkIo for gpio::PA16 { type GclkId = Gclk2Id; } + impl GclkIo for gpio::PA17 { type GclkId = Gclk3Id; } + #[hal_cfg("pa20")] + impl GclkIo for gpio::PA20 { type GclkId = Gclk4Id; } + #[hal_cfg("pa21")] + impl GclkIo for gpio::PA21 { type GclkId = Gclk5Id; } + impl GclkIo for gpio::PA22 { type GclkId = Gclk6Id; } + impl GclkIo for gpio::PA23 { type GclkId = Gclk7Id; } + #[hal_cfg("pa27")] + impl GclkIo for gpio::PA27 { type GclkId = Gclk0Id; } + #[hal_cfg("pa28")] + impl GclkIo for gpio::PA28 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA30 { type GclkId = Gclk0Id; } + + #[hal_cfg("pb10")] + impl GclkIo for gpio::PB10 { type GclkId = Gclk4Id; } + #[hal_cfg("pb11")] + impl GclkIo for gpio::PB11 { type GclkId = Gclk5Id; } + #[hal_cfg("pb12")] + impl GclkIo for gpio::PB12 { type GclkId = Gclk6Id; } + #[hal_cfg("pb13")] + impl GclkIo for gpio::PB13 { type GclkId = Gclk7Id; } + #[hal_cfg("pb14")] + impl GclkIo for gpio::PB14 { type GclkId = Gclk0Id; } + #[hal_cfg("pb15")] + impl GclkIo for gpio::PB15 { type GclkId = Gclk1Id; } + #[hal_cfg("pb16")] + impl GclkIo for gpio::PB16 { type GclkId = Gclk2Id; } + #[hal_cfg("pb17")] + impl GclkIo for gpio::PB17 { type GclkId = Gclk3Id; } + #[hal_cfg("pb22")] + impl GclkIo for gpio::PB22 { type GclkId = Gclk0Id; } + #[hal_cfg("pb23")] + impl GclkIo for gpio::PB23 { type GclkId = Gclk1Id; } +} + +#[rustfmt::skip] +#[hal_cfg("clock-d11")] +mod gclkio_impl { + use super::*; + + impl GclkIo for gpio::PA08 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA09 { type GclkId = Gclk1Id; } + #[hal_cfg("pa10")] + impl GclkIo for gpio::PA10 { type GclkId = Gclk4Id; } + #[hal_cfg("pa11")] + impl GclkIo for gpio::PA11 { type GclkId = Gclk5Id; } + impl GclkIo for gpio::PA14 { type GclkId = Gclk4Id; } + impl GclkIo for gpio::PA15 { type GclkId = Gclk5Id; } + #[hal_cfg("pa16")] + impl GclkIo for gpio::PA16 { type GclkId = Gclk2Id; } + #[hal_cfg("pa17")] + impl GclkIo for gpio::PA17 { type GclkId = Gclk3Id; } + #[hal_cfg("pa22")] + impl GclkIo for gpio::PA22 { type GclkId = Gclk1Id; } + #[hal_cfg("pa23")] + impl GclkIo for gpio::PA23 { type GclkId = Gclk2Id; } + impl GclkIo for gpio::PA24 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA25 { type GclkId = Gclk0Id; } + #[hal_cfg("pa27")] + impl GclkIo for gpio::PA27 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA30 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA31 { type GclkId = Gclk0Id; } +} + //============================================================================== // Gclk0Io //============================================================================== From bdf83f5b55cd935fc089424ff8f9c72e5cab1886 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Mon, 28 Jul 2025 13:26:36 +1200 Subject: [PATCH 083/114] Add xosc to devices table This makes a `hal_cfg()` argument available for xosc1 on bigger chips --- atsamd-hal-macros/devices.yaml | 3 +++ hal/src/clock/v2/dpll.rs | 35 ++++++++++------------------------ hal/src/clock/v2/gclk.rs | 6 +++--- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/atsamd-hal-macros/devices.yaml b/atsamd-hal-macros/devices.yaml index 667c98742e38..df6a7af81f8d 100644 --- a/atsamd-hal-macros/devices.yaml +++ b/atsamd-hal-macros/devices.yaml @@ -21,6 +21,7 @@ families: - serial-numbers - dsu - clock + - xosc: { count: 1 } - gclk: { count: 6 } - pm - sysctrl @@ -53,6 +54,7 @@ families: - serial-numbers - dsu - clock + - xosc: { count: 1 } - gclk: { count: 8 } - pm - sysctrl @@ -96,6 +98,7 @@ families: - cmcc - dsu - clock + - xosc: { count: 2 } - gclk: { count: 12 } - mclk - rstc diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index ba8b886b86e3..ab79025ef1f4 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -237,7 +237,7 @@ //! [`GclkDivider`]: super::gclk::GclkDivider //! [`Pclk`]: super::pclk::Pclk -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use fugit::RateExtU32; @@ -245,7 +245,6 @@ use typenum::U0; #[hal_cfg("clock-d5x")] mod imports { - pub use super::super::xosc::Xosc1Id; pub use crate::pac::Oscctrl as Peripheral; pub use crate::pac::oscctrl::{ Dpll as PacDpll, @@ -271,6 +270,8 @@ use crate::typelevel::{Decrement, Increment, Sealed}; use super::gclk::GclkId; use super::pclk::{Pclk, PclkId}; +#[hal_cfg("xosc1")] +use super::xosc::Xosc1Id; use super::xosc::{Xosc0Id, XoscId}; use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -360,19 +361,14 @@ impl DpllToken { #[inline] fn enable(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) { // Convert the actual predivider to the `div` register field value - #[hal_cfg("clock-d5x")] + #[hal_macro_helper] let div = match id { DynDpllSourceId::Xosc0 => prediv / 2 - 1, + #[hal_cfg("xosc1")] DynDpllSourceId::Xosc1 => prediv / 2 - 1, _ => 0, }; - #[hal_cfg(any("clock-d11", "clock-d21"))] - let div = match id { - DynDpllSourceId::Xosc0 => prediv / 2 - 1, - _ => 0, - }; - self.ctrlb().write(|w| { // Safety: The value is masked to the correct bit width by the PAC. // An invalid value could produce an invalid clock frequency, but @@ -528,20 +524,21 @@ impl DpllId for Dpll1Id { /// a given [`Dpll`]. /// /// `DynDpllSourceId` is the value-level equivalent of [`DpllSourceId`]. -#[hal_cfg("clock-d5x")] +#[hal_macro_helper] #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DynDpllSourceId { /// The DPLL is driven by a [`Pclk`] Pclk, /// The DPLL is driven by [`Xosc0`](super::xosc::Xosc0) Xosc0, + #[hal_cfg("xosc1")] /// The DPLL is driven by [`Xosc1`](super::xosc::Xosc1) Xosc1, /// The DPLL is driven by [`Xosc32k`](super::xosc32k::Xosc32k) Xosc32k, } -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] impl From for Refclkselect { fn from(source: DynDpllSourceId) -> Self { match source { @@ -553,18 +550,7 @@ impl From for Refclkselect { } } -#[hal_cfg(any("clock-d11", "clock-d21"))] -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum DynDpllSourceId { - /// The DPLL is driven by a [`Pclk`] - Pclk, - /// The DPLL is driven by [`Xosc0`](super::xosc::Xosc0) - Xosc0, - /// The DPLL is driven by [`Xosc32k`](super::xosc32k::Xosc32k) - Xosc32k, -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] +#[hal_cfg("sysctrl")] impl From for Refclkselect { fn from(source: DynDpllSourceId) -> Self { match source { @@ -574,7 +560,6 @@ impl From for Refclkselect { } } } - //============================================================================== // DpllSourceId //============================================================================== @@ -609,7 +594,7 @@ impl DpllSourceId for Xosc0Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc0; type Reference = settings::Xosc; } -#[hal_cfg("clock-d5x")] +#[hal_cfg("xosc1")] impl DpllSourceId for Xosc1Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc1; type Reference = settings::Xosc; diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 65646e014af1..3a847c99d0fd 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -358,7 +358,7 @@ use super::dfll::DfllId; use super::osc::OscId; use super::osculp32k::OscUlp32kId; use super::xosc::Xosc0Id; -#[hal_cfg("clock-d5x")] +#[hal_cfg("xosc1")] use super::xosc::Xosc1Id; use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -949,7 +949,7 @@ mod gclkio_impl { /// /// This is effectively a trait alias for [`PinId`]s that implement [`GclkIo`] /// with a `GclkId` associated type of [`Gclk0Id`], i.e. -/// `GclkIo`. The trait is useful to simply some function +/// `GclkIo`. The trait is useful to simplify some function /// signatures and to help type inference in a few cases. pub trait Gclk0Io where @@ -1085,7 +1085,7 @@ impl GclkSourceId for Xosc0Id { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; type Resource = (); } -#[hal_cfg("clock-d5x")] +#[hal_cfg("xosc1")] impl GclkSourceId for Xosc1Id { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; type Resource = (); From 8e01658983f1a3513aa6fc62b9205015d17a4859 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Mon, 28 Jul 2025 13:35:42 +1200 Subject: [PATCH 084/114] stash 5 - dpll --- hal/src/clock/v2/dpll.rs | 111 ++++++++++++++++++++++++--------------- hal/src/clock/v2/gclk.rs | 21 ++++---- 2 files changed, 81 insertions(+), 51 deletions(-) diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index ab79025ef1f4..7d033a5023d6 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -1,9 +1,10 @@ -//! # Digital Phase-Locked Loop +//! # Fractional Digital Phase-Locked Loop //! //! ## Overview //! -//! The `dpll` module provides access to the two digital phase-locked loops -//! (DPLLs) within the `OSCCTRL` peripheral. +//! The `dpll` module provides access to the digital phase-locked loops (DPLLs) +//! within the `OSCCTRL` or `SYSCTRL` peripheral, datasheets refer to these as +//! FDPLL200M and FDPLL96M, respectively. //! //! A DPLL is used to multiply clock frequencies. It takes a lower-frequency //! input clock and produces a higher-frequency output clock. It works by taking @@ -243,27 +244,25 @@ use core::marker::PhantomData; use fugit::RateExtU32; use typenum::U0; -#[hal_cfg("clock-d5x")] -mod imports { - pub use crate::pac::Oscctrl as Peripheral; - pub use crate::pac::oscctrl::{ +#[hal_cfg("oscctrl")] +use crate::pac::{ + Oscctrl as Peripheral, + oscctrl::{ Dpll as PacDpll, dpll::dpllctrlb::Refclkselect, dpll::{Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus, dpllsyncbusy}, - }; -} + }, +}; -#[hal_cfg(any("clock-d11", "clock-d21"))] -mod imports { - pub use crate::pac::Sysctrl as Peripheral; - pub use crate::pac::sysctrl::{ +#[hal_cfg("sysctrl")] +use crate::pac::{ + Sysctrl as Peripheral, + sysctrl::{ RegisterBlock as PacDpll, dpllctrlb::Refclkselect, {Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus}, - }; -} - -use imports::*; + }, +}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; @@ -317,11 +316,11 @@ impl DpllToken { // of registers for the corresponding `DpllId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] unsafe { &(*Peripheral::PTR).dpll(D::NUM) } - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] unsafe { &(*Peripheral::PTR) } @@ -345,7 +344,7 @@ impl DpllToken { self.dpll().dpllratio() } - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] /// Access the corresponding DPLLSYNCBUSY register for reading only #[inline] fn syncbusy(&self) -> dpllsyncbusy::R { @@ -377,7 +376,7 @@ impl DpllToken { w.refclk().variant(id.into()); w.lbypass().bit(settings.lock_bypass); w.wuf().bit(settings.wake_up_fast); - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] if let Some(cap) = settings.dco_filter { w.dcoen().bit(true); unsafe { @@ -395,7 +394,7 @@ impl DpllToken { w.ldr().bits(settings.mult - 1); w.ldrfrac().bits(settings.frac) }); - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] while self.syncbusy().dpllratio().bit_is_set() {} self.ctrla().modify(|_, w| { w.ondemand().bit(settings.on_demand); @@ -414,17 +413,17 @@ impl DpllToken { #[inline] fn wait_enabled(&self) { - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] while self.status().enable().bit_is_clear() {} } #[inline] fn wait_disabled(&self) { - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] while self.status().enable().bit_is_set() {} } @@ -502,13 +501,13 @@ impl DpllId for Dpll0Id { /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] pub enum Dpll1Id {} -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] impl Sealed for Dpll1Id {} -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] impl DpllId for Dpll1Id { const DYN: DynDpllId = DynDpllId::Dpll1; const NUM: usize = 1; @@ -608,6 +607,12 @@ impl DpllSourceId for Xosc32kId { // Settings //============================================================================== +/// Fractional divider for the `LDRFRAC` field +#[hal_cfg("sysctrl")] +pub const FRAC_DIV: u8 = 16; +#[hal_cfg("oscctrl")] +pub const FRAC_DIV: u8 = 32; + /// [`Dpll`] Proportional Integral Filter /// /// Filter settings affect PLL stability and jitter. The datasheet suggests a @@ -672,6 +677,7 @@ pub enum DcoFilter { /// [`Dpll`] settings relevant to all reference clocks #[derive(Copy, Clone)] +#[hal_macro_helper] struct Settings { mult: u16, frac: u8, @@ -680,6 +686,7 @@ struct Settings { on_demand: bool, run_standby: bool, filter: PiFilter, + #[hal_cfg("oscctrl")] dco_filter: Option, } @@ -795,7 +802,7 @@ where pub type Dpll0 = Dpll; /// Type alias for the corresponding [`Dpll`] -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] pub type Dpll1 = Dpll; impl Dpll @@ -803,6 +810,7 @@ where D: DpllId, I: DpllSourceId, { + #[hal_macro_helper] fn new(token: DpllToken, reference: I::Reference) -> Self { let settings = Settings { mult: 1, @@ -812,6 +820,7 @@ where on_demand: true, run_standby: false, filter: PiFilter::Bw92p7kHzDf0p76, + #[hal_cfg("oscctrl")] dco_filter: None, }; Self { @@ -971,7 +980,7 @@ where /// parts of the division factor, i.e. the division factor is: /// /// ```text - /// int + frac / 32 + /// int + frac / FRAC_DIV /// ``` /// /// This function will confirm that the `int` and `frac` values convert to @@ -981,7 +990,7 @@ where if int < 1 || int > 0x2000 { panic!("Invalid integer part of the DPLL loop divider") } - if frac > 31 { + if frac > FRAC_DIV - 1 { panic!("Invalid fractional part of the DPLL loop divider") } self.settings.mult = int; @@ -1022,6 +1031,7 @@ where /// Enable sigma-delta DAC low pass filter #[inline] + #[hal_cfg("oscctrl")] pub fn dco_filter(mut self, capacitor: DcoFilter) -> Self { self.settings.dco_filter = Some(capacitor); self @@ -1054,15 +1064,15 @@ where #[inline] fn output_freq(&self) -> Hertz { // The actual formula is: - // y = x * (mult + frac / 32) + // y = x * (mult + frac / FRAC_DIV) // To avoid integer precision loss, the formula is restructured: - // y = x * (mult + frac / 32) * 32 / 32 - // y = x * (32 * mult + 32 * frac / 32) / 32 - // y = x * (32 * mult + frac) / 32 + // y = x * (mult + frac / FRAC_DIV) * FRAC_DIV / FRAC_DIV + // y = x * (FRAC_DIV * mult + FRAC_DIV * frac / FRAC_DIV) / FRAC_DIV + // y = x * (FRAC_DIV * mult + frac) / FRAC_DIV let input = self.input_freq().to_Hz() as u64; - let multiplier_times_32 = - (32 * self.settings.mult as u32 + self.settings.frac as u32) as u64; - let output = (input * multiplier_times_32 / 32) as u32; + let multiplier_scaled = + (FRAC_DIV as u32 * self.settings.mult as u32 + self.settings.frac as u32) as u64; + let output = (input * multiplier_scaled / FRAC_DIV as u64) as u32; output.Hz() } @@ -1091,12 +1101,29 @@ where /// frequency is invalid, this call will panic. #[inline] pub fn enable(self) -> EnabledDpll { + const INPUT_MIN: u32 = 32_000; + + #[hal_cfg("sysctrl")] + const INPUT_MAX: u32 = 2_000_000; + #[hal_cfg("oscctrl")] + const INPUT_MAX: u32 = 3_200_000; + + #[hal_cfg("sysctrl")] + const OUTPUT_MIN: u32 = 48_000_000; + #[hal_cfg("oscctrl")] + const OUTPUT_MIN: u32 = 96_000_000; + + #[hal_cfg("sysctrl")] + const OUTPUT_MAX: u32 = 96_000_000; + #[hal_cfg("oscctrl")] + const OUTPUT_MAX: u32 = 200_000_000; + let input_freq = self.input_freq().to_Hz(); let output_freq = self.output_freq().to_Hz(); - if input_freq < 32_000 || input_freq > 3_200_000 { + if input_freq < INPUT_MIN || input_freq > INPUT_MAX { panic!("Invalid DPLL input frequency"); } - if output_freq < 96_000_000 || output_freq > 200_000_000 { + if output_freq < OUTPUT_MIN || output_freq > OUTPUT_MAX { panic!("Invalid DPLL output frequency"); } self.enable_unchecked() @@ -1136,7 +1163,7 @@ pub type EnabledDpll = Enabled, N>; pub type EnabledDpll0 = EnabledDpll; /// Type alias for the corresponding [`EnabledDpll`] -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] pub type EnabledDpll1 = EnabledDpll; impl EnabledDpll diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 3a847c99d0fd..56ba297be998 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -353,7 +353,9 @@ use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; use super::dfll::DfllId; -// use super::dpll::{Dpll0Id, Dpll1Id}; +use super::dpll::Dpll0Id; +#[hal_cfg("oscctrl")] +use super::dpll::Dpll1Id; #[hal_cfg(any("clock-d11", "clock-d21"))] use super::osc::OscId; use super::osculp32k::OscUlp32kId; @@ -1056,14 +1058,15 @@ impl GclkSourceId for DfllId { const DYN: DynGclkSourceId = DynGclkSourceId::Dfll; type Resource = (); } -//impl GclkSourceId for Dpll0Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Dpll0; -// type Resource = (); -//} -//impl GclkSourceId for Dpll1Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; -// type Resource = (); -//} +impl GclkSourceId for Dpll0Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Dpll0; + type Resource = (); +} +#[hal_cfg("oscctrl")] +impl GclkSourceId for Dpll1Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; + type Resource = (); +} impl GclkSourceId for Gclk1Id { const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; type Resource = (); From 086b616c6f66c7bd584dd0bd2cea42bb41b7780b Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 08:44:34 +1200 Subject: [PATCH 085/114] minor doc fix from stash 5 - finer-grained configuration --- hal/src/clock/v2/types.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index 0ff95ac3a475..f16b7d3eb053 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -30,9 +30,9 @@ macro_rules! create_types { $( /// Marker type representing the corresponding peripheral /// - /// This type is defined by and used within the [`clock`](super) - /// module. See the the [`types`](self) module documentation for - /// more details. + /// This type is defined by and used within the + /// [`clock`](super::super) module. See the the [`types`](super) + /// module documentation for more details. pub enum $Type {} impl Sealed for $Type {} )+ From df290cd58f7276f351496d535f5329aaeb767540 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 09:04:24 +1200 Subject: [PATCH 086/114] stash 5 - pclk Decided not to split the file up, doesn't seem necessary --- hal/src/clock/v2/pclk.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 61e038463ea7..f8f87522eaa5 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -290,13 +290,10 @@ macro_rules! with_pclk_types_ids { (Dpll1Id = 2, dpll1) (SlowClk = 3, slow) (Eic = 4, eic) - #[hal_cfg("clock-d5x")] (FreqMMeasure = 5, freq_m_measure) - #[hal_cfg("clock-d5x")] (FreqMReference = 6, freq_m_reference) (Sercom0 = 7, sercom0) (Sercom1 = 8, sercom1) - #[hal_cfg("clock-d5x")] (Tc0Tc1 = 9, tc0_tc1) (Usb = 10, usb) (EvSys0 = 11, ev_sys0) @@ -314,20 +311,16 @@ macro_rules! with_pclk_types_ids { (Sercom2 = 23, sercom2) (Sercom3 = 24, sercom3) (Tcc0Tcc1 = 25, tcc0_tcc1) - #[hal_cfg("clock-d5x")] (Tc2Tc3 = 26, tc2_tc3) #[hal_cfg("can0")] (Can0 = 27, can0) #[hal_cfg("can1")] (Can1 = 28, can1) - #[hal_cfg("clock-d5x")] (Tcc2Tcc3 = 29, tcc2_tcc3) #[hal_cfg(all("tc4", "tc5"))] (Tc4Tc5 = 30, tc4_tc5) - #[hal_cfg("clock-d5x")] (PDec = 31, pdec) (Ac = 32, ac) - #[hal_cfg("clock-d5x")] (Ccl = 33, ccl) (Sercom4 = 34, sercom4) (Sercom5 = 35, sercom5) @@ -340,18 +333,15 @@ macro_rules! with_pclk_types_ids { #[hal_cfg(all("tc6", "tc7"))] (Tc6Tc7 = 39, tc6_tc7) (Adc0 = 40, adc0) - #[hal_cfg("clock-d5x")] (Adc1 = 41, adc1) (Dac = 42, dac) #[hal_cfg("i2s")] (I2S0 = 43, i2s0) #[hal_cfg("i2s")] (I2S1 = 44, i2s1) - #[hal_cfg("clock-d5x")] (Sdhc0 = 45, sdhc0) #[hal_cfg("sdhc1")] (Sdhc1 = 46, sdhc1) - #[hal_cfg("clock-d5x")] (CM4Trace = 47, cm4_trace) ); }; From 521ae4c61973202c094c7056c96f293bfd0cae3c Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 09:47:18 +1200 Subject: [PATCH 087/114] stash 5 - xosc32k --- hal/src/clock/v2/xosc32k.rs | 112 +++++++++++++----------------------- 1 file changed, 41 insertions(+), 71 deletions(-) diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index 4df5386e3157..32dafa8be796 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -341,32 +341,28 @@ //! [`is_switched`]: Xosc32kCfd::is_switched //! [`switch_back`]: Xosc32kCfd::switch_back -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use fugit::RateExtU32; use typenum::U0; -#[hal_cfg("clock-d5x")] -mod imports { - pub use super::super::osculp32k::OscUlp32kId; - pub use crate::pac::Osc32kctrl as PERIPHERAL; - pub use crate::pac::osc32kctrl::xosc32k::Cgmselect; - pub use crate::pac::osc32kctrl::{Cfdctrl, Xosc32k as PacXosc32k, status::R as STATUS_R}; -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -mod imports { - pub use crate::pac::Sysctrl as PERIPHERAL; - pub use crate::pac::sysctrl::Xosc32k as PacXosc32k; - pub use crate::pac::sysctrl::pclksr::R as STATUS_R; -} - -use imports::*; - -#[hal_cfg("clock-d21")] +#[hal_cfg("osc32kctrl")] +use crate::{ + clock::v2::osculp32k::OscUlp32kId, + pac::{ + Osc32kctrl as PERIPHERAL, + osc32kctrl::{Cfdctrl, Xosc32k as PacXosc32k, status::R as STATUS_R, xosc32k::Cgmselect}, + }, +}; + +#[hal_cfg("sysctrl")] +use crate::pac::{ + Sysctrl as PERIPHERAL, + sysctrl::{Xosc32k as PacXosc32k, pclksr::R as STATUS_R}, +}; + +#[hal_cfg(any("port-d21", "port-d5x"))] pub use crate::gpio::{PA00 as XIn32Id, PA01 as XOut32Id}; -#[hal_cfg("clock-d5x")] -pub use crate::gpio::{PA00 as XIn32Id, PA01 as XOut32Id}; -#[hal_cfg("clock-d11")] +#[hal_cfg("port-d11")] pub use crate::gpio::{PA08 as XIn32Id, PA09 as XOut32Id}; use crate::gpio::{FloatingDisabled, Pin}; @@ -398,6 +394,7 @@ pub struct Xosc32kBaseToken(()); /// /// The [`Xosc1k`] clock is disabled at power-on reset. To use it, you must /// first exchange the token for an actual clock with [`Xosc1k::enable`]. +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] pub struct Xosc1kToken(()); /// Singleton token that can be exchanged for [`Xosc32k`] @@ -419,19 +416,21 @@ pub struct Xosc32kToken(()); /// /// Clock failure detection is disabled at power-on reset. To use it, you must /// first enable it by exchanging the token with [`Xosc32kCfd::enable`]. -#[hal_cfg("clock-d5x")] +#[hal_cfg("osc32kctrl")] pub struct Xosc32kCfdToken(()); -#[hal_cfg("clock-d5x")] +#[hal_macro_helper] /// Set of tokens representing the disabled XOSC32K clocks power-on reset pub struct Xosc32kTokens { pub base: Xosc32kBaseToken, + #[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] pub xosc1k: Xosc1kToken, pub xosc32k: Xosc32kToken, + #[hal_cfg("osc32kctrl")] pub cfd: Xosc32kCfdToken, } -#[hal_cfg("clock-d5x")] +#[hal_macro_helper] impl Xosc32kTokens { /// Create the set of tokens /// @@ -443,50 +442,25 @@ impl Xosc32kTokens { pub(super) unsafe fn new() -> Self { Self { base: Xosc32kBaseToken(()), + #[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] xosc1k: Xosc1kToken(()), xosc32k: Xosc32kToken(()), + #[hal_cfg("osc32kctrl")] cfd: Xosc32kCfdToken(()), } } } -#[hal_cfg(any("clock-d11", "clock-d21"))] - -/// Set of tokens representing the disabled XOSC32K clocks power-on reset -pub struct Xosc32kTokens { - pub base: Xosc32kBaseToken, - pub xosc1k: Xosc1kToken, - pub xosc32k: Xosc32kToken, -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -impl Xosc32kTokens { - /// Create the set of tokens - /// - /// # Safety - /// - /// There must never be more than one instance of these tokens at any given - /// time. See the notes on `Token` types and memory safety in the root of - /// the `clock` module for more details. - pub(super) unsafe fn new() -> Self { - Self { - base: Xosc32kBaseToken(()), - xosc1k: Xosc1kToken(()), - xosc32k: Xosc32kToken(()), - } - } -} - impl Xosc32kBaseToken { #[inline] fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. - #[hal_cfg("clock-d5x")] + #[hal_cfg("osc32kctrl")] unsafe { (*PERIPHERAL::PTR).status().read() } - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] unsafe { (*PERIPHERAL::PTR).pclksr().read() } @@ -514,24 +488,13 @@ impl Xosc32kBaseToken { /// Set most of the fields in the XOSC32K register #[inline] - #[hal_cfg("clock-d5x")] + #[hal_macro_helper] fn enable(&mut self, mode: DynMode, settings: Settings) { let xtalen = mode == DynMode::CrystalMode; self.xosc32k().write(|w| { + #[hal_cfg("osc32kctrl")] w.cgm().variant(settings.cgm.into()); - unsafe { w.startup().bits(settings.start_up as u8) }; - w.ondemand().bit(settings.on_demand); - w.runstdby().bit(settings.run_standby); - w.xtalen().bit(xtalen); - w.enable().set_bit() - }); - } - - #[inline] - #[hal_cfg(any("clock-d11", "clock-d21"))] - fn enable(&mut self, mode: DynMode, settings: Settings) { - let xtalen = mode == DynMode::CrystalMode; - self.xosc32k().write(|w| { + #[hal_cfg("sysctrl")] w.aampen().bit(settings.aampen); unsafe { w.startup().bits(settings.start_up as u8) }; w.ondemand().bit(settings.on_demand); @@ -549,12 +512,14 @@ impl Xosc32kBaseToken { /// Enable the 1 kHz output #[inline] + #[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] fn enable_1k(&mut self) { self.xosc32k().modify(|_, w| w.en1k().set_bit()); } /// Disable the 1 kHz output #[inline] + #[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] fn disable_1k(&mut self) { self.xosc32k().modify(|_, w| w.en1k().clear_bit()); } @@ -578,7 +543,7 @@ impl Xosc32kBaseToken { } } -#[hal_cfg("clock-d5x")] +#[hal_cfg("osc32kctrl")] impl Xosc32kCfdToken { #[inline] fn status(&self) -> STATUS_R { @@ -1097,12 +1062,12 @@ impl EnabledXosc32kBase { /// /// [`OscUlp32k`]: super::osculp32k::OscUlp32k /// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k -#[hal_cfg("clock-d5x")] +#[hal_cfg("osc32kctrl")] pub struct Xosc32kCfd { token: Xosc32kCfdToken, } -#[hal_cfg("clock-d5x")] +#[hal_cfg("osc32kctrl")] impl Xosc32kCfd { /// Enable continuous monitoring of the XOSC32K for clock failure /// @@ -1202,6 +1167,7 @@ impl Sealed for Xosc32kId {} /// of three clocks forming a small clock tree. The [`Xosc1k`] clock is derived /// from the [`Xosc32kBase`] clock. See the [module-level documentation](super) /// for details and examples. +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] pub struct Xosc1k { token: Xosc1kToken, } @@ -1215,8 +1181,10 @@ pub struct Xosc1k { /// /// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified, /// the counter is assumed to be zero. +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] pub type EnabledXosc1k = Enabled; +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] impl Xosc1k { /// Enable 1 kHz output from the [`Xosc32kBase`] clock /// @@ -1235,6 +1203,7 @@ impl Xosc1k { } } +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] impl EnabledXosc1k { /// Disable 1 kHz output from the [`Xosc32kBase`] clock /// @@ -1253,6 +1222,7 @@ impl EnabledXosc1k { } } +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] impl Source for EnabledXosc1k { type Id = Xosc1kId; From 209e22938ac12e8d669fdc899f793aecce42b108 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 10:01:01 +1200 Subject: [PATCH 088/114] stash 4 - gpio --- hal/src/gpio/dynpin.rs | 5 +---- hal/src/gpio/pin.rs | 6 +----- hal/src/gpio/reg.rs | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/hal/src/gpio/dynpin.rs b/hal/src/gpio/dynpin.rs index 913193b81e3a..1c6d5e290a24 100644 --- a/hal/src/gpio/dynpin.rs +++ b/hal/src/gpio/dynpin.rs @@ -111,7 +111,6 @@ pub enum DynAlternate { E, F, G, - #[hal_cfg(any("port-d21", "port-d5x"))] H, #[hal_cfg("port-d5x")] I, @@ -182,9 +181,7 @@ macro_rules! dyn_alternate { }; } -dyn_alternate!(B, C, D, E, F, G); -#[hal_cfg(any("port-d21", "port-d5x"))] -dyn_alternate!(H); +dyn_alternate!(B, C, D, E, F, G, H); #[hal_cfg("port-d5x")] dyn_alternate!(I, J, K, L, M, N); diff --git a/hal/src/gpio/pin.rs b/hal/src/gpio/pin.rs index 040c8473e8bd..62129af8fca0 100644 --- a/hal/src/gpio/pin.rs +++ b/hal/src/gpio/pin.rs @@ -341,10 +341,7 @@ macro_rules! alternate { }; } -alternate!(B, C, D, E, F, G); - -#[hal_cfg(any("port-d21", "port-d5x"))] -alternate!(H); +alternate!(B, C, D, E, F, G, H); #[hal_cfg("port-d5x")] alternate!(I, J, K, L, M, N); @@ -752,7 +749,6 @@ impl_core_convert_from!( AlternateE, AlternateF, AlternateG, - #[hal_cfg(any("port-d21", "port-d5x"))] AlternateH, #[hal_cfg("port-d5x")] AlternateI, diff --git a/hal/src/gpio/reg.rs b/hal/src/gpio/reg.rs index e1229fa425ae..1eb865fe8da8 100644 --- a/hal/src/gpio/reg.rs +++ b/hal/src/gpio/reg.rs @@ -125,7 +125,6 @@ impl From for ModeFields { G => { fields.pmux = 6; } - #[hal_cfg(any("port-d21", "port-d5x"))] H => { fields.pmux = 7; } From 0c3981493d50e255ccd47f5ec250b9540e9fcec8 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 10:31:09 +1200 Subject: [PATCH 089/114] fix build for SAMD11 --- hal/src/clock/v2/apb.rs | 52 +++++++++++++++++++++++++++++++++++--- hal/src/clock/v2/osc32k.rs | 2 +- hal/src/clock/v2/pclk.rs | 10 +++++--- hal/src/clock/v2/types.rs | 3 +++ 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index dab3f3e11d76..a701134241b4 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -519,8 +519,9 @@ define_apb_types!( ); // SAMD21/DA1 datasheet DS40001882H, Table 12-1. Peripherals Configuration -// Summary TODO I2S needs to be added (disabled on startup) -#[hal_cfg(any("clock-d11", "clock-d21"))] +// Summary +#[hal_macro_helper] +#[hal_cfg("clock-d21")] define_apb_types!( A { Pac0 = (0, all, any) @@ -537,7 +538,8 @@ define_apb_types!( NvmCtrl = (2, all, any) Port = (3, all, any) Dmac = (4, all, any) - Usb = (5, all, any) // TODO should be conditional + #[hal_cfg("usb")] + Usb = (5, all, any) } C { Pac2 = (0, any, all) @@ -557,6 +559,50 @@ define_apb_types!( Adc0 = (16, any, all) Ac = (17, any, all) Dac = (18, any, all) + Ptc = (19, any, all) + #[hal_cfg("i2s")] + I2S = (20, any, all) + Ac1 = (21, any, all) + } +); + +// Atmel-42363H-SAM-D11-Datasheet_09/2016, Table 11-1. Peripherals Configuration +// Summary +#[hal_macro_helper] +#[hal_cfg("clock-d11")] +define_apb_types!( + A { + Pac0 = (0, all, any) + Pm = (1, all, any) + SysCtrl = (2, all, any) + Gclk = (3, all, any) + Wdt = (4, all, any) + Rtc = (5, all, any) + Eic = (6, all, any) + } + B { + Pac1 = (0, all, any) + Dsu = (1, all, any) + NvmCtrl = (2, all, any) + Port = (3, all, any) + Dmac = (4, all, any) + #[hal_cfg("usb")] + Usb = (5, all, any) + } + C { + Pac2 = (0, any, all) + EvSys = (1, any, all) + Sercom0 = (2, any, all) + Sercom1 = (3, any, all) + #[hal_cfg("sercom2")] + Sercom2 = (4, any, all) + Tcc0 = (5, any, all) + Tc1 = (6, any, all) + Tc2 = (7, any, all) + Adc0 = (8, any, all) + Ac = (9, any, all) + Dac = (10, any, all) + Ptc = (11, any, all) } ); diff --git a/hal/src/clock/v2/osc32k.rs b/hal/src/clock/v2/osc32k.rs index 7e1c49f0b698..39d7fb2dc646 100644 --- a/hal/src/clock/v2/osc32k.rs +++ b/hal/src/clock/v2/osc32k.rs @@ -522,7 +522,7 @@ impl Source for EnabledOsc1k { #[inline] fn freq(&self) -> Hertz { - Hertz(1024) + 1_024u32.Hz() } } diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index f8f87522eaa5..49c9abb2cd1a 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -212,16 +212,18 @@ pub mod ids { pub use super::super::types::{ Ac, Adc0, Adc1, CM4Trace, Ccl, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, FreqMMeasure, FreqMReference, PDec, - Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Tcc0Tcc1, Tcc2Tcc3, Usb, + Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Tcc2Tcc3, Usb, }; #[hal_cfg(any("clock-d11", "clock-d21"))] pub use super::super::types::{ Ac, AcAna, AcDig, Adc0, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, - EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, Ptc, Rtc, SercomSlow, SlowClk, Tcc0Tcc1, Usb, - Wdt, + EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, Ptc, Rtc, SercomSlow, SlowClk, Usb, Wdt, }; + #[hal_cfg("clock-d11")] + pub use super::super::types::{Tc1Tc2, Tcc0}; + #[hal_cfg("can0")] pub use super::super::types::Can0; #[hal_cfg("can1")] @@ -232,6 +234,8 @@ pub mod ids { pub use super::super::types::Tc4Tc5; #[hal_cfg(all("tc6", "tc7"))] pub use super::super::types::Tc6Tc7; + #[hal_cfg(all("tcc0", "tcc1"))] + pub use super::super::types::Tcc0Tcc1; #[hal_cfg("tcc4")] pub use super::super::types::Tcc4; diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index f16b7d3eb053..93b8dc81e7eb 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -119,6 +119,9 @@ create_types!(Tcc0Tcc1); #[hal_cfg(all("tcc2", "tcc3"))] create_types!(Tcc2Tcc3); +#[hal_cfg(all("tc1-d11", "tc2-d11"))] +create_types!(Tc1Tc2); + #[hal_cfg(all("tcc2", "tc3-d21"))] create_types!(Tcc2Tc3); From 0a21f5ed89077919c3878f41e4fba8c5ad11a929 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 10:59:28 +1200 Subject: [PATCH 090/114] L variants don't have xosc32k --- atsamd-hal-macros/devices.yaml | 3 +++ hal/src/clock/v2.rs | 5 ++++- hal/src/clock/v2/dpll.rs | 7 +++++++ hal/src/clock/v2/gclk.rs | 2 ++ hal/src/clock/v2/reset_thumbv6m.rs | 6 ++++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/atsamd-hal-macros/devices.yaml b/atsamd-hal-macros/devices.yaml index df6a7af81f8d..bcfb70f40688 100644 --- a/atsamd-hal-macros/devices.yaml +++ b/atsamd-hal-macros/devices.yaml @@ -21,6 +21,7 @@ families: - serial-numbers - dsu - clock + - xosc32k - xosc: { count: 1 } - gclk: { count: 6 } - pm @@ -54,6 +55,7 @@ families: - serial-numbers - dsu - clock + - xosc32k: { except: ["samd21el", "samd21gl"] } - xosc: { count: 1 } - gclk: { count: 8 } - pm @@ -98,6 +100,7 @@ families: - cmcc - dsu - clock + - xosc32k - xosc: { count: 2 } - gclk: { count: 12 } - mclk diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index eb689d63b6cb..99a3959fe1d4 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -882,7 +882,10 @@ pub mod pclk; pub mod rtcosc {} pub mod types; pub mod xosc; -pub mod xosc32k; +#[hal_module( + "xosc32k" => "v2/xosc32k.rs" +)] +pub mod xosc32k {} #[hal_module( any("clock-d11", "clock-d21") => "v2/reset_thumbv6m.rs", diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 7d033a5023d6..0101eff3a46c 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -272,6 +272,7 @@ use super::pclk::{Pclk, PclkId}; #[hal_cfg("xosc1")] use super::xosc::Xosc1Id; use super::xosc::{Xosc0Id, XoscId}; +#[hal_cfg("xosc32k")] use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -598,6 +599,7 @@ impl DpllSourceId for Xosc1Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc1; type Reference = settings::Xosc; } +#[hal_cfg("xosc32k")] impl DpllSourceId for Xosc32kId { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc32k; type Reference = settings::Xosc32k; @@ -693,7 +695,9 @@ struct Settings { /// Store and retrieve [`Dpll`] settings for different reference clocks mod settings { use super::super::pclk; + #[hal_cfg("xosc32k")] use super::RateExtU32; + use super::hal_cfg; use super::{DpllId, GclkId, Hertz}; /// [`Dpll`] settings when referenced to a [`Pclk`] @@ -717,6 +721,7 @@ mod settings { /// /// [`Dpll`]: super::Dpll /// [`Xosc32k`]: super::super::xosc32k::Xosc32k + #[hal_cfg("xosc32k")] pub struct Xosc32k; /// Generic interface for the frequency and predivider of a reference clock @@ -747,6 +752,7 @@ mod settings { } } + #[hal_cfg("xosc32k")] impl Reference for Xosc32k { #[inline] fn freq(&self) -> Hertz { @@ -931,6 +937,7 @@ where } } +#[hal_cfg("xosc32k")] impl Dpll { /// Create a [`Dpll`] from an [`Xosc32k`] /// diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 56ba297be998..e6cdd0ebed2f 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -362,6 +362,7 @@ use super::osculp32k::OscUlp32kId; use super::xosc::Xosc0Id; #[hal_cfg("xosc1")] use super::xosc::Xosc1Id; +#[hal_cfg("xosc32k")] use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -1093,6 +1094,7 @@ impl GclkSourceId for Xosc1Id { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; type Resource = (); } +#[hal_cfg("xosc32k")] impl GclkSourceId for Xosc32kId { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; type Resource = (); diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index ef4ede831cb6..521159205195 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -2,6 +2,8 @@ //! from the `v2` module, which is where the corresponding documentation will //! appear. +use atsamd_hal_macros::hal_macro_helper; + use typenum::U1; use crate::pac::{Gclk, Pm, Sysctrl}; @@ -108,6 +110,7 @@ pub struct Clocks { /// As described in the [top-level](super::super) documentation for the `clock` /// module, token types are used to guanrantee the uniqueness of each clock. To /// configure or enable a clock, you must provide the corresponding token. +#[hal_macro_helper] pub struct Tokens { /// Tokens to create [`apb::ApbClk`]s pub apbs: apb::ApbTokens, @@ -125,6 +128,7 @@ pub struct Tokens { pub xosc: xosc::XoscToken, /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and /// [`xosc32k::Xosc32k`] + #[hal_cfg("xosc32k")] pub xosc32k: xosc32k::Xosc32kTokens, } @@ -168,6 +172,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl wdt, osculp, }; + #[hal_macro_helper] let tokens = Tokens { apbs: apb::ApbTokens::new(), dfll: dfll::DfllToken::new(), @@ -176,6 +181,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl pclks: pclk::PclkTokens::new(), osc32k: osc32k::Osc32kTokens::new(), xosc: xosc::XoscToken::new(), + #[hal_cfg("xosc32k")] xosc32k: xosc32k::Xosc32kTokens::new(), }; (buses, clocks, tokens) From 2a3f6a1472ff19616e9232750d426c77895658c6 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 11:00:06 +1200 Subject: [PATCH 091/114] Fixes for SAMD21E --- hal/src/clock/v2/apb.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index a701134241b4..27b9eb6680a2 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -548,7 +548,9 @@ define_apb_types!( Sercom1 = (3, any, all) Sercom2 = (4, any, all) Sercom3 = (5, any, all) + #[hal_cfg("sercom4")] Sercom4 = (6, any, all) + #[hal_cfg("sercom5")] Sercom5 = (7, any, all) Tcc0 = (8, any, all) Tcc1 = (9, any, all) From 13872c278980da54e2a6dcb670325abc14e67ff7 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 11:45:00 +1200 Subject: [PATCH 092/114] Fix builds for smaller SAMD51 --- hal/src/clock/v1_thumbv7em.rs | 1 + hal/src/clock/v2/pclk.rs | 5 ++++- hal/src/peripherals/pwm/d5x.rs | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hal/src/clock/v1_thumbv7em.rs b/hal/src/clock/v1_thumbv7em.rs index b6369fa3a429..efdd9572fc9e 100644 --- a/hal/src/clock/v1_thumbv7em.rs +++ b/hal/src/clock/v1_thumbv7em.rs @@ -439,6 +439,7 @@ clock_generator!( (tc0_tc1, Tc0Tc1Clock, TC0_TC1, Tc0Tc1), (tcc0_tcc1, Tcc0Tcc1Clock, TCC0_TCC1, Tcc0Tcc1), (tc2_tc3, Tc2Tc3Clock, TC2_TC3, Tc2Tc3), + #[hal_cfg(all("tcc2", "tcc3"))] (tcc2_tcc3, Tcc2Tcc3Clock, TCC2_TCC3, Tcc2Tcc3), #[hal_cfg(all("tc4", "tc5"))] (tc4_tc5, Tc4Tc5Clock, TC4_TC5, Tc4Tc5), diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 49c9abb2cd1a..137b81debe03 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -212,7 +212,7 @@ pub mod ids { pub use super::super::types::{ Ac, Adc0, Adc1, CM4Trace, Ccl, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, FreqMMeasure, FreqMReference, PDec, - Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Tcc2Tcc3, Usb, + Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Usb, }; #[hal_cfg(any("clock-d11", "clock-d21"))] @@ -236,6 +236,8 @@ pub mod ids { pub use super::super::types::Tc6Tc7; #[hal_cfg(all("tcc0", "tcc1"))] pub use super::super::types::Tcc0Tcc1; + #[hal_cfg(all("tcc2", "tcc3"))] + pub use super::super::types::Tcc2Tcc3; #[hal_cfg("tcc4")] pub use super::super::types::Tcc4; @@ -320,6 +322,7 @@ macro_rules! with_pclk_types_ids { (Can0 = 27, can0) #[hal_cfg("can1")] (Can1 = 28, can1) + #[hal_cfg(all("tcc2", "tcc3"))] (Tcc2Tcc3 = 29, tcc2_tcc3) #[hal_cfg(all("tc4", "tc5"))] (Tc4Tc5 = 30, tc4_tc5) diff --git a/hal/src/peripherals/pwm/d5x.rs b/hal/src/peripherals/pwm/d5x.rs index 30e4286a46cf..10b8a547f0c5 100644 --- a/hal/src/peripherals/pwm/d5x.rs +++ b/hal/src/peripherals/pwm/d5x.rs @@ -688,9 +688,9 @@ impl $crate::ehal_02::Pwm for $TYPE { pwm_tcc! { Tcc0Pwm: (Tcc0, TCC0Pinout, Tcc0Tcc1Clock, apbbmask, tcc0_, TccPwm0Wrapper) } #[hal_cfg("tcc1")] pwm_tcc! { Tcc1Pwm: (Tcc1, TCC1Pinout, Tcc0Tcc1Clock, apbbmask, tcc1_, TccPwm1Wrapper) } -#[hal_cfg("tcc2")] +#[hal_cfg(all("tcc2", "tcc3"))] pwm_tcc! { Tcc2Pwm: (Tcc2, TCC2Pinout, Tcc2Tcc3Clock, apbcmask, tcc2_, TccPwm2Wrapper) } -#[hal_cfg("tcc3")] +#[hal_cfg(all("tcc2", "tcc3"))] pwm_tcc! { Tcc3Pwm: (Tcc3, TCC3Pinout, Tcc2Tcc3Clock, apbcmask, tcc3_, TccPwm3Wrapper) } #[hal_cfg("tcc4")] pwm_tcc! { Tcc4Pwm: (Tcc4, TCC4Pinout, Tcc4Clock, apbdmask, tcc4_, TccPwm4Wrapper) } From 23929caf27c5c6f848644da3c562bd9520b163d7 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 08:51:23 +1200 Subject: [PATCH 093/114] Build on stable Rust --- hal/src/clock/v2/dfll.rs | 3 ++- hal/src/clock/v2/dpll.rs | 5 ++++- hal/src/clock/v2/gclk.rs | 4 ++++ hal/src/clock/v2/osculp32k.rs | 3 ++- hal/src/clock/v2/pclk.rs | 3 +++ hal/src/clock/v2/reset_thumbv6m.rs | 2 +- hal/src/clock/v2/xosc.rs | 5 ++++- hal/src/clock/v2/xosc32k.rs | 1 + hal/src/lib.rs | 4 ---- 9 files changed, 21 insertions(+), 9 deletions(-) diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index daa623f139d3..1f4dbfc91d24 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -272,7 +272,7 @@ //! [`from_usb`]: Dfll::from_usb //! [`into_mode`]: EnabledDfll::into_mode -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; #[hal_cfg("clock-d5x")] mod imports { @@ -433,6 +433,7 @@ impl DfllToken { } #[inline] + #[hal_macro_helper] fn disable(&mut self) { self.dfllctrl().write(|w| w.enable().clear_bit()); #[hal_cfg("clock-d5x")] diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 0101eff3a46c..8c295c89e529 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -312,6 +312,7 @@ impl DpllToken { /// Access the corresponding PAC `DPLL` struct #[inline] + #[hal_macro_helper] fn dpll(&self) -> &PacDpll { // Safety: Each `DpllToken` only has access to a mutually exclusive set // of registers for the corresponding `DpllId`, and we use a shared @@ -359,9 +360,9 @@ impl DpllToken { } #[inline] + #[hal_macro_helper] fn enable(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) { // Convert the actual predivider to the `div` register field value - #[hal_macro_helper] let div = match id { DynDpllSourceId::Xosc0 => prediv / 2 - 1, #[hal_cfg("xosc1")] @@ -413,6 +414,7 @@ impl DpllToken { } #[inline] + #[hal_macro_helper] fn wait_enabled(&self) { #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} @@ -421,6 +423,7 @@ impl DpllToken { } #[inline] + #[hal_macro_helper] fn wait_disabled(&self) { #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index e6cdd0ebed2f..2a90661c57e4 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -407,6 +407,7 @@ impl GclkToken { /// Provide a reference to the corresponding [`Genctrl`] register #[inline] + #[hal_macro_helper] fn genctrl(&self) -> &Genctrl { // Safety: Each `GclkToken` only has access to a mutually exclusive set // of registers for the corresponding `GclkId`, and we use a shared @@ -433,6 +434,7 @@ impl GclkToken { /// Reads or writes to synchronized fields must be accompanied by a check of /// the `SYNCBUSY` register. See the datasheet for more details. #[inline] + #[hal_macro_helper] fn wait_syncbusy(&self) { // Safety: We are only reading from the `SYNCBUSY` register, and we are // only observing the bit corresponding to this particular `GclkId`, so @@ -461,6 +463,7 @@ impl GclkToken { /// Use the internal interface of [`GclkDivider`] to set the `DIV` and /// `DIVSEL` fields of the `GENCTRL` register. #[inline] + #[hal_macro_helper] fn set_div(&mut self, div: G::Divider) { let (divsel, div) = div.divsel_div(); // Safety: The `DIVSEL` and `DIV` values are derived from the @@ -515,6 +518,7 @@ impl GclkToken { } #[inline] + #[hal_macro_helper] fn enable(&mut self, id: DynGclkSourceId, settings: Settings) { let (divsel, div) = settings.div.divsel_div(); self.genctrl().write(|w| { diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index 916b4383b2e7..64a1cb72df56 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -162,7 +162,7 @@ //! [`clock_system_at_reset`]: super::clock_system_at_reset //! [`Clocks`]: super::Clocks -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use fugit::RateExtU32; use typenum::U0; @@ -221,6 +221,7 @@ pub struct OscUlp32kToken(()); impl OscUlp32kBaseToken { #[inline] + #[hal_macro_helper] fn osculp32k(&self) -> &Osculp32k { // Safety: The `OscUlp32kBaseToken` has exclusive access to the // `OSCULP32K` register. See the notes on `Token` types and memory diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 137b81debe03..991aa396ae6c 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -125,6 +125,7 @@ impl PclkToken

{ /// Access the corresponding `PCHCTRL` register #[inline] + #[hal_macro_helper] fn ctrl(&self) -> &Ctrl { // Safety: Each `PclkToken` only has access to a mutually exclusive set // of registers for the corresponding `PclkId`, and we use a shared @@ -142,6 +143,7 @@ impl PclkToken

{ /// Set the [`Pclk`] source #[inline] + #[hal_macro_helper] fn enable(&mut self, source: DynPclkSourceId) { self.ctrl().write(|w| { w.r#gen().variant(source.into()); @@ -157,6 +159,7 @@ impl PclkToken

{ /// Disable the [`Pclk`] #[inline] + #[hal_macro_helper] fn disable(&mut self) { self.ctrl().modify(|_, w| { #[hal_cfg(any("clock-d11", "clock-d21"))] diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index 521159205195..2f9728911de6 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -140,6 +140,7 @@ pub struct Tokens { /// /// See the [module-level documentation](super) for more details. #[inline] +#[hal_macro_helper] pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Clocks, Tokens) { // Safety: No bus, clock or token is instantiated more than once unsafe { @@ -172,7 +173,6 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl wdt, osculp, }; - #[hal_macro_helper] let tokens = Tokens { apbs: apb::ApbTokens::new(), dfll: dfll::DfllToken::new(), diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 55ac7e2c0ec7..7f0a437aad2f 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -204,7 +204,7 @@ //! [`Dfll`]: super::dfll::Dfll //! [`EnabledDfll`]: super::dfll::EnabledDfll -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use typenum::U0; @@ -273,6 +273,7 @@ impl XoscToken { /// Return a reference to the corresponding XOSCCTRL register #[inline] + #[hal_macro_helper] fn xoscctrl(&self) -> &Xoscctrl { // Safety: Each `XoscToken` only has access to a mutually exclusive set // of registers for the corresponding `XoscId`, and we use a shared @@ -290,6 +291,7 @@ impl XoscToken { /// Read the STATUS register #[inline] + #[hal_macro_helper] fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. @@ -358,6 +360,7 @@ impl XoscToken { /// Set most of the fields in the XOSCCTRL register #[inline] + #[hal_macro_helper] fn enable(&mut self, mode: DynMode, settings: Settings) { let xtalen = mode == DynMode::CrystalMode; // Safety: The `IMULT` and `IPTAT` values come from the diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index 32dafa8be796..a3cd6d7857df 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -453,6 +453,7 @@ impl Xosc32kTokens { impl Xosc32kBaseToken { #[inline] + #[hal_macro_helper] fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. diff --git a/hal/src/lib.rs b/hal/src/lib.rs index f5f588c13a1d..4bf3008b7bba 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,8 +1,4 @@ #![no_std] -// TODO Allows using hal_cfg to gate clock v2 for thumbv6, nightly only -#![feature(proc_macro_hygiene)] -// TODO as above -#![feature(stmt_expr_attributes)] pub use embedded_hal_1 as ehal; use embedded_hal_02 as ehal_02; From bbdfaaeac81a960a3ca7fe148a1dd4d9d7a20204 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 10:32:49 +1200 Subject: [PATCH 094/114] Update Feather M4 examples --- boards/feather_m4/examples/adc.rs | 5 ++--- boards/feather_m4/examples/blinky_rtic.rs | 22 +++++++--------------- boards/feather_m4/examples/clocking_v2.rs | 7 ++----- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/boards/feather_m4/examples/adc.rs b/boards/feather_m4/examples/adc.rs index b6b892cf43d3..a8d736b0b5c5 100644 --- a/boards/feather_m4/examples/adc.rs +++ b/boards/feather_m4/examples/adc.rs @@ -17,13 +17,13 @@ use bsp::Pins; use pac::{CorePeripherals, Peripherals}; use hal::{ - adc::{Accumulation, Adc, Prescaler, Resolution}, + adc::{Accumulation, Prescaler}, clock::v2::{clock_system_at_reset, pclk::Pclk}, }; #[entry] fn main() -> ! { - let mut peripherals = Peripherals::take().unwrap(); + let peripherals = Peripherals::take().unwrap(); let _core = CorePeripherals::take().unwrap(); let pins = Pins::new(peripherals.port); @@ -33,7 +33,6 @@ fn main() -> ! { peripherals.osc32kctrl, peripherals.gclk, peripherals.mclk, - &mut peripherals.nvmctrl, ); // Enable the ADC0 ABP clock... diff --git a/boards/feather_m4/examples/blinky_rtic.rs b/boards/feather_m4/examples/blinky_rtic.rs index d853e3f52262..8945f5cf130b 100644 --- a/boards/feather_m4/examples/blinky_rtic.rs +++ b/boards/feather_m4/examples/blinky_rtic.rs @@ -10,7 +10,7 @@ use panic_halt as _; #[cfg(feature = "use_semihosting")] use panic_semihosting as _; -use hal::clock::v2::{clock_system_at_reset, osculp32k::OscUlp1k, rtcosc::RtcOsc}; +use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; use hal::prelude::*; use hal::rtc::rtic::rtc_clock; use rtic::app; @@ -33,25 +33,17 @@ mod app { #[init] fn init(cx: init::Context) -> (Shared, Resources) { - let mut device = cx.device; + let device = cx.device; let mut core: rtic::export::Peripherals = cx.core; // Use v2 of the clocks API so that we can set the RTC clock source - let (_, clocks, tokens) = clock_system_at_reset( - device.oscctrl, - device.osc32kctrl, - device.gclk, - device.mclk, - &mut device.nvmctrl, - ); - - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - - // Enable the RTC clock with the 1 kHz source. + let (_, clocks, tokens) = + clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); + + // Enable the RTC clock with the internal 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); // Start the monotonic Mono::start(device.rtc); diff --git a/boards/feather_m4/examples/clocking_v2.rs b/boards/feather_m4/examples/clocking_v2.rs index 7a9b763bbe14..fa86e38d160f 100644 --- a/boards/feather_m4/examples/clocking_v2.rs +++ b/boards/feather_m4/examples/clocking_v2.rs @@ -8,7 +8,6 @@ use atsamd_hal::{ self as clock, dpll::Dpll, gclk::{Gclk, GclkDiv16, GclkDiv8}, - osculp32k::OscUlp32k, pclk::Pclk, rtcosc::RtcOsc, xosc32k::{ControlGainMode, Xosc1k, Xosc32k, Xosc32kBase}, @@ -43,7 +42,7 @@ mod app { #[init] fn init(cx: init::Context) -> (SharedResources, LocalResources) { - let mut device = cx.device; + let device = cx.device; // Get the clocks & tokens let (_buses, clocks, tokens) = clock::clock_system_at_reset( @@ -51,7 +50,6 @@ mod app { device.osc32kctrl, device.gclk, device.mclk, - &mut device.nvmctrl, ); // This is required because the `sercom` and `rtc` modules have not yet @@ -113,8 +111,7 @@ mod app { // Output `OscUlp32k` on PB11 pin via `Gclk5`, without any division resulting in // 32 kHz output frequency - let (osculp32k, _osculp_base) = - OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base); + let osculp32k = clocks.osculp.osculp32k; let (gclk5, _osculp32k) = Gclk::from_source(tokens.gclks.gclk5, osculp32k); let gclk5 = gclk5.enable(); let (_gclk5, _gclk5_out) = gclk5.enable_gclk_out(pins.pb11); From 47c074f9d2521c93cfd0332cdd44b704cac60d0c Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 11:23:58 +1200 Subject: [PATCH 095/114] Deduplicate feather_m4 and metro_m4 blinky_rtc example --- Cargo.toml | 2 + boards/examples/m4-blinky_rtic.rs | 82 +++++++++++++++++++++++ boards/feather_m4/examples/blinky_rtic.rs | 74 +------------------- boards/metro_m4/examples/blinky_rtic.rs | 82 +---------------------- 4 files changed, 86 insertions(+), 154 deletions(-) create mode 100644 boards/examples/m4-blinky_rtic.rs diff --git a/Cargo.toml b/Cargo.toml index 6613515bbc01..c7e8accbc2ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,8 @@ members = [ "pac/*", "boards/*", ] +# Fragments of example files, referenced by `include!()` from BSP examples +exclude = ["boards/examples"] [profile.dev] debug = true diff --git a/boards/examples/m4-blinky_rtic.rs b/boards/examples/m4-blinky_rtic.rs new file mode 100644 index 000000000000..2a055d3c0918 --- /dev/null +++ b/boards/examples/m4-blinky_rtic.rs @@ -0,0 +1,82 @@ +// Blink an led using an RTIC software task and the RTC-based monotonic. +// +// This file is included by one or more BSP examples. In normal usage, firmware +// source code needs to start with something like: +// +// ``` +// #![no_std] +// #![no_main] +// use feather_m4 as bsp; +//``` + +use bsp::{hal, Pins, RedLed}; +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; +use hal::prelude::*; +use hal::rtc::rtic::rtc_clock; +use rtic::app; + +hal::rtc_monotonic!(Mono, rtc_clock::Clock1k); + +#[app(device = bsp::pac, dispatchers = [EVSYS_0])] +mod app { + use super::*; + + #[local] + struct Resources {} + + #[shared] + struct Shared { + // The LED could be a local resource, since it is only used in one task + // But we want to showcase shared resources and locking + red_led: RedLed, + } + + #[init] + fn init(cx: init::Context) -> (Shared, Resources) { + let device = cx.device; + let mut core: rtic::export::Peripherals = cx.core; + + // Use v2 of the clocks API so that we can set the RTC clock source + let (_, clocks, tokens) = + clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); + + // Enable the RTC clock with the internal 1 kHz source. + // Note that currently the proof of this (the `RtcOsc` instance) is not + // required to start the monotonic. + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); + + // Start the monotonic + Mono::start(device.rtc); + + let pins = Pins::new(device.port); + + // We can use the RTC in standby for maximum power savings + core.SCB.set_sleepdeep(); + + blink_led::spawn().ok().unwrap(); + + ( + Shared { + red_led: pins.d13.into_push_pull_output(), + }, + Resources {}, + ) + } + + /// This function is spawned and never returns. + #[task(priority = 1, shared=[red_led])] + async fn blink_led(mut cx: blink_led::Context) { + loop { + // If the LED were a local resource, the lock would not be necessary + cx.shared.red_led.lock(|led| { + led.toggle().unwrap(); + }); + Mono::delay(400u64.millis()).await; + } + } +} diff --git a/boards/feather_m4/examples/blinky_rtic.rs b/boards/feather_m4/examples/blinky_rtic.rs index 8945f5cf130b..812fc88b53a6 100644 --- a/boards/feather_m4/examples/blinky_rtic.rs +++ b/boards/feather_m4/examples/blinky_rtic.rs @@ -1,77 +1,5 @@ -//! Blink an led using an RTIC software task and the RTC-based monotonic. - #![no_std] #![no_main] -use bsp::{hal, Pins, RedLed}; use feather_m4 as bsp; -#[cfg(not(feature = "use_semihosting"))] -use panic_halt as _; -#[cfg(feature = "use_semihosting")] -use panic_semihosting as _; - -use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; -use hal::prelude::*; -use hal::rtc::rtic::rtc_clock; -use rtic::app; - -hal::rtc_monotonic!(Mono, rtc_clock::Clock1k); - -#[app(device = bsp::pac, dispatchers = [EVSYS_0])] -mod app { - use super::*; - - #[local] - struct Resources {} - - #[shared] - struct Shared { - // The LED could be a local resource, since it is only used in one task - // But we want to showcase shared resources and locking - red_led: RedLed, - } - - #[init] - fn init(cx: init::Context) -> (Shared, Resources) { - let device = cx.device; - let mut core: rtic::export::Peripherals = cx.core; - - // Use v2 of the clocks API so that we can set the RTC clock source - let (_, clocks, tokens) = - clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); - - // Enable the RTC clock with the internal 1 kHz source. - // Note that currently the proof of this (the `RtcOsc` instance) is not - // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); - - // Start the monotonic - Mono::start(device.rtc); - - let pins = Pins::new(device.port); - - // We can use the RTC in standby for maximum power savings - core.SCB.set_sleepdeep(); - - blink_led::spawn().ok().unwrap(); - - ( - Shared { - red_led: pins.d13.into_push_pull_output(), - }, - Resources {}, - ) - } - - /// This function is spawned and never returns. - #[task(priority = 1, shared=[red_led])] - async fn blink_led(mut cx: blink_led::Context) { - loop { - // If the LED were a local resource, the lock would not be necessary - cx.shared.red_led.lock(|led| { - led.toggle().unwrap(); - }); - Mono::delay(400u64.millis()).await; - } - } -} +include!("../../examples/m4-blinky_rtic.rs"); diff --git a/boards/metro_m4/examples/blinky_rtic.rs b/boards/metro_m4/examples/blinky_rtic.rs index 13f39d41d5c2..34b385542b1e 100644 --- a/boards/metro_m4/examples/blinky_rtic.rs +++ b/boards/metro_m4/examples/blinky_rtic.rs @@ -1,85 +1,5 @@ -//! Blink an led using an RTIC software task and the RTC-based monotonic. - #![no_std] #![no_main] -use bsp::{hal, Pins, RedLed}; use metro_m4 as bsp; -#[cfg(not(feature = "use_semihosting"))] -use panic_halt as _; -#[cfg(feature = "use_semihosting")] -use panic_semihosting as _; - -use hal::clock::v2::{clock_system_at_reset, osculp32k::OscUlp1k, rtcosc::RtcOsc}; -use hal::prelude::*; -use hal::rtc::rtic::rtc_clock; -use rtic::app; - -hal::rtc_monotonic!(Mono, rtc_clock::Clock1k); - -#[app(device = bsp::pac, dispatchers = [EVSYS_0])] -mod app { - use super::*; - - #[local] - struct Resources {} - - #[shared] - struct Shared { - // The LED could be a local resource, since it is only used in one task - // But we want to showcase shared resources and locking - red_led: RedLed, - } - - #[init] - fn init(cx: init::Context) -> (Shared, Resources) { - let mut device = cx.device; - let mut core: rtic::export::Peripherals = cx.core; - - // Use v2 of the clocks API so that we can set the RTC clock source - let (_, clocks, tokens) = clock_system_at_reset( - device.oscctrl, - device.osc32kctrl, - device.gclk, - device.mclk, - &mut device.nvmctrl, - ); - - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - - // Enable the RTC clock with the 1 kHz source. - // Note that currently the proof of this (the `RtcOsc` instance) is not - // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); - - // Start the monotonic - Mono::start(device.rtc); - - let pins = Pins::new(device.port); - - // We can use the RTC in standby for maximum power savings - core.SCB.set_sleepdeep(); - - blink_led::spawn().ok().unwrap(); - - ( - Shared { - red_led: pins.d13.into_push_pull_output(), - }, - Resources {}, - ) - } - - /// This function is spawned and never returns. - #[task(priority = 1, shared=[red_led])] - async fn blink_led(mut cx: blink_led::Context) { - loop { - // If the LED were a local resource, the lock would not be necessary - cx.shared.red_led.lock(|led| { - led.toggle().unwrap(); - }); - Mono::delay(400u64.millis()).await; - } - } -} +include!("../../examples/m4-blinky_rtic.rs"); From a81e20715d2944aa08b26f10b39dd915b0eb2e99 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 11:35:34 +1200 Subject: [PATCH 096/114] Deduplicate feather_m4 and metro_m4 adc example --- boards/examples/m4-adc.rs | 63 +++++++++++++++++++++++++++ boards/feather_m4/examples/adc.rs | 55 +---------------------- boards/metro_m4/examples/adc.rs | 55 +---------------------- boards/metro_m4/examples/async_adc.rs | 5 +-- 4 files changed, 67 insertions(+), 111 deletions(-) create mode 100644 boards/examples/m4-adc.rs diff --git a/boards/examples/m4-adc.rs b/boards/examples/m4-adc.rs new file mode 100644 index 000000000000..f6278c5fadf7 --- /dev/null +++ b/boards/examples/m4-adc.rs @@ -0,0 +1,63 @@ +// This file is included by one or more BSP examples. In normal usage, firmware +// source code needs to start with something like: +// +// ``` +// #![no_std] +// #![no_main] +// use feather_m4 as bsp; +//``` + +use atsamd_hal::adc::AdcBuilder; + +use bsp::hal; +use bsp::pac; + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::entry; +use bsp::Pins; +use pac::{CorePeripherals, Peripherals}; + +use hal::{ + adc::{Accumulation, Prescaler}, + clock::v2::{clock_system_at_reset, pclk::Pclk}, +}; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take().unwrap(); + let _core = CorePeripherals::take().unwrap(); + + let pins = Pins::new(peripherals.port); + + let (mut buses, clocks, tokens) = clock_system_at_reset( + peripherals.oscctrl, + peripherals.osc32kctrl, + peripherals.gclk, + peripherals.mclk, + ); + + // Enable the ADC0 ABP clock... + let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); + // ...and enable the ADC0 PCLK. Both of these are required for the + // ADC to run. + let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); + + let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) + .with_clock_cycles_per_sample(5) + // Overruns if clock divider < 32 in debug mode + .with_clock_divider(Prescaler::Div32) + .with_vref(atsamd_hal::adc::Reference::Arefa) + .enable(peripherals.adc0, apb_adc0, &pclk_adc0) + .unwrap(); + let mut adc_pin = pins.a0.into_alternate(); + + loop { + let res = adc.read(&mut adc_pin); + #[cfg(feature = "use_semihosting")] + let _ = cortex_m_semihosting::hprintln!("ADC value: {}", res); + } +} diff --git a/boards/feather_m4/examples/adc.rs b/boards/feather_m4/examples/adc.rs index a8d736b0b5c5..98d4a974135a 100644 --- a/boards/feather_m4/examples/adc.rs +++ b/boards/feather_m4/examples/adc.rs @@ -1,58 +1,5 @@ #![no_std] #![no_main] -use atsamd_hal::adc::AdcBuilder; use feather_m4 as bsp; - -use bsp::hal; -use bsp::pac; - -#[cfg(not(feature = "use_semihosting"))] -use panic_halt as _; -#[cfg(feature = "use_semihosting")] -use panic_semihosting as _; - -use bsp::entry; -use bsp::Pins; -use pac::{CorePeripherals, Peripherals}; - -use hal::{ - adc::{Accumulation, Prescaler}, - clock::v2::{clock_system_at_reset, pclk::Pclk}, -}; - -#[entry] -fn main() -> ! { - let peripherals = Peripherals::take().unwrap(); - let _core = CorePeripherals::take().unwrap(); - - let pins = Pins::new(peripherals.port); - - let (mut buses, clocks, tokens) = clock_system_at_reset( - peripherals.oscctrl, - peripherals.osc32kctrl, - peripherals.gclk, - peripherals.mclk, - ); - - // Enable the ADC0 ABP clock... - let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); - // ...and enable the ADC0 PCLK. Both of these are required for the - // ADC to run. - let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); - - let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) - .with_clock_cycles_per_sample(5) - // Overruns if clock divider < 32 in debug mode - .with_clock_divider(Prescaler::Div32) - .with_vref(atsamd_hal::adc::Reference::Arefa) - .enable(peripherals.adc0, apb_adc0, &pclk_adc0) - .unwrap(); - let mut adc_pin = pins.a0.into_alternate(); - - loop { - let res = adc.read(&mut adc_pin); - #[cfg(feature = "use_semihosting")] - cortex_m_semihosting::hprintln!("ADC value: {}", res); - } -} +include!("../../examples/m4-adc.rs"); \ No newline at end of file diff --git a/boards/metro_m4/examples/adc.rs b/boards/metro_m4/examples/adc.rs index 56c46bbd97f7..8af58dc94ef4 100644 --- a/boards/metro_m4/examples/adc.rs +++ b/boards/metro_m4/examples/adc.rs @@ -1,58 +1,5 @@ #![no_std] #![no_main] -use atsamd_hal::adc::AdcBuilder; use metro_m4 as bsp; - -use bsp::hal; -use bsp::pac; - -#[cfg(not(feature = "use_semihosting"))] -use panic_halt as _; -#[cfg(feature = "use_semihosting")] -use panic_semihosting as _; - -use bsp::entry; -use bsp::Pins; -use pac::{CorePeripherals, Peripherals}; - -use hal::{ - adc::{Accumulation, Adc, Prescaler, Resolution}, - clock::v2::{clock_system_at_reset, pclk::Pclk}, -}; - -#[entry] -fn main() -> ! { - let mut peripherals = Peripherals::take().unwrap(); - let _core = CorePeripherals::take().unwrap(); - - let pins = Pins::new(peripherals.port); - - let (mut buses, clocks, tokens) = clock_system_at_reset( - peripherals.oscctrl, - peripherals.osc32kctrl, - peripherals.gclk, - peripherals.mclk, - &mut peripherals.nvmctrl, - ); - - // Enable the ADC0 ABP clock... - let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); - // ...and enable the ADC0 PCLK. Both of these are required for the - // ADC to run. - let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); - - let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) - .with_clock_cycles_per_sample(5) - .with_clock_divider(Prescaler::Div32) - .with_vref(atsamd_hal::adc::Reference::Arefa) - .enable(peripherals.adc0, apb_adc0, &pclk_adc0) - .unwrap(); - let mut adc_pin = pins.a0.into_alternate(); - - loop { - let res = adc.read(&mut adc_pin); - #[cfg(feature = "use_semihosting")] - cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap(); - } -} +include!("../../examples/m4-adc.rs"); \ No newline at end of file diff --git a/boards/metro_m4/examples/async_adc.rs b/boards/metro_m4/examples/async_adc.rs index 818e395734d7..a9fe0763369f 100644 --- a/boards/metro_m4/examples/async_adc.rs +++ b/boards/metro_m4/examples/async_adc.rs @@ -16,7 +16,7 @@ use bsp::Pins; use pac::{CorePeripherals, Peripherals}; use hal::{ - adc::{Accumulation, Adc, Adc0, Prescaler, Resolution}, + adc::{Accumulation, Adc0, Prescaler}, clock::v2::{clock_system_at_reset, pclk::Pclk}, }; @@ -26,7 +26,7 @@ atsamd_hal::bind_multiple_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_s: embassy_executor::Spawner) -> ! { - let mut peripherals = Peripherals::take().unwrap(); + let peripherals = Peripherals::take().unwrap(); let _core = CorePeripherals::take().unwrap(); let pins = Pins::new(peripherals.port); @@ -36,7 +36,6 @@ async fn main(_s: embassy_executor::Spawner) -> ! { peripherals.osc32kctrl, peripherals.gclk, peripherals.mclk, - &mut peripherals.nvmctrl, ); // Enable the ADC0 ABP clock... From 640744b147fc02b8c5bb423f63451076a9307316 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 11:39:47 +1200 Subject: [PATCH 097/114] Update pygamer blinky_rtic example Couldn't deduplicate with the feather_m4 and metro_m4 examples, because the alias used for the LED is different. Sorting that out seems like a separate project. --- boards/pygamer/examples/blinky_rtic.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/boards/pygamer/examples/blinky_rtic.rs b/boards/pygamer/examples/blinky_rtic.rs index c4549b21702c..a13bb736f57f 100644 --- a/boards/pygamer/examples/blinky_rtic.rs +++ b/boards/pygamer/examples/blinky_rtic.rs @@ -8,7 +8,7 @@ use bsp::{hal, Pins, RedLed}; use panic_halt as _; use pygamer as bsp; -use hal::clock::v2::{clock_system_at_reset, osculp32k::OscUlp1k, rtcosc::RtcOsc}; +use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; use hal::prelude::*; use hal::rtc::rtic::rtc_clock; use rtic::app; @@ -31,25 +31,17 @@ mod app { #[init] fn init(cx: init::Context) -> (Shared, Resources) { - let mut device = cx.device; + let device = cx.device; let mut core: rtic::export::Peripherals = cx.core; // Use v2 of the clocks API so that we can set the RTC clock source - let (_, clocks, tokens) = clock_system_at_reset( - device.oscctrl, - device.osc32kctrl, - device.gclk, - device.mclk, - &mut device.nvmctrl, - ); - - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - - // Enable the RTC clock with the 1 kHz source. + let (_, clocks, tokens) = + clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); + + // Enable the RTC clock with the internal 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); // Start the monotonic Mono::start(device.rtc); From 0c08af4fb9571206b98788911958032c4433ef29 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 12:21:41 +1200 Subject: [PATCH 098/114] Update atsame54_xpro examples --- boards/atsame54_xpro/examples/blinky_rtic.rs | 10 +++------- boards/atsame54_xpro/examples/mcan.rs | 12 ++++-------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/boards/atsame54_xpro/examples/blinky_rtic.rs b/boards/atsame54_xpro/examples/blinky_rtic.rs index e331bedfcfa9..4289dfd56ee1 100644 --- a/boards/atsame54_xpro/examples/blinky_rtic.rs +++ b/boards/atsame54_xpro/examples/blinky_rtic.rs @@ -3,7 +3,7 @@ use atsame54_xpro as bsp; use bsp::hal; -use hal::clock::v2::{clock_system_at_reset, osculp32k::OscUlp1k, rtcosc::RtcOsc}; +use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; use hal::prelude::*; use hal::rtc::rtic::rtc_clock; use panic_rtt_target as _; @@ -27,7 +27,7 @@ mod app { #[init] fn init(ctx: init::Context) -> (Shared, Local) { - let mut device = ctx.device; + let device = ctx.device; let mut core: rtic::export::Peripherals = ctx.core; rtt_init_print!(); @@ -37,16 +37,12 @@ mod app { device.osc32kctrl, device.gclk, device.mclk, - &mut device.nvmctrl, ); - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - // Enable the RTC clock with the 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); // Start the monotonic Mono::start(device.rtc); diff --git a/boards/atsame54_xpro/examples/mcan.rs b/boards/atsame54_xpro/examples/mcan.rs index 5cad635297f6..6ba28ca63424 100644 --- a/boards/atsame54_xpro/examples/mcan.rs +++ b/boards/atsame54_xpro/examples/mcan.rs @@ -21,7 +21,7 @@ use atsame54_xpro as bsp; use bsp::hal; -use clock::{osculp32k::OscUlp1k, rtcosc::RtcOsc}; +use clock::rtcosc::RtcOsc; use hal::clock::v2 as clock; use hal::eic::{Ch15, Eic, ExtInt, Sense}; use hal::gpio::{Interrupt as GpioInterrupt, *}; @@ -115,7 +115,7 @@ mod app { can_memory: SharedMemory = SharedMemory::new() ])] fn init(ctx: init::Context) -> (Shared, Local) { - let mut device = ctx.device; + let device = ctx.device; rtt_init_print!(); rprintln!("Application up!"); @@ -125,16 +125,12 @@ mod app { device.osc32kctrl, device.gclk, device.mclk, - &mut device.nvmctrl, ); - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - // Enable the RTC clock with the 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); // Start the monotonic Mono::start(device.rtc); @@ -159,7 +155,7 @@ mod app { let _ = can1_standby.set_low(); - let (pclk_can1, gclk0) = clock::pclk::Pclk::enable(tokens.pclks.can1, gclk0); + let (pclk_can1, _gclk0) = clock::pclk::Pclk::enable(tokens.pclks.can1, gclk0); let (dependencies, _gclk0) = hal::can::Dependencies::new( gclk0, From 9d1ec8a5c6ef78d6fe92e631ab1a223c391676b0 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 12:31:04 +1200 Subject: [PATCH 099/114] dfll tidy --- hal/src/clock/v2/dfll.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index 1f4dbfc91d24..8227771c1ed6 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -274,7 +274,7 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] mod imports { pub use crate::pac::Oscctrl as PERIPHERAL; pub use crate::pac::oscctrl::{ @@ -282,10 +282,10 @@ mod imports { }; } -#[hal_cfg(any("clock-d11", "clock-d21"))] +#[hal_cfg("sysctrl")] mod imports { pub use crate::pac::Sysctrl as PERIPHERAL; - pub use crate::pac::sysctrl::{Dfllctrl, Dfllmul, Dfllsync, RegisterBlock}; + pub use crate::pac::sysctrl::{Dfllctrl, Dfllmul, RegisterBlock}; } use fugit::RateExtU32; From 11f357c0ca4c35d925b58496998fec46f20d3551 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 12:48:34 +1200 Subject: [PATCH 100/114] TEMPORARY enable clock v2 for thumbv6 in delay --- hal/src/delay.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hal/src/delay.rs b/hal/src/delay.rs index 3ea6aa60bc8a..aad0273f3447 100644 --- a/hal/src/delay.rs +++ b/hal/src/delay.rs @@ -1,6 +1,5 @@ //! Delays -use atsamd_hal_macros::hal_cfg; use cortex_m::peripheral::SYST; use cortex_m::peripheral::syst::SystClkSource; @@ -9,10 +8,8 @@ use crate::ehal::delay::DelayNs; use crate::ehal_02; use crate::time::Hertz; -#[hal_cfg("rtc-d5x")] use crate::typelevel::Increment; -#[hal_cfg("rtc-d5x")] use crate::clock::v2::{Source, gclk::Gclk0Id}; /// System timer (SysTick) as a delay provider @@ -32,7 +29,6 @@ impl Delay { } } - #[hal_cfg("rtc-d5x")] /// Configures the system timer (SysTick) as a delay provide, compatible /// with the V2 clocking API pub fn new_with_source(mut syst: SYST, gclk0: S) -> (Self, S::Inc) From ac25db868acaaf948e8088f28c2b2433ebfa0047 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 12:52:02 +1200 Subject: [PATCH 101/114] Metro M0 blinky_basic update to clock v2 --- boards/metro_m0/examples/blinky_basic.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/boards/metro_m0/examples/blinky_basic.rs b/boards/metro_m0/examples/blinky_basic.rs index 0a41c9297814..5904df598d8f 100644 --- a/boards/metro_m0/examples/blinky_basic.rs +++ b/boards/metro_m0/examples/blinky_basic.rs @@ -11,24 +11,23 @@ use bsp::pac; use metro_m0 as bsp; use bsp::entry; -use hal::clock::GenericClockController; +use hal::clock::v2 as clock; use hal::delay::Delay; use hal::prelude::*; use pac::{CorePeripherals, Peripherals}; #[entry] fn main() -> ! { - let mut peripherals = Peripherals::take().unwrap(); + let peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); - let mut clocks = GenericClockController::with_external_32kosc( - peripherals.gclk, - &mut peripherals.pm, - &mut peripherals.sysctrl, - &mut peripherals.nvmctrl, - ); + let (_buses, clocks, _tokens) = + clock::clock_system_at_reset(peripherals.gclk, peripherals.pm, peripherals.sysctrl); + + let gclk0 = clocks.gclk0; + let (mut delay, _gclk0) = Delay::new_with_source(core.SYST, gclk0); + let pins = bsp::Pins::new(peripherals.port); let mut red_led: bsp::RedLed = pins.d13.into(); - let mut delay = Delay::new(core.SYST, &mut clocks); loop { delay.delay_ms(200u8); red_led.set_high().unwrap(); From 24a944fa232355f4661c5cf2e06a99c3677a0841 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 15:53:57 +1200 Subject: [PATCH 102/114] Clippy --- hal/src/clock/v2/apb.rs | 2 +- hal/src/clock/v2/dfll.rs | 8 ++++---- hal/src/clock/v2/dpll.rs | 2 +- hal/src/clock/v2/gclk.rs | 6 +++--- hal/src/clock/v2/osc.rs | 2 +- hal/src/clock/v2/osc32k.rs | 2 +- hal/src/clock/v2/osculp32k.rs | 4 ++-- hal/src/clock/v2/pclk.rs | 5 ++--- hal/src/clock/v2/xosc.rs | 4 ++-- hal/src/clock/v2/xosc32k.rs | 4 ++-- 10 files changed, 19 insertions(+), 20 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 27b9eb6680a2..1855be8fa7ab 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -198,7 +198,7 @@ impl Apb { #[inline] #[hal_cfg("clock-d5x")] fn apbdmask(&mut self) -> &Apbdmask { - &self.mclk().apbdmask() + self.mclk().apbdmask() } #[inline] diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index 8227771c1ed6..3dc39520b4db 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -337,13 +337,13 @@ impl DfllToken { #[hal_cfg("clock-d5x")] #[inline] fn dfllctrl(&self) -> &Dfllctrl { - &self.reg_block().dfllctrla() + self.reg_block().dfllctrla() } #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] fn dfllctrl(&self) -> &Dfllctrl { - &self.reg_block().dfllctrl() + self.reg_block().dfllctrl() } #[hal_cfg("clock-d5x")] @@ -354,13 +354,13 @@ impl DfllToken { #[inline] fn dfllmul(&self) -> &Dfllmul { - &self.reg_block().dfllmul() + self.reg_block().dfllmul() } #[hal_cfg("clock-d5x")] #[inline] fn dfllsync(&self) -> &Dfllsync { - &self.reg_block().dfllsync() + self.reg_block().dfllsync() } #[hal_cfg("clock-d5x")] diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 8c295c89e529..e65886c973e4 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -320,7 +320,7 @@ impl DpllToken { // memory safety in the root of the `clock` module for more details. #[hal_cfg("oscctrl")] unsafe { - &(*Peripheral::PTR).dpll(D::NUM) + (*Peripheral::PTR).dpll(D::NUM) } #[hal_cfg("sysctrl")] unsafe { diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 2a90661c57e4..5d3717f579be 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -415,18 +415,18 @@ impl GclkToken { // memory safety in the root of the `clock` module for more details. #[hal_cfg("clock-d5x")] unsafe { - &(*pac::Gclk::PTR).genctrl(G::NUM) + (*pac::Gclk::PTR).genctrl(G::NUM) } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*pac::Gclk::PTR).genctrl() + (*pac::Gclk::PTR).genctrl() } } #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] fn gendiv(&self) -> &Gendiv { - unsafe { &(*pac::Gclk::PTR).gendiv() } + unsafe { (*pac::Gclk::PTR).gendiv() } } /// Block until synchronization has completed diff --git a/hal/src/clock/v2/osc.rs b/hal/src/clock/v2/osc.rs index 71fb9013e354..d0ebbae9c7a8 100644 --- a/hal/src/clock/v2/osc.rs +++ b/hal/src/clock/v2/osc.rs @@ -18,7 +18,7 @@ impl OscToken { } fn osc8m(&self) -> &Osc8m { - unsafe { &(*Sysctrl::PTR).osc8m() } + unsafe { (*Sysctrl::PTR).osc8m() } } fn enable(&mut self, settings: Settings) { diff --git a/hal/src/clock/v2/osc32k.rs b/hal/src/clock/v2/osc32k.rs index 39d7fb2dc646..3288210c1c73 100644 --- a/hal/src/clock/v2/osc32k.rs +++ b/hal/src/clock/v2/osc32k.rs @@ -254,7 +254,7 @@ impl Osc32kBaseToken { // Safety: The `Osc32kBaseToken` has exclusive access to the // `OSC32K` register. See the notes on `Token` types and memory // safety in the root of the `clock` module for more details. - unsafe { &(*crate::pac::Sysctrl::PTR).osc32k() } + unsafe { (*crate::pac::Sysctrl::PTR).osc32k() } } /// Set the calibration diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index 64a1cb72df56..df5b98136ac1 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -228,11 +228,11 @@ impl OscUlp32kBaseToken { // safety in the root of the `clock` module for more details. #[hal_cfg("osc32kctrl")] unsafe { - &(*crate::pac::Osc32kctrl::PTR).osculp32k() + (*crate::pac::Osc32kctrl::PTR).osculp32k() } #[hal_cfg("sysctrl")] unsafe { - &(*crate::pac::Sysctrl::PTR).osculp32k() + (*crate::pac::Sysctrl::PTR).osculp32k() } } diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 991aa396ae6c..ace79da62e7a 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -133,11 +133,11 @@ impl PclkToken

{ // memory safety in the root of the `clock` module for more details. #[hal_cfg("clock-d5x")] unsafe { - &(*pac::Gclk::PTR).pchctrl(P::DYN as usize) + (*pac::Gclk::PTR).pchctrl(P::DYN as usize) } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*pac::Gclk::PTR).clkctrl() + (*pac::Gclk::PTR).clkctrl() } } @@ -186,7 +186,6 @@ impl PclkToken

{ /// ``` /// use atsamd_hal::clock::v2::pclk::ids::*; /// ``` - pub mod ids { use atsamd_hal_macros::hal_cfg; diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 7f0a437aad2f..4c1e5b2ef420 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -281,11 +281,11 @@ impl XoscToken { // memory safety in the root of the `clock` module for more details. #[hal_cfg("clock-d5x")] unsafe { - &(*Peripheral::PTR).xoscctrl(X::NUM) + (*Peripheral::PTR).xoscctrl(X::NUM) } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*Peripheral::PTR).xosc() + (*Peripheral::PTR).xosc() } } diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index a3cd6d7857df..dbb8de87e9b9 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -478,7 +478,7 @@ impl Xosc32kBaseToken { // Safety: The `Xosc32kBaseToken` has exclusive access to the `XOSC32K` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { &(*PERIPHERAL::PTR).xosc32k() } + unsafe { (*PERIPHERAL::PTR).xosc32k() } } /// Reset the XOSC32K register @@ -570,7 +570,7 @@ impl Xosc32kCfdToken { // Safety: The `Xosc32kCfdToken` has exclusive access to the `Cfdctrl` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { &(*PERIPHERAL::PTR).cfdctrl() } + unsafe { (*PERIPHERAL::PTR).cfdctrl() } } /// Enable clock failure detection and set the safe clock divider From 330fd25bf06fd5141ab8f0b6a8cfc9defa07c400 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 1 Aug 2025 21:31:57 +1200 Subject: [PATCH 103/114] Fix polarity in DPLL wait_enabled() --- hal/src/clock/v2/dpll.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index e65886c973e4..b67f3484a981 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -413,13 +413,14 @@ impl DpllToken { self.wait_disabled(); } + /// Waits for the enable bit to synchronize in the enabled state #[inline] #[hal_macro_helper] fn wait_enabled(&self) { #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} #[hal_cfg("sysctrl")] - while self.status().enable().bit_is_clear() {} + while self.status().enable().bit_is_set() {} } #[inline] From c3325890e850f1ffc4c8f08a605ab5203b3e55a8 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 1 Aug 2025 16:41:19 +1200 Subject: [PATCH 104/114] Fix missing ID field in GCLK divider selection --- hal/src/clock/v2/gclk.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 5d3717f579be..a7d42dcee23a 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -521,6 +521,13 @@ impl GclkToken { #[hal_macro_helper] fn enable(&mut self, id: DynGclkSourceId, settings: Settings) { let (divsel, div) = settings.div.divsel_div(); + #[hal_cfg(any("clock-d11", "clock-d21"))] + self.gendiv().write(|w| unsafe { + w.id().bits(G::NUM as u8); + w.div().bits(div) + }); + #[hal_cfg(any("clock-d11", "clock-d21"))] + self.wait_syncbusy(); self.genctrl().write(|w| { // Safety: The `DIVSEL` and `DIV` values are derived from the // `GclkDivider` type, so they are guaranteed to be valid. From b67d9d7778f7a6d91131188a666c62d62f83a70a Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 1 Aug 2025 16:54:37 +1200 Subject: [PATCH 105/114] GCLK refactor Reading the GCLK GENCTRL register isn't possible on the thumbv6m chips, on these there is only one GENCTRL register for the whole GCLK peripheral, in contrast to one GENCTRL per generator on the thumbv7em chips. On the thumbv6m chips, modifying GENCTRL is done by atomically writing the whole register, which has a field for the generator ID to be modified. The GENCTRL register had been modified from the GclkToken<> impl, per-field, but the state required to fill the other fields for the atomic register write wasn't available in the GclkToken<> scope. So, these GENCTRL accesses were moved up in to the Gclk<> impl. One more bit of state was added to the settings to handle the Output Enable bit. --- hal/src/clock/v2/gclk.rs | 288 ++++++++++++++++++++++----------------- 1 file changed, 163 insertions(+), 125 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index a7d42dcee23a..bfbd8fce5fc2 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -348,7 +348,7 @@ use crate::gpio::{self, AlternateH, AnyPin, Pin, PinId}; use crate::pac::gclk::Genctrl; #[hal_cfg(any("clock-d11", "clock-d21"))] use crate::pac::gclk::Gendiv; -use crate::pac::gclk::genctrl::Srcselect; +use crate::pac::gclk::genctrl::{self, Srcselect}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; @@ -376,12 +376,13 @@ use super::{Enabled, Source}; /// various `Token` types can be exchanged for actual clock types. They /// typically represent clocks that are disabled at power-on reset. /// -/// [`GclkToken`]s are no different. All [`Gclk`]s other than [`Gclk0`] are -/// disabled at power-on reset. To use a [`Gclk`], you must first exchange the -/// token for an actual clock with [`Gclk::from_source`] or [`Gclk::from_pin`]. +/// [`GclkToken`]s are no different. [`Gclk`]s other than [`Gclk0`], and +/// [`Gclk2`] on SAMD21/SAMD11, are disabled at power-on reset. To use a +/// [`Gclk`], you must first exchange the token for an actual clock with +/// [`Gclk::from_source`] or [`Gclk::from_pin`]. /// /// [`GclkToken`] is generic over the [`GclkId`], where each corresponding token -/// represents one of the 12 respective [`Gclk`]s. +/// represents one of the [`Gclk`]s. pub struct GclkToken { generator: PhantomData, } @@ -450,109 +451,6 @@ impl GclkToken { while status.read().syncbusy().bit() {} } } - - /// Set the clock source for this [`Gclk`] - #[inline] - fn set_source(&mut self, source: DynGclkSourceId) { - self.genctrl().modify(|_, w| w.src().variant(source.into())); - self.wait_syncbusy(); - } - - /// Set the [`GclkDivider`] value - /// - /// Use the internal interface of [`GclkDivider`] to set the `DIV` and - /// `DIVSEL` fields of the `GENCTRL` register. - #[inline] - #[hal_macro_helper] - fn set_div(&mut self, div: G::Divider) { - let (divsel, div) = div.divsel_div(); - // Safety: The `DIVSEL` and `DIV` values are derived from the - // `GclkDivider` type, so they are guaranteed to be valid. - #[hal_cfg("clock-d5x")] - { - self.genctrl().modify(|_, w| unsafe { - w.divsel().bit(divsel); - w.div().bits(div) - }); - } - #[hal_cfg(any("clock-d11", "clock-d21"))] - { - self.genctrl().write(|w| { - unsafe { w.id().bits(G::NUM as u8) }; - w.divsel().bit(divsel) - }); - self.gendiv().write(|w| unsafe { w.div().bits(div) }); - } - self.wait_syncbusy(); - } - - /// Output a 50-50 duty-cycle clock when using an odd division factor - #[inline] - fn improve_duty_cycle(&mut self, flag: bool) { - self.genctrl().modify(|_, w| w.idc().bit(flag)); - self.wait_syncbusy(); - } - - /// Set the state of [`GclkOut`] pins when the GCLK_IO output is disabled - #[inline] - fn output_off_value(&mut self, high: bool) { - self.genctrl().modify(|_, w| w.oov().bit(high)); - self.wait_syncbusy(); - } - - /// Enable [`Gclk`] output to a GPIO [`Pin`] - #[inline] - fn enable_gclk_out(&mut self) { - self.genctrl().modify(|_, w| w.oe().set_bit()); - self.wait_syncbusy(); - } - - /// Disable [`Gclk`] output on a GPIO [`Pin`] - /// - /// If a corresponding [`Pin`] is in the [`AlternateH`] mode, it's logic - /// level will depend on the [`output_off_value`]. - #[inline] - fn disable_gclk_out(&mut self) { - self.genctrl().modify(|_, w| w.oe().clear_bit()); - self.wait_syncbusy(); - } - - #[inline] - #[hal_macro_helper] - fn enable(&mut self, id: DynGclkSourceId, settings: Settings) { - let (divsel, div) = settings.div.divsel_div(); - #[hal_cfg(any("clock-d11", "clock-d21"))] - self.gendiv().write(|w| unsafe { - w.id().bits(G::NUM as u8); - w.div().bits(div) - }); - #[hal_cfg(any("clock-d11", "clock-d21"))] - self.wait_syncbusy(); - self.genctrl().write(|w| { - // Safety: The `DIVSEL` and `DIV` values are derived from the - // `GclkDivider` type, so they are guaranteed to be valid. - unsafe { - #[hal_cfg("clock-d5x")] - w.div().bits(div); - #[hal_cfg(any("clock-d11", "clock-d21"))] - w.id().bits(G::NUM as u8); - }; - w.divsel().bit(divsel); - w.src().variant(id.into()); - w.idc().bit(settings.improve_duty_cycle); - w.oov().bit(settings.output_off_value) - }); - #[hal_cfg(any("clock-d11", "clock-d21"))] - self.gendiv().write(|w| unsafe { w.div().bits(div) }); - self.wait_syncbusy(); - } - - /// Disable the [`Gclk`] - #[inline] - fn disable(&mut self) { - self.genctrl().write(|w| w.genen().clear_bit()); - self.wait_syncbusy(); - } } //============================================================================== @@ -1133,11 +1031,16 @@ impl> NotGclkIo for I {} // Settings //============================================================================== -/// Collection of [`Gclk`] settings to configure on enable +/// Collection of [`Gclk`] settings +/// +/// This structure is largely required due to the thumbv6m chips sharing one +/// GENCTRL register among all the clock generators. On these chips, all fields +/// in the register need to be updated by a 32b atomic write. struct Settings { div: G::Divider, output_off_value: bool, improve_duty_cycle: bool, + output_enable: bool, } impl Clone for Settings { @@ -1154,6 +1057,7 @@ impl Default for Settings { div: G::Divider::default(), output_off_value: false, improve_duty_cycle: false, + output_enable: false, } } } @@ -1351,21 +1255,57 @@ where G: GclkId, I: GclkSourceId, { + #[hal_macro_helper] + fn update_genctrl(&self, writer: F, genen: bool) { + #[hal_cfg("clock-d5x")] + self.token.genctrl().modify(|_, w| { + let _ = genen; // Suppress warning on d5x builds + writer(w); + w + }); + + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + let (divsel, _div) = self.settings.div.divsel_div(); + + self.token.genctrl().write(|w| { + unsafe { w.id().bits(G::NUM as u8) }; + w.src().variant(I::DYN.into()); + w.divsel().bit(divsel); + w.oe().bit(self.settings.output_enable); + w.oov().bit(self.settings.output_off_value); + w.idc().bit(self.settings.improve_duty_cycle); + w.genen().bit(genen); + writer(w); + w + }); + } + self.token.wait_syncbusy(); + } + /// Modify the source of an existing clock /// /// This is a helper function for swapping Gclk0 to different clock sources. fn change_source( - mut self, + self, resource: N::Resource, freq: Hertz, ) -> (Gclk, I::Resource) { - self.token.set_source(N::DYN); let gclk = Gclk { token: self.token, resource, src_freq: freq, settings: self.settings, }; + + // Call update_genctrl() on object that has the correct source type + gclk.update_genctrl( + |w| { + w.src().variant(N::DYN.into()); + }, + // This method is always called on Gclk0, which is always enabled + true, + ); (gclk, self.resource) } @@ -1420,7 +1360,14 @@ where #[inline] pub fn output_off_value(mut self, high: bool) -> Self { self.settings.output_off_value = high; - self.token.output_off_value(high); + self.update_genctrl( + |w| { + w.oov().bit(high); + }, + // This method is only accessible via disabled GCLKs + false, + ); + self } @@ -1434,8 +1381,37 @@ where /// The returned value is an [`EnabledGclk`] that can be used as a clock /// [`Source`] for other clocks. #[inline] - pub fn enable(mut self) -> EnabledGclk { - self.token.enable(I::DYN, self.settings); + #[hal_macro_helper] + pub fn enable(self) -> EnabledGclk { + let (divsel, div) = self.settings.div.divsel_div(); + + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + self.token.gendiv().write(|w| unsafe { + w.id().bits(G::NUM as u8); + w.div().bits(div) + }); + self.token.wait_syncbusy(); + } + + self.token.genctrl().write(|w| { + // Safety: The `DIVSEL` and `DIV` values are derived from the + // `GclkDivider` type, so they are guaranteed to be valid. + unsafe { + #[hal_cfg("clock-d5x")] + w.div().bits(div); + #[hal_cfg(any("clock-d11", "clock-d21"))] + w.id().bits(G::NUM as u8); + }; + w.divsel().bit(divsel); + w.src().variant(I::DYN.into()); + w.idc().bit(self.settings.improve_duty_cycle); + w.oe().bit(self.settings.output_enable); + w.oov().bit(self.settings.output_off_value); + w.genen().set_bit() + }); + self.token.wait_syncbusy(); + Enabled::new(self) } } @@ -1450,8 +1426,13 @@ where /// This method is only implemented for `N = U0`, which means the clock can /// only be disabled when no other clocks consume this [`Gclk`]. #[inline] - pub fn disable(mut self) -> Gclk { - self.0.token.disable(); + pub fn disable(self) -> Gclk { + self.0.update_genctrl( + |w| { + w.genen().clear_bit(); + }, + false, + ); self.0 } } @@ -1473,6 +1454,11 @@ impl EnabledGclk0 { /// Swap [`Gclk0`] from one clock [`Source`] to another /// /// `Gclk0` will remain fully enabled during the swap. + /// + /// Note for thumbv6m chips: Before switching the Generic Clock Generator 0 + /// (GCLKGEN0) from a clock source A to another clock source B, enable the + /// "ONDEMAND" feature of the clock source A to ensure a proper transition + /// from clock source A to clock source B. #[inline] pub fn swap_sources(self, old: O, new: N) -> (EnabledGclk0, O::Dec, N::Inc) where @@ -1488,6 +1474,7 @@ impl EnabledGclk0 { /// Swap [`Gclk0`] from one [`GclkIo`] [`Pin`] to another /// /// `Gclk0` will remain fully enabled during the swap. + /// TODO there's only one input IO pad per... #[inline] pub fn swap_pins

( self, @@ -1549,16 +1536,46 @@ impl EnabledGclk0 { /// /// See [`Gclk::div`] documentation for more details. #[inline] - pub fn div(&mut self, div: GclkDiv8) { - self.0.settings.div = div; - self.0.token.set_div(div); + #[hal_macro_helper] + pub fn div(&mut self, divider: GclkDiv8) { + self.0.settings.div = divider; + + let (divsel, div) = divider.divsel_div(); + + // D5x div is in the GENCTRL register, smaller chips keep it separate + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + self.0.token.gendiv().write(|w| unsafe { + w.id().bits(0); + w.div().bits(div) + }); + self.0.token.wait_syncbusy(); + } + + self.0.update_genctrl( + |w| { + // Safety: The `DIVSEL` and `DIV` values are derived from the + // `GclkDivider` type, so they are guaranteed to be valid. + #[hal_cfg("clock-d5x")] + unsafe { + w.div().bits(div); + } + w.divsel().bit(divsel); + }, + true, + ); } /// Output a 50-50 duty cycle clock when using an odd [`GclkDivider`] #[inline] pub fn improve_duty_cycle(&mut self, flag: bool) { self.0.settings.improve_duty_cycle = flag; - self.0.token.improve_duty_cycle(flag); + self.0.update_genctrl( + |w| { + w.idc().bit(flag); + }, + true, + ); } /// Return the [`Gclk0`] frequency @@ -1575,7 +1592,12 @@ impl EnabledGclk0 { #[inline] pub fn output_off_value(&mut self, high: bool) { self.0.settings.output_off_value = high; - self.0.token.output_off_value(high); + self.0.update_genctrl( + |w| { + w.oov().bit(high); + }, + true, + ); } } @@ -1711,9 +1733,18 @@ where P::Id: GclkIo, { let pin = pin.into().into_mode(); - let freq = self.freq(); - self.0.token.enable_gclk_out(); - let gclk_out = GclkOut { pin, freq }; + self.0.settings.output_enable = true; + self.0.update_genctrl( + |w| { + w.oe().set_bit(); + }, + true, + ); + + let gclk_out = GclkOut { + pin, + freq: self.freq(), + }; (self.inc(), gclk_out) } @@ -1732,7 +1763,14 @@ where N: Decrement, I: GclkIo, { - self.0.token.disable_gclk_out(); + self.0.settings.output_enable = false; + self.0.update_genctrl( + |w| { + w.oe().clear_bit(); + }, + true, + ); + (self.dec(), gclk_out.pin) } } From e82dde24c850bfc05dec399465ae17ad295e9074 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 9 Aug 2025 16:57:21 +1200 Subject: [PATCH 106/114] GCLK refactor to update entire GENCTRL --- hal/src/clock/v2/gclk.rs | 123 +++++++++++++-------------------------- 1 file changed, 39 insertions(+), 84 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index bfbd8fce5fc2..7b6b119b700a 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -348,7 +348,7 @@ use crate::gpio::{self, AlternateH, AnyPin, Pin, PinId}; use crate::pac::gclk::Genctrl; #[hal_cfg(any("clock-d11", "clock-d21"))] use crate::pac::gclk::Gendiv; -use crate::pac::gclk::genctrl::{self, Srcselect}; +use crate::pac::gclk::genctrl::Srcselect; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; @@ -1255,31 +1255,49 @@ where G: GclkId, I: GclkSourceId, { + /// Updates the GENCTRL register based on self.settings + /// + /// The thumbv7em chips use one GENCTRL per clock generator and are capable + /// of read-modify-write operations, but the thumbv6 chips share one GENCTRL + /// register among the clock generators so only support writes. To + /// accommodate both, this implementation maintains a [`Settings`] struct + /// containing the GENCTRL settings, and this method is called after + /// updating it to apply them. #[hal_macro_helper] - fn update_genctrl(&self, writer: F, genen: bool) { + fn update_genctrl(&self, genen: bool) { + let (divsel, div) = self.settings.div.divsel_div(); + #[hal_cfg("clock-d5x")] self.token.genctrl().modify(|_, w| { - let _ = genen; // Suppress warning on d5x builds - writer(w); - w + w.divsel().bit(divsel); + // Safety: The `DIVSEL` and `DIV` values are derived from the + // `GclkDivider` type, so they are guaranteed to be valid. + unsafe { + w.div().bits(div); + } + w.oe().bit(self.settings.output_enable); + w.oov().bit(self.settings.output_off_value); + w.idc().bit(self.settings.improve_duty_cycle); + w.genen().bit(genen); + w.src().variant(I::DYN.into()) }); #[hal_cfg(any("clock-d11", "clock-d21"))] { - let (divsel, _div) = self.settings.div.divsel_div(); + // Suppress warning for thumbv7em builds + let _ = div; self.token.genctrl().write(|w| { - unsafe { w.id().bits(G::NUM as u8) }; - w.src().variant(I::DYN.into()); w.divsel().bit(divsel); w.oe().bit(self.settings.output_enable); w.oov().bit(self.settings.output_off_value); w.idc().bit(self.settings.improve_duty_cycle); w.genen().bit(genen); - writer(w); - w + w.src().variant(I::DYN.into()); + unsafe { w.id().bits(G::NUM as u8) } }); } + self.token.wait_syncbusy(); } @@ -1300,9 +1318,6 @@ where // Call update_genctrl() on object that has the correct source type gclk.update_genctrl( - |w| { - w.src().variant(N::DYN.into()); - }, // This method is always called on Gclk0, which is always enabled true, ); @@ -1361,9 +1376,6 @@ where pub fn output_off_value(mut self, high: bool) -> Self { self.settings.output_off_value = high; self.update_genctrl( - |w| { - w.oov().bit(high); - }, // This method is only accessible via disabled GCLKs false, ); @@ -1373,20 +1385,14 @@ where /// Enable the [`Gclk`], so that it can be used as a clock [`Source`] /// - /// As mentioned in the [`Gclk`] documentation, no hardware registers are - /// actually modified until this call. Rather, the desired configuration is - /// stored internally, and the [`Gclk`] is initialized and configured here - /// according to the datasheet. - /// /// The returned value is an [`EnabledGclk`] that can be used as a clock /// [`Source`] for other clocks. #[inline] #[hal_macro_helper] pub fn enable(self) -> EnabledGclk { - let (divsel, div) = self.settings.div.divsel_div(); - #[hal_cfg(any("clock-d11", "clock-d21"))] { + let (_divsel, div) = self.settings.div.divsel_div(); self.token.gendiv().write(|w| unsafe { w.id().bits(G::NUM as u8); w.div().bits(div) @@ -1394,23 +1400,7 @@ where self.token.wait_syncbusy(); } - self.token.genctrl().write(|w| { - // Safety: The `DIVSEL` and `DIV` values are derived from the - // `GclkDivider` type, so they are guaranteed to be valid. - unsafe { - #[hal_cfg("clock-d5x")] - w.div().bits(div); - #[hal_cfg(any("clock-d11", "clock-d21"))] - w.id().bits(G::NUM as u8); - }; - w.divsel().bit(divsel); - w.src().variant(I::DYN.into()); - w.idc().bit(self.settings.improve_duty_cycle); - w.oe().bit(self.settings.output_enable); - w.oov().bit(self.settings.output_off_value); - w.genen().set_bit() - }); - self.token.wait_syncbusy(); + self.update_genctrl(true); Enabled::new(self) } @@ -1427,12 +1417,7 @@ where /// only be disabled when no other clocks consume this [`Gclk`]. #[inline] pub fn disable(self) -> Gclk { - self.0.update_genctrl( - |w| { - w.genen().clear_bit(); - }, - false, - ); + self.0.update_genctrl(false); self.0 } } @@ -1540,11 +1525,12 @@ impl EnabledGclk0 { pub fn div(&mut self, divider: GclkDiv8) { self.0.settings.div = divider; - let (divsel, div) = divider.divsel_div(); - // D5x div is in the GENCTRL register, smaller chips keep it separate #[hal_cfg(any("clock-d11", "clock-d21"))] { + let (_divsel, div) = divider.divsel_div(); + // Safety: The `DIVSEL` and `DIV` values are derived from the + // `GclkDivider` type, so they are guaranteed to be valid. self.0.token.gendiv().write(|w| unsafe { w.id().bits(0); w.div().bits(div) @@ -1552,30 +1538,14 @@ impl EnabledGclk0 { self.0.token.wait_syncbusy(); } - self.0.update_genctrl( - |w| { - // Safety: The `DIVSEL` and `DIV` values are derived from the - // `GclkDivider` type, so they are guaranteed to be valid. - #[hal_cfg("clock-d5x")] - unsafe { - w.div().bits(div); - } - w.divsel().bit(divsel); - }, - true, - ); + self.0.update_genctrl(true); } /// Output a 50-50 duty cycle clock when using an odd [`GclkDivider`] #[inline] pub fn improve_duty_cycle(&mut self, flag: bool) { self.0.settings.improve_duty_cycle = flag; - self.0.update_genctrl( - |w| { - w.idc().bit(flag); - }, - true, - ); + self.0.update_genctrl(true); } /// Return the [`Gclk0`] frequency @@ -1592,12 +1562,7 @@ impl EnabledGclk0 { #[inline] pub fn output_off_value(&mut self, high: bool) { self.0.settings.output_off_value = high; - self.0.update_genctrl( - |w| { - w.oov().bit(high); - }, - true, - ); + self.0.update_genctrl(true); } } @@ -1734,12 +1699,7 @@ where { let pin = pin.into().into_mode(); self.0.settings.output_enable = true; - self.0.update_genctrl( - |w| { - w.oe().set_bit(); - }, - true, - ); + self.0.update_genctrl(true); let gclk_out = GclkOut { pin, @@ -1764,12 +1724,7 @@ where I: GclkIo, { self.0.settings.output_enable = false; - self.0.update_genctrl( - |w| { - w.oe().clear_bit(); - }, - true, - ); + self.0.update_genctrl(true); (self.dec(), gclk_out.pin) } From 2dee8da8c4bc70c2a4c234565323687775e54990 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 9 Aug 2025 22:30:45 +1200 Subject: [PATCH 107/114] bsp(atsame54_xpro): Fix example --- boards/atsame54_xpro/examples/mcan.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/atsame54_xpro/examples/mcan.rs b/boards/atsame54_xpro/examples/mcan.rs index 6ba28ca63424..d79541b3561c 100644 --- a/boards/atsame54_xpro/examples/mcan.rs +++ b/boards/atsame54_xpro/examples/mcan.rs @@ -155,7 +155,7 @@ mod app { let _ = can1_standby.set_low(); - let (pclk_can1, _gclk0) = clock::pclk::Pclk::enable(tokens.pclks.can1, gclk0); + let (pclk_can1, gclk0) = clock::pclk::Pclk::enable(tokens.pclks.can1, gclk0); let (dependencies, _gclk0) = hal::can::Dependencies::new( gclk0, From 77d032ad8a58e4cb8b8cb4f351111492f56b8e77 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 17 Aug 2025 09:27:06 +1200 Subject: [PATCH 108/114] Documentation warnings for SAMD21G --- hal/src/clock/v2.rs | 85 ++++++++++++++---------------- hal/src/clock/v2/dpll.rs | 23 ++++---- hal/src/clock/v2/gclk.rs | 32 +++++------ hal/src/clock/v2/osc32k.rs | 42 +++++++-------- hal/src/clock/v2/osculp32k.rs | 20 +++++-- hal/src/clock/v2/reset_thumbv6m.rs | 16 +++--- hal/src/clock/v2/xosc.rs | 54 +++++++++++-------- hal/src/clock/v2/xosc32k.rs | 58 +++++++++++++------- hal/src/sercom/dma.rs | 14 +++-- 9 files changed, 186 insertions(+), 158 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 99a3959fe1d4..3095055a5b80 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -65,7 +65,7 @@ //! In general, there are two classes of clock in ATSAMD chips. Some clocks map //! one-to-one (1:1) to a specific bus or peripheral. This is true for the AHB //! clocks ([`AhbClk`]s), APB clocks ([`ApbClk`]s), GCLK outputs ([`GclkOut`]s), -//! peripheral channel clocks ([`Pclk`]s), and RTC oscillator ([`RtcOsc`]). +//! peripheral channel clocks ([`Pclk`]s), and RTC oscillator (`RtcOsc`). //! Other clocks form one-to-many (1:N) relationships, like the external crystal //! oscillator ([`Xosc`]), the 48 MHz DFLL ([`Dfll`]) or the two DPLLs //! ([`Dpll`]). @@ -115,9 +115,9 @@ //! on the movement of `Producer` objects. //! //! Instead, the `clock` module takes a different approach. It uses type-level -//! programming to track, at compile-time, the number of consumer clocks, N, -//! fed by a particular producer clock. With this approach, we can move -//! `Producer` objects while still making them impossible to modify if N > 0. +//! programming to track, at compile-time, the number of consumer clocks, N, fed +//! by a particular producer clock. With this approach, we can move `Producer` +//! objects while still making them impossible to modify if N > 0. //! //! The following sections will describe the implementation of this strategy. //! @@ -175,9 +175,9 @@ //! can only `Decrement` the same producer it `Increment`ed. Stated differently, //! we need a way to track the identity of each consumer's clock source. //! -//! The [`Source`] trait is designed for this purpose. It marks -//! [`Enabled`] producer clocks, and it's associated type, [`Id`], is the -//! identity type that should be stored by consumers. +//! The [`Source`] trait is designed for this purpose. It marks [`Enabled`] producer clocks, and it's associated type, [`Id`], is the identity type +//! that should be stored by consumers. //! //! Given that all implementers of `Source` are instances of `Enabled`, //! the naïve choice for [`Source::Id`] would be `T`. However, in a moment, we @@ -194,8 +194,8 @@ //! //! While these type parameters are important and necessary for configuration of //! a given producer clock, they are not relevant to consumer clocks. A consumer -//! clock does not need to know or care which `Mode` the XOSC is using, but -//! it *does* need to track that its clock [`Source`] is XOSC0. +//! clock does not need to know or care which `Mode` the XOSC is using, but it +//! *does* need to track that its clock [`Source`] is XOSC0. //! //! From this, we can see that `Enabled, N>` should not implement //! `Source` with `Source::Id = Xosc0`, because that would require consumers @@ -219,13 +219,13 @@ //! corresponding clock. Moreover, they also fundamentally restructure the way //! registers are accessed relative to the [PAC]. //! -//! Each of the four PAC clocking structs ([`OSCCTRL`], [`OSC32KCTRL`], [`GCLK`] -//! and [`MCLK`]) is a singleton object that controls a set of MMIO registers. -//! It is impossible to create two instances of any PAC object without `unsafe`. -//! However, each object controls a large set of registers that can be further -//! sub-divided into smaller sets for individual clocks. For example, the -//! [`GCLK`] object controls registers for 12 different clock generators and 48 -//! peripheral channel clocks. +//! Each of the PAC clocking structs (which vary between targets, including +//! `OSCCTRL`, `SYSCTRL`, `OSC32KCTRL`, [`GCLK`] and `MCLK`) is a singleton object +//! that controls a set of MMIO registers. It is impossible to create two +//! instances of any PAC object without `unsafe`. However, each object controls +//! a large set of registers that can be further sub-divided into smaller sets +//! for individual clocks. For example, the [`GCLK`] object controls registers +//! for 12 different clock generators and 48 peripheral channel clocks. //! //! `Token` types serve to break up the large PAC objects into smaller, //! more-targetted pieces. And in the process, they also remove the PAC objects' @@ -238,8 +238,8 @@ //! Bus clocks are fundamentally different from the other clock types in this //! module, because they do not use mutually exclusive registers for //! configuration. For instance, the registers that control [`Dpll0`] are -//! mutually exclusive to those that control [`Dpll1`], but `ApbClk` -//! and `ApbClk` share a single register. +//! mutually exclusive to those that control `Dpll1`, but `ApbClk` and +//! `ApbClk` share a single register. //! //! This presents a challenge for memory safety, because we need some way to //! guarantee that there are no data races. For example, if both @@ -403,24 +403,24 @@ //! //! Next, we want to use a DPLL to multiply the 8 MHz crystal clock up to 100 //! MHz. Once again, we need to decide between two instances of a clock, because -//! each chip has two [`Dpll`]s. This time, however, our decision between -//! [`Dpll0`] and [`Dpll1`] is arbitrary. +//! this chip has two [`Dpll`]s. This time, however, our decision between +//! [`Dpll0`] and `Dpll1` is arbitrary. //! //! Also note that, like before, `Dpll0` and `Dpll1` are aliases for -//! `Dpll` and `Dpll`. [`Dpll0Id`] and [`Dpll1Id`] +//! `Dpll` and `Dpll`. [`Dpll0Id`] and `Dpll1Id` //! represent the *identity* of the respective DPLL, while `I` represents the //! [`Id` type](self#id-types) for the [`Source`] driving the DPLL. In this //! particular case, we aim to create an instance of `Dpll0`. //! //! Only certain clocks can drive the DPLL, so `I` is constrained by the -//! [`DpllSourceId`] trait. Specifically, only the [`Xosc0Id`], [`Xosc1Id`], -//! [`Xosc32kId`] and [`GclkId`] types implement this trait. +//! [`DpllSourceId`] trait. Specifically, only the [`Xosc0Id`], `Xosc1Id` (only +//! some targets), [`Xosc32kId`] and [`GclkId`] types implement this trait. //! //! As before, we access the [`Tokens`] struct and use the corresponding //! [`DpllToken`] when creating an instance of `Dpll`. However, unlike before, //! we are creating a new clock-tree relationship that must be tracked by the -//! type system. Because DPLL0 will now consume XOSC0, we must [`Increment`] -//! the [`Enabled`] counter for [`EnabledXosc0`]. +//! type system. Because DPLL0 will now consume XOSC0, we must [`Increment`] the +//! [`Enabled`] counter for [`EnabledXosc0`]. //! //! Thus, to create an instance of `Dpll0`, we must provide the //! `EnabledXosc0`, so that its `U0` type parameter can be incremented to `U1`. @@ -461,11 +461,11 @@ //! # ).enable(); //! let (dpll0, xosc0) = Dpll::from_xosc(tokens.dpll0, xosc0); //! ``` -//! Next, we set the DPLL pre-divider and loop divider. We must pre-divide -//! the XOSC clock down from 8 MHz to 2 MHz, so that it is within the valid -//! input frequency range for the DPLL. Then, we set the DPLL loop divider, so -//! that it will multiply the 2 MHz clock by 50 for a 100 MHz output. We do not -//! need fractional mutiplication here, so the fractional loop divider is zero. +//! Next, we set the DPLL pre-divider and loop divider. We must pre-divide the +//! XOSC clock down from 8 MHz to 2 MHz, so that it is within the valid input +//! frequency range for the DPLL. Then, we set the DPLL loop divider, so that it +//! will multiply the 2 MHz clock by 50 for a 100 MHz output. We do not need +//! fractional mutiplication here, so the fractional loop divider is zero. //! Finally, we can enable the `Dpll`, yielding an instance of //! `EnabledDpll0`. //! @@ -515,11 +515,11 @@ //! [`EnabledGclk0`] to change the base clock without disabling GCLK0 or the //! main clock. //! -//! This time we will be modifying two [`Enabled`] counters simultaneously. -//! We will [`Decrement`] the [`EnabledDfll`] count from `U1` to `U0`, and -//! we will [`Increment`] the [`EnabledDpll0`] count from `U0` to `U1`. -//! Again, we need to provide both the DFLL and DPLL clocks, so that their -//! type parameters can be changed. +//! This time we will be modifying two [`Enabled`] counters simultaneously. We +//! will [`Decrement`] the [`EnabledDfll`] count from `U1` to `U0`, and we will +//! [`Increment`] the [`EnabledDpll0`] count from `U0` to `U1`. Again, we need +//! to provide both the DFLL and DPLL clocks, so that their type parameters can +//! be changed. //! //! ```no_run //! # use atsamd_hal::{ @@ -597,8 +597,8 @@ //! ``` //! //! We have the clocks set up, but we're not using them for anything other than -//! the main clock. Our final steps will create SERCOM APB and peripheral -//! clocks and will output the raw GCLK0 to a GPIO pin. +//! the main clock. Our final steps will create SERCOM APB and peripheral clocks +//! and will output the raw GCLK0 to a GPIO pin. //! //! To enable the APB clock for SERCOM0, we must access the [`Apb`] bus struct. //! We provide an [`ApbToken`] to the [`Apb::enable`] method and receive an @@ -768,10 +768,7 @@ //! ``` //! //! [PAC]: crate::pac -//! [`OSCCTRL`]: crate::pac::Oscctrl -//! [`OSC32KCTRL`]: crate::pac::Osc32kctrl //! [`GCLK`]: crate::pac::Gclk -//! [`MCLK`]: crate::pac::Mclk //! [`Peripherals::steal`]: crate::pac::Peripherals::steal //! //! [`Ahb`]: ahb::Ahb @@ -795,9 +792,7 @@ //! [`Dpll`]: dpll::Dpll //! [`Dpll`]: dpll::Dpll //! [`Dpll0`]: dpll::Dpll0 -//! [`Dpll1`]: dpll::Dpll1 //! [`Dpll0Id`]: dpll::Dpll0Id -//! [`Dpll1Id`]: dpll::Dpll1Id //! [`DpllSourceId`]: dpll::DpllSourceId //! [`DpllToken`]: dpll::DpllToken //! [`EnabledDpll0`]: dpll::EnabledDpll0 @@ -819,15 +814,12 @@ //! [`PclkSourceId`]: pclk::PclkSourceId //! [`PclkToken`]: pclk::PclkToken //! -//! [`RtcOsc`]: rtcosc::RtcOsc -//! //! [`Xosc`]: xosc::Xosc //! [`Xosc::from_crystal`]: xosc::Xosc::from_crystal //! [`Xosc::enable`]: xosc::Xosc::enable //! [`Xosc0`]: xosc::Xosc0 //! [`Xosc0`]: xosc::Xosc0 //! [`Xosc0Id`]: xosc::Xosc0Id -//! [`Xosc1Id`]: xosc::Xosc1Id //! [`XoscToken`]: xosc::XoscToken //! [`EnabledXosc0`]: xosc::EnabledXosc0 //! [`EnabledXosc0`]: xosc::EnabledXosc0 @@ -850,7 +842,8 @@ //! [`Sub1`]: typenum::Sub1 //! [`Unsigned`]: typenum::Unsigned //! -//! [interior mutability]: https://doc.rust-lang.org/reference/interior-mutability.html +//! [interior mutability]: +//! https://doc.rust-lang.org/reference/interior-mutability.html #![allow(clippy::manual_range_contains)] diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index b67f3484a981..f1c35227aeb3 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -464,15 +464,14 @@ pub enum DynDpllId { // DpllId //============================================================================== -/// Type-level enum identifying one of two possible [`Dpll`]s +/// Type-level enum identifying a [`Dpll`] /// -/// The types implementing this trait, i.e. [`Dpll0Id`] and [`Dpll1Id`], are -/// type-level variants of `DpllId`, and they identify one of the two possible -/// digital phase-locked loops. +/// The types implementing this trait, i.e. [`Dpll0Id`] (and `Dpll1Id`, on +/// targets with two DPLLs), identify a specific digital phase-locked loop. /// /// `DpllId` is the type-level equivalent of [`DynDpllId`]. See the -/// documentation on [type-level programming] and specifically -/// [type-level enums] for more details. +/// documentation on [type-level programming] and specifically [type-level +/// enums] for more details. /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums @@ -778,12 +777,12 @@ mod settings { /// A DPLL is used to multiply clock frequencies, taking a lower-frequency input /// clock and producing a higher-frequency output clock. /// -/// The type parameter `D` is a [`DpllId`] that determines which of the two -/// instances this `Dpll` represents ([`Dpll0`] or [`Dpll1`]). The type -/// parameter `I` represents the `Id` type for the clock [`Source`] driving this -/// `Dpll`. It must be one of the valid [`DpllSourceId`]s. See the -/// [`clock` module documentation](super) for more detail on -/// [`Id` types](super#id-types). +/// The type parameter `D` is a [`DpllId`] that determines which of the one or +/// two (depending on the target) instances this `Dpll` represents ([`Dpll0`] or +/// `Dpll1`). The type parameter `I` represents the `Id` type for the clock +/// [`Source`] driving this `Dpll`. It must be one of the valid +/// [`DpllSourceId`]s. See the [`clock` module documentation](super) for more +/// detail on [`Id` types](super#id-types). /// /// On its own, an instance of `Dpll` does not represent an enabled DPLL. /// Instead, it must first be wrapped with [`Enabled`], which implements diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 7b6b119b700a..09037dd0f24e 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -83,10 +83,10 @@ //! //! At this point, notice that [`Gclk`] takes two type parameters. `G` is //! a [`GclkId`] identifying which of the 12 generators this `Gclk` represents. -//! [`Gclk1`] is simply an alias for `Gclk`. `I` is an -//! [`Id` type](super#id-types) identifying the input clock, which must be a -//! valid [`GclkSourceId`]. In this case, `I` is [`PB14`](gpio::PB14), which is -//! a `GclkSourceId` for `Gclk1`, because it implements [`GclkIo`] with +//! [`Gclk1`] is simply an alias for `Gclk`. `I` is an [`Id` +//! type](super#id-types) identifying the input clock, which must be a valid +//! [`GclkSourceId`]. In this case, `I` is `PB14`, which is a `GclkSourceId` for +//! `Gclk1` on this target, because it implements [`GclkIo`] with //! [`GclkIo::GclkId`]` = Gclk1Id`. //! //! ```no_run @@ -488,15 +488,15 @@ pub enum DynGclkId { // GclkId //============================================================================== -/// Type-level enum identifying one of 12 possible [`Gclk`]s +/// Type-level enum identifying one of possible [`Gclk`]s /// -/// The types implementing this trait, i.e. [`Gclk0Id`] - [`Gclk11Id`], are -/// type-level variants of `GclkId`, and they identify one of the 12 possible +/// The types implementing this trait, i.e. [`Gclk0Id`] - `Gclk11Id`, are +/// type-level variants of `GclkId`, and they identify one of the possible /// generic clock generators. /// /// `GclkId` is the type-level equivalent of [`DynGclkId`]. See the -/// documentation on [type-level programming] and specifically -/// [type-level enums] for more details. +/// documentation on [type-level programming] and specifically [type-level +/// enums] for more details. /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums @@ -1072,13 +1072,13 @@ impl Default for Settings { /// a root or branch clock to other branch or leaf clocks. In particular, all /// peripheral [`Pclk`]s must be derived from a `Gclk`. /// -/// The type parameter `G` is a [`GclkId`] that determines which of the 12 -/// generators this [`Gclk`] represents ([`Gclk0`] - [`Gclk11`]). The type -/// parameter `I` represents the `Id` type for the clock [`Source`] driving this -/// `Gclk`. It must be one of the valid [`GclkSourceId`]s. Alternatively, if the -/// `Gclk` is driven by a [GPIO](gpio) [`Pin`], then `I` is a [`PinId`] -/// implementing [`GclkIo`]. See the [`clock` module documentation](super) for -/// more detail on `Id` types. +/// The type parameter `G` is a [`GclkId`] that determines which of the +/// generators this [`Gclk`] represents ([`Gclk0`] - `Gclk11` on the largest +/// targets). The type parameter `I` represents the `Id` type for the clock +/// [`Source`] driving this `Gclk`. It must be one of the valid +/// [`GclkSourceId`]s. Alternatively, if the `Gclk` is driven by a [GPIO](gpio) +/// [`Pin`], then `I` is a [`PinId`] implementing [`GclkIo`]. See the [`clock` +/// module documentation](super) for more detail on `Id` types. /// /// On its own, an instance of `Gclk` does not represent an enabled clock /// generator. Instead, it must first be wrapped with [`Enabled`], which diff --git a/hal/src/clock/v2/osc32k.rs b/hal/src/clock/v2/osc32k.rs index 3288210c1c73..96f3bcfe4fa2 100644 --- a/hal/src/clock/v2/osc32k.rs +++ b/hal/src/clock/v2/osc32k.rs @@ -2,35 +2,27 @@ //! //! ## Overview //! -//! TODO this documentation is for the SAMD51 version, not the SYSCTRL sub-peripheral +//! The `osc32k` module provides access to the 32 kHz oscillator (OSC32K), +//! provided by the `SYSCTRL` peripheral. Depending on the target, it has one +//! or two outputs: one at 32 kHz and another divided down to 1 kHz. These +//! outputs can be disabled or enabled independently at any given time. //! -//! The `osc32k` module provides access to the 32 kHz ultra low power -//! internal oscillator (OSC32K) within the `OSC32KCTRL` peripheral. -//! -//! The `OSC32K` clock is unlike most other clocks. First, it is an internal -//! clock that is always enabled and can't be disabled. And second, it has two -//! separate outputs, one at 32 kHz and another divided down to 1 kHz. Moreover, -//! none, either or both of these outputs can be enabled at any given time. -//! -//! We can see, then, that the `OSC32K` peripheral forms its own, miniature -//! clock tree. There is a 1:N producer clock that is always enabled; and there -//! are two possible consumer clocks that can be independently and optionally -//! enabled. In fact, this structure is illustrated by the `OSC32K` -//! register, which has no regular `ENABLE` bit and two different enable bits -//! for clock output, `EN32K` and `EN1K`. +//! We can see, that the `OSC32K` peripheral forms its own, miniature clock +//! tree. There is a 1:N producer clock; and there are one or two possible +//! consumer clocks that can be independently and optionally enabled. //! //! To represent this structure in the type system, we divide the `OSC32K` //! peripheral into these three clocks. Users get access to the 1:N -//! [`EnabledOsc32kBase`] clock [`Source`] at power-on reset, which can be -//! consumed by both the [`Osc32k`] and [`Osc1k`] clocks. Note that -//! `Osc32k` and `Osc1k` are themselves 1:N clocks as well. +//! [`EnabledOsc32kBase`] clock [`Source`], which can be consumed by both the +//! [`Osc32k`] and [`Osc1k`] clocks. Note that `Osc32k` and `Osc1k` are +//! themselves 1:N clocks as well. //! //! ## Write lock //! -//! Rhe `OSC32K` register has a dedicated write lock bit that will freeze its +//! The `OSC32K` register has a dedicated write lock bit that will freeze its //! configuration until the next power-on reset. We implement this by simply -//! dropping the [`Osc32kBase`] clock, which prevents any further access to -//! the `OSC32K` register. +//! dropping the [`Osc32kBase`] clock, which prevents any further access to the +//! `OSC32K` register. //! //! ## Example //! @@ -108,8 +100,7 @@ //! ``` //! //! And finally, we can set the write lock bit to freeze the configuation until -//! the next power-on reset. Doing so also drops the `EnabledOsc32kBase` -//! clock. +//! the next power-on reset. Doing so also drops the `EnabledOsc32kBase` clock. //! //! ```no_run //! # use atsamd_hal::{ @@ -474,6 +465,11 @@ pub struct Osc1k { token: Osc1kToken, } +/// OSC1K is not available on the currently-documented target +#[cfg(doc)] +#[hal_cfg(not("sysctrl-d11"))] +pub struct Osc1k {} + /// The [`Enabled`] [`Osc1k`] clock /// /// As described in the [`clock` module documentation](super), the [`Enabled`] diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index df5b98136ac1..57b7f4d584ed 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -205,8 +205,9 @@ struct OscUlp32kBaseToken(()); /// various `Token` types can be exchanged for actual clock types. They /// typically represent clocks that are disabled at power-on reset. /// -/// The [`OscUlp1k`] clock is disabled at power-on reset. To use it, you must -/// first exchange the token for an actual clock with [`OscUlp1k::enable`]. +/// On some targets, the [`OscUlp1k`] clock is disabled at power-on reset, and +/// to use it the token must first be exchanged for an actual clock with +/// [`OscUlp1k::enable`]. pub struct OscUlp1kToken(()); /// Singleton token that can be exchanged for [`OscUlp32k`] @@ -215,8 +216,9 @@ pub struct OscUlp1kToken(()); /// various `Token` types can be exchanged for actual clock types. They /// typically represent clocks that are disabled at power-on reset. /// -/// The [`OscUlp32k`] clock is disabled at power-on reset. To use it, you must -/// first exchange the token for an actual clock with [`OscUlp32k::enable`]. +/// On some targets, the [`OscUlp32k`] clock is disabled at power-on reset, and +/// to use it the token must first be exchanged for an actual clock with +/// [`OscUlp32k::enable`]. pub struct OscUlp32kToken(()); impl OscUlp32kBaseToken { @@ -402,6 +404,11 @@ impl OscUlp1k { base.0.token.enable_1k(); (Enabled::new(Self { token }), base.inc()) } + + /// The OSCULP32K 1.024kHz output is always enabled on the documented target + #[cfg(doc)] + #[hal_cfg(not("clock-d5x"))] + pub fn enable(_token: OscUlp1kToken) {} } impl EnabledOscUlp1k { @@ -482,6 +489,11 @@ impl OscUlp32k { base.0.token.enable_32k(); (Enabled::new(Self { token }), base.inc()) } + + /// The OSCULP32K 32.768kHz output is always enabled on the documented target + #[cfg(doc)] + #[hal_cfg(not("clock-d5x"))] + pub fn enable(_token: OscUlp32kToken) {} } impl EnabledOscUlp32k { diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index 2f9728911de6..1c44f83f3268 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -30,8 +30,7 @@ impl Pac { /// /// Consume the [`Pac`] and return the low-level PAC structs. This is /// useful when the `clock::v2` API does not provide a necessary feature, or - /// when dealing with the legacy `clock::v1` API. For example, many of the - /// `clock::v1` functions require access to the [`MCLK`] peripheral. + /// when dealing with the legacy `clock::v1` API. /// /// # Safety /// @@ -122,21 +121,20 @@ pub struct Tokens { pub gclks: gclk::GclkTokens, /// Tokens to create [`pclk::Pclk`]s pub pclks: pclk::PclkTokens, - /// Tokens to create the [`osc32k::Osc1k`] and [`osc32k::Osc32k`] clocks + /// Tokens to create the [`osc32k`] clocks pub osc32k: osc32k::Osc32kTokens, /// Tokens [`xosc::Xosc0`] pub xosc: xosc::XoscToken, - /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and - /// [`xosc32k::Xosc32k`] + /// Tokens to create [`xosc32k`] clocks #[hal_cfg("xosc32k")] pub xosc32k: xosc32k::Xosc32kTokens, } -/// Consume the PAC clocking structs and return a HAL-level -/// representation of the clocks at power-on reset +/// Consume the PAC clocking structs and return a HAL-level representation of +/// the clocks at power-on reset /// -/// This function consumes the [`OSCCTRL`], [`OSC32KCTRL`], [`Gclk`] and -/// [`MCLK`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`]. +/// This function consumes the [`Gclk`], [`Pm`], and [`Sysctrl``] PAC structs +/// and returns the [`Buses`], [`Clocks`] and [`Tokens`]. /// /// See the [module-level documentation](super) for more details. #[inline] diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 4c1e5b2ef420..5bc7a41424bb 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -11,8 +11,8 @@ //! //! When used with an external clock, only one GPIO [`Pin`] is required, but //! when used with a crystal oscillator, two GPIO `Pin`s are required. The -//! [`XIn`] `Pin` is used in both `Mode`s, while the [`XOut`] `Pin` is only -//! used in [`CrystalMode`]. +//! [`XIn`] `Pin` is used in both `Mode`s, while the [`XOut`] `Pin` is only used +//! in [`CrystalMode`]. //! //! When operating in [`CrystalMode`], the XOSC peripheral provides several //! configuration options to increase stability or reduce power consumption of @@ -86,14 +86,15 @@ //! //! We start by calling [`Xosc::from_crystal`], and we provide the corresponding //! [`XIn`] and [`XOut`] [`Pin`]s, as well as the nominal crystal frequency. We -//! then set the [`CrystalCurrent`] level to `Medium`. The default current level -//! for a 20 MHz signal is actually `High`, but we opt for a lower current under -//! the assumption that our crystal's capacitive load is small. Next, we turn on -//! automatic loop control, which should save power, but we also set -//! `LOWBUFGAIN` to `1`. Counterintuitively, this actually _increases_ the -//! crystal amplitude, which increases power consumption, but it also improves -//! stability. We then apply a 488 μs start up delay, to allow the clock to -//! stabilize before it is applied to any logic. Finally, we enable the `Xosc`. +//! then set the `CrystalCurrent` level to `Medium` (supported only on some +//! targets). The default current level for a 20 MHz signal is actually `High`, +//! but we opt for a lower current under the assumption that our crystal's +//! capacitive load is small. Next, we turn on automatic loop control, which +//! should save power, but we also set `LOWBUFGAIN` to `1`. Counterintuitively, +//! this actually _increases_ the crystal amplitude, which increases power +//! consumption, but it also improves stability. We then apply a 488 μs start up +//! delay, to allow the clock to stabilize before it is applied to any logic. +//! Finally, we enable the `Xosc`. //! //! Next, we wait until the `Xosc` is stable and ready to be used as a clock //! [`Source`]. @@ -126,11 +127,11 @@ //! while !xosc.is_ready() {} //! ``` //! -//! Once the clock is stable, we can also enable failure detection. To do so, we -//! must provide the [`EnabledDfll`] to act as the backup safe clock. We can -//! also select a divider for the safe clock, so that it loosely matches the -//! `Xosc` frequency. In thise case, we divide the 48 MHz [`Dfll`] down to -//! 24 MHz, which is the closest option to 20 MHz. +//! Once the clock is stable, we can also enable failure detection on targets +//! that support it. To do so, we must provide the [`EnabledDfll`] to act as the +//! backup safe clock. We can also select a divider for the safe clock, so that +//! it loosely matches the `Xosc` frequency. In thise case, we divide the 48 MHz +//! [`Dfll`] down to 24 MHz, which is the closest option to 20 MHz. //! //! ```no_run //! # use atsamd_hal::{ @@ -454,11 +455,11 @@ impl Default for Settings { // XoscId //============================================================================== -/// Type-level enum identifying one of two possible [`Xosc`]s +/// Type-level enum identifying [`Xosc`]s /// -/// The types implementing this trait, i.e. [`Xosc0Id`] and [`Xosc1Id`], are -/// type-level variants of `XoscId`, and they identify one of two possible -/// external crystal oscillators. +/// The types implementing this trait, i.e. [`Xosc0Id`] and `Xosc1Id` on +/// supporting targets, are type-level variants of `XoscId`, and they identify +/// one of two possible external crystal oscillators. /// /// See the documentation on [type-level programming] and specifically /// [type-level enums] for more details. @@ -770,8 +771,8 @@ impl Mode for CrystalMode { /// oscillator and delivers the resulting clock to the rest of the clock system. /// /// The type parameter `X` is a [`XoscId`] that determines which of the two -/// instances this `Xosc` represents ([`Xosc0`] or [`Xosc1`]). The type -/// parameter `M` represents the operating [`Mode`], either [`ClockMode`] or +/// instances this `Xosc` represents ([`Xosc0`] or `Xosc1`). The type parameter +/// `M` represents the operating [`Mode`], either [`ClockMode`] or /// [`CrystalMode`]. /// /// On its own, an instance of `Xosc` does not represent an enabled XOSC. @@ -1037,6 +1038,7 @@ where } } +#[hal_macro_helper] impl EnabledXosc where X: XoscId, @@ -1048,6 +1050,16 @@ where pub fn is_ready(&self) -> bool { self.0.token.is_ready() } + + /// XOSC failure detection is not supported by the currently-documented target + #[cfg(doc)] + #[hal_cfg(not("clock-d5x"))] + pub fn has_failed(&self) {} + + /// XOSC failure detection is not supported by the currently-documented target + #[cfg(doc)] + #[hal_cfg(not("clock-d5x"))] + pub fn switch_back(&self) {} } #[hal_cfg("clock-d5x")] diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index dbb8de87e9b9..4b574121cd7a 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -33,20 +33,20 @@ //! `ENABLE` bit. The call to [`Xosc32kBase::enable`] returns a 1:N [`Enabled`] //! clock [`Source`], which can be consumed by both the [`Xosc32k`] and //! [`Xosc1k`] clocks. Enabling either of these two clocks will [`Increment`] -//! the [`EnabledXosc32kBase`] counter, preventing it from being disabled. -//! Note that `Xosc32k` and `Xosc1k` are themselves 1:N clocks as well. +//! the [`EnabledXosc32kBase`] counter, preventing it from being disabled. Note +//! that `Xosc32k` and `Xosc1k` are themselves 1:N clocks as well. //! //! ## Clock failure detection and write lock //! -//! Like the [`Xosc`] clocks, the XOSC32K peripheral also has clock failure -//! detection. However, unlike the `XOSCCTRL` registers, the `XOSC32K` register -//! has a dedicated write lock bit that will freeze its configuration until the -//! next power-on reset. +//! The XOSC32K peripheral on some microcontrollers supports Clock Failure +//! Detection (CFD), like the [`Xosc`] clocks. However, unlike the `XOSCCTRL` +//! registers, the `XOSC32K` register has a dedicated write lock bit that will +//! freeze its configuration until the next power-on reset. //! //! While `Xosc` clock failure detection is configured directly in the -//! `XOSCCTRL` register, the XOSC32K peripheral has a separate, dedicated -//! clock failure detection register (`Cfdctrl`). This difference likely exists -//! to provide control of clock failure detection *after* write lock has been +//! `XOSCCTRL` register, the XOSC32K peripheral has a separate, dedicated clock +//! failure detection register (`Cfdctrl`). This difference likely exists to +//! provide control of clock failure detection *after* write lock has been //! enabled. //! //! In this module, write lock is implemented by simply dropping the @@ -71,7 +71,6 @@ //! osculp32k::OscUlp32k, //! xosc32k::{ //! ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase, -//! Xosc32kCfd, //! }, //! }, //! gpio::Pins, @@ -91,8 +90,8 @@ //! Next, we create the [`Xosc32kBase`] clock from a 32 kHz oscillator using its //! corresponding [`Xosc32kBaseToken`] and the [`XIn32`] and [`XOut32`] `Pin`s. //! We then set the delay before the clock is unmasked by providing a desired -//! [`StartUpDelay`]. Finally, we select a [`ControlGainMode`] for the crystal -//! before enabling it. +//! [`StartUpDelay`]. Finally, on supported targets, we select a +//! `ControlGainMode` for the crystal before enabling it. //! //! ```no_run //! # use atsamd_hal::{ @@ -101,7 +100,6 @@ //! # osculp32k::OscUlp32k, //! # xosc32k::{ //! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase, -//! # Xosc32kCfd, //! # }, //! # }, //! # gpio::Pins, @@ -118,6 +116,7 @@ //! # ); //! let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01) //! .start_up_delay(StartUpDelay::Delay1s) +//! // n.b. only some targets support this setting //! .control_gain_mode(ControlGainMode::HighSpeed) //! .enable(); //! ``` @@ -132,7 +131,6 @@ //! # osculp32k::OscUlp32k, //! # xosc32k::{ //! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase, -//! # Xosc32kCfd, //! # }, //! # }, //! # gpio::Pins, @@ -155,10 +153,10 @@ //! ``` //! //! With the [`EnabledXosc32kBase`] clock in hand, we can enable the [`Xosc1k`] -//! and [`Xosc32k`], each of which [`Increment`]s the [`Enabled`] counter. -//! Once we are satisfied with the configuration, we can call `write_lock` to -//! lock the XOSC32K configuration at the hardware level. Doing so also consumes -//! the `EnabledXosc32kBase` clock, which eliminates any ability to change the +//! and [`Xosc32k`], each of which [`Increment`]s the [`Enabled`] counter. Once +//! we are satisfied with the configuration, we can call `write_lock` to lock +//! the XOSC32K configuration at the hardware level. Doing so also consumes the +//! `EnabledXosc32kBase` clock, which eliminates any ability to change the //! configuration at the API level. //! //! ```no_run @@ -168,7 +166,6 @@ //! # osculp32k::OscUlp32k, //! # xosc32k::{ //! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase, -//! # Xosc32kCfd, //! # }, //! # }, //! # gpio::Pins, @@ -1139,6 +1136,22 @@ impl Xosc32kCfd { } } +/// Clock failure detection is not supported by the currently-documented target +#[cfg(doc)] +#[hal_cfg(not("osc32kctrl"))] +pub struct Xosc32kCfd; + +#[cfg(doc)] +#[hal_cfg(not("osc32kctrl"))] +impl Xosc32kCfd { + /// Clock failure detection is not supported by the currently-documented target + pub fn has_failed() {} + /// Clock failure detection is not supported by the currently-documented target + pub fn is_switched() {} + /// Clock failure detection is not supported by the currently-documented target + pub fn switch_back() {} +} + //============================================================================== // Ids //============================================================================== @@ -1173,6 +1186,13 @@ pub struct Xosc1k { token: Xosc1kToken, } + +/// XOSC1K is not available on the currently-documented target +#[cfg(doc)] +#[hal_cfg(not(any("sysctrl-d11", "osc32kctrl")))] +pub struct Xosc1k; + + /// The [`Enabled`] [`Xosc1k`] clock /// /// As described in the [`clock` module documentation](super), the [`Enabled`] diff --git a/hal/src/sercom/dma.rs b/hal/src/sercom/dma.rs index 02e1c0a337d1..703b8f0b0d10 100644 --- a/hal/src/sercom/dma.rs +++ b/hal/src/sercom/dma.rs @@ -176,10 +176,9 @@ where /// the provided buffer. /// /// In order to be (safely) non-blocking, his method has to take a `'static` - /// buffer. If you'd rather use DMA with the blocking - /// [`embedded_io::Read`] trait, and avoid having - /// to use static buffers, - /// use [`Uart::with_rx_channel`](Self::with_tx_channel) instead. + /// buffer. If you'd rather use DMA with the blocking [`embedded_io::Read`] + /// trait, and avoid having to use static buffers, use + /// [`Uart::with_rx_channel`](Self::with_tx_channel) instead. #[inline] #[hal_macro_helper] pub fn receive_with_dma( @@ -218,10 +217,9 @@ where /// provided buffer. /// /// In order to be (safely) non-blocking, his method takes a `'static` - /// buffer. If you'd rather use DMA with the blocking - /// [`embedded_io::Write`] trait, and avoid - /// having to use static buffers, - /// use[`Uart::with_tx_channel`](Self::with_tx_channel) instead. + /// buffer. If you'd rather use DMA with the blocking [`embedded_io::Write`] + /// trait, and avoid having to use static buffers, use + /// [`Uart::with_tx_channel`](Self::with_tx_channel) instead. #[inline] #[hal_macro_helper] pub fn send_with_dma( From 80c8d4da16beef74964921222e97a100712adfe3 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 17 Aug 2025 09:30:00 +1200 Subject: [PATCH 109/114] More doc fixes --- hal/src/gpio/pin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hal/src/gpio/pin.rs b/hal/src/gpio/pin.rs index 62129af8fca0..8979f0b63d4c 100644 --- a/hal/src/gpio/pin.rs +++ b/hal/src/gpio/pin.rs @@ -1084,8 +1084,7 @@ macro_rules! pins{ )+ } impl Pins { - /// Take ownership of the PAC - /// [`Port`] and split it into + /// Take ownership of the PAC [`Port`] and split it into /// discrete [`Pin`]s #[inline] pub fn new(port: Port) -> Pins { From 1ff22a953ab27f70c761bca11258ca3b8eb7966e Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 17 Aug 2025 09:51:23 +1200 Subject: [PATCH 110/114] Formatting, minor fix in /rustfmt.sh --- boards/atsame54_xpro/examples/blinky_rtic.rs | 8 ++------ boards/feather_m4/examples/adc.rs | 2 +- boards/metro_m4/examples/adc.rs | 2 +- hal/src/clock/v2.rs | 4 ++-- hal/src/clock/v2/osculp32k.rs | 3 ++- hal/src/clock/v2/xosc.rs | 6 ++++-- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/boards/atsame54_xpro/examples/blinky_rtic.rs b/boards/atsame54_xpro/examples/blinky_rtic.rs index 4289dfd56ee1..32b42710b483 100644 --- a/boards/atsame54_xpro/examples/blinky_rtic.rs +++ b/boards/atsame54_xpro/examples/blinky_rtic.rs @@ -32,12 +32,8 @@ mod app { rtt_init_print!(); - let (_buses, clocks, tokens) = clock_system_at_reset( - device.oscctrl, - device.osc32kctrl, - device.gclk, - device.mclk, - ); + let (_buses, clocks, tokens) = + clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); // Enable the RTC clock with the 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not diff --git a/boards/feather_m4/examples/adc.rs b/boards/feather_m4/examples/adc.rs index 98d4a974135a..9f90fe3682a3 100644 --- a/boards/feather_m4/examples/adc.rs +++ b/boards/feather_m4/examples/adc.rs @@ -2,4 +2,4 @@ #![no_main] use feather_m4 as bsp; -include!("../../examples/m4-adc.rs"); \ No newline at end of file +include!("../../examples/m4-adc.rs"); diff --git a/boards/metro_m4/examples/adc.rs b/boards/metro_m4/examples/adc.rs index 8af58dc94ef4..79f1675e1d1b 100644 --- a/boards/metro_m4/examples/adc.rs +++ b/boards/metro_m4/examples/adc.rs @@ -2,4 +2,4 @@ #![no_main] use metro_m4 as bsp; -include!("../../examples/m4-adc.rs"); \ No newline at end of file +include!("../../examples/m4-adc.rs"); diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 3095055a5b80..cbd0a036a94c 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -220,8 +220,8 @@ //! registers are accessed relative to the [PAC]. //! //! Each of the PAC clocking structs (which vary between targets, including -//! `OSCCTRL`, `SYSCTRL`, `OSC32KCTRL`, [`GCLK`] and `MCLK`) is a singleton object -//! that controls a set of MMIO registers. It is impossible to create two +//! `OSCCTRL`, `SYSCTRL`, `OSC32KCTRL`, [`GCLK`] and `MCLK`) is a singleton +//! object that controls a set of MMIO registers. It is impossible to create two //! instances of any PAC object without `unsafe`. However, each object controls //! a large set of registers that can be further sub-divided into smaller sets //! for individual clocks. For example, the [`GCLK`] object controls registers diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index 57b7f4d584ed..e580bc18c561 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -490,7 +490,8 @@ impl OscUlp32k { (Enabled::new(Self { token }), base.inc()) } - /// The OSCULP32K 32.768kHz output is always enabled on the documented target + /// The OSCULP32K 32.768kHz output is always enabled on the documented + /// target #[cfg(doc)] #[hal_cfg(not("clock-d5x"))] pub fn enable(_token: OscUlp32kToken) {} diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 5bc7a41424bb..49af41688882 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -1051,12 +1051,14 @@ where self.0.token.is_ready() } - /// XOSC failure detection is not supported by the currently-documented target + /// XOSC failure detection is not supported by the currently-documented + /// target #[cfg(doc)] #[hal_cfg(not("clock-d5x"))] pub fn has_failed(&self) {} - /// XOSC failure detection is not supported by the currently-documented target + /// XOSC failure detection is not supported by the currently-documented + /// target #[cfg(doc)] #[hal_cfg(not("clock-d5x"))] pub fn switch_back(&self) {} From 22815d175f21fb07537400a5c0be66fe8c9a2906 Mon Sep 17 00:00:00 2001 From: Ashcon Mohseninia Date: Thu, 27 Nov 2025 14:42:02 +0100 Subject: [PATCH 111/114] Unify ADC setup (Remove V1 clock setup) --- hal/src/peripherals/adc/builder.rs | 13 ------- hal/src/peripherals/adc/d11/mod.rs | 7 ++-- hal/src/peripherals/adc/mod.rs | 54 ------------------------------ 3 files changed, 2 insertions(+), 72 deletions(-) diff --git a/hal/src/peripherals/adc/builder.rs b/hal/src/peripherals/adc/builder.rs index baaa62e74b83..cb81c09d3b7c 100644 --- a/hal/src/peripherals/adc/builder.rs +++ b/hal/src/peripherals/adc/builder.rs @@ -245,7 +245,6 @@ impl AdcBuilder { } /// Turn the builder into an ADC - #[hal_cfg("adc-d5x")] #[inline] pub fn enable( self, @@ -256,16 +255,4 @@ impl AdcBuilder { let settings = self.to_settings()?; Adc::new(adc, settings, clk, pclk).map_err(|e| e.into()) } - - #[hal_cfg(any("adc-d11", "adc-d21"))] - #[inline] - pub fn enable( - self, - adc: I::Instance, - pm: &mut crate::pac::Pm, - clock: &crate::clock::AdcClock, - ) -> Result, BuilderError> { - let settings = self.to_settings()?; - Adc::new(adc, settings, pm, clock).map_err(|e| e.into()) - } } diff --git a/hal/src/peripherals/adc/d11/mod.rs b/hal/src/peripherals/adc/d11/mod.rs index d43d76012144..be5753932679 100644 --- a/hal/src/peripherals/adc/d11/mod.rs +++ b/hal/src/peripherals/adc/d11/mod.rs @@ -22,6 +22,8 @@ impl PrimaryAdc for Adc0 {} impl AdcInstance for Adc0 { type Instance = pac::Adc; + type ClockId = crate::clock::v2::pclk::ids::Adc0; + #[cfg(feature = "async")] type Interrupt = crate::async_hal::interrupts::ADC; @@ -30,11 +32,6 @@ impl AdcInstance for Adc0 { &p.adc } - #[inline] - fn enable_pm(pm: &mut pac::Pm) { - pm.apbcmask().modify(|_, w| w.adc_().set_bit()); - } - #[inline] fn calibrate(instance: &Self::Instance) { instance.calib().write(|w| unsafe { diff --git a/hal/src/peripherals/adc/mod.rs b/hal/src/peripherals/adc/mod.rs index 1b22a158a9bb..50223e94572b 100644 --- a/hal/src/peripherals/adc/mod.rs +++ b/hal/src/peripherals/adc/mod.rs @@ -140,14 +140,10 @@ pub trait AdcInstance { // The Adc0 and Adc1 PAC types implement Deref type Instance: Deref; - #[hal_cfg("adc-d5x")] type ClockId: crate::clock::v2::apb::ApbId + crate::clock::v2::pclk::PclkId; fn peripheral_reg_block(p: &mut Peripherals) -> &adc0::RegisterBlock; - #[hal_cfg(any("adc-d11", "adc-d21"))] - fn enable_pm(pm: &mut pac::Pm); - fn calibrate(instance: &Self::Instance); #[cfg(feature = "async")] @@ -162,16 +158,6 @@ where const CHANNEL: u8; } -/// ADC Instance -#[hal_cfg(any("adc-d11", "adc-d21"))] -pub struct Adc { - adc: I::Instance, - cfg: AdcSettings, - discard: bool, -} - -/// ADC Instance -#[hal_cfg("adc-d5x")] pub struct Adc { adc: I::Instance, _apbclk: crate::clock::v2::apb::ApbClk, @@ -201,7 +187,6 @@ impl Adc { /// /// NOTE: If you plan to run the chip above 100°C, then the maximum GCLK /// frequency for the ADC is restricted to 90Mhz for stable performance. - #[hal_cfg("adc-d5x")] #[inline] pub(crate) fn new( adc: I::Instance, @@ -233,36 +218,6 @@ impl Adc { Ok(new_adc) } - /// Construct a new ADC instance - /// - /// ## Important - /// - /// This function will return [Error::ClockTooFast] if the clock source - /// provided is faster than 48 MHz, since this is the maximum frequency - /// for the ADC as per the datasheet. - #[hal_cfg(any("adc-d11", "adc-d21"))] - #[inline] - pub(crate) fn new( - adc: I::Instance, - settings: AdcSettings, - pm: &mut pac::Pm, - clock: &crate::clock::AdcClock, - ) -> Result { - if (clock.freq() as crate::time::Hertz).to_Hz() > 48_000_000 { - // Clock source is too fast - return Err(Error::ClockTooFast); - } - - I::enable_pm(pm); - let mut new_adc = Self { - adc, - cfg: settings, - discard: true, - }; - new_adc.configure(settings); - Ok(new_adc) - } - /// Switch the ['Adc'] to ['FutureAdc'], allowing for the use of async /// reading methods. You are required to provide the struct created by /// the [`bind_interrupts`](crate::bind_interrupts) macro to prove @@ -405,16 +360,7 @@ impl Adc { Ok(()) } - /// Return the underlying ADC PAC object. - #[hal_cfg(any("adc-d11", "adc-d21"))] - #[inline] - pub fn free(mut self) -> I::Instance { - self.software_reset(); - self.adc - } - /// Return the underlying ADC PAC object and the enabled APB ADC clock. - #[hal_cfg("adc-d5x")] #[inline] pub fn free(mut self) -> (I::Instance, crate::clock::v2::apb::ApbClk) { self.software_reset(); From e10df039c07959abe155cc1637c56132cda10056 Mon Sep 17 00:00:00 2001 From: Ashcon Mohseninia Date: Thu, 27 Nov 2025 14:47:19 +0100 Subject: [PATCH 112/114] PCLK Freq check D21 ADC --- hal/src/peripherals/adc/mod.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hal/src/peripherals/adc/mod.rs b/hal/src/peripherals/adc/mod.rs index 50223e94572b..eed8cdc28650 100644 --- a/hal/src/peripherals/adc/mod.rs +++ b/hal/src/peripherals/adc/mod.rs @@ -177,17 +177,18 @@ impl Adc { /// ## Important /// /// This function will return `Err` if the clock source provided - /// is faster than 100 MHz, since this is the maximum frequency for - /// GCLK_ADCx as per the datasheet. + /// is faster than 100 MHz (D5x) or 48Mhz (D21/D11), since this + /// is the maximum frequency for GCLK_ADCx as per the datasheet. /// /// The [`new`](Self::new) function currently takes an `&` reference to a /// [`Pclk`](crate::clock::v2::pclk::Pclk). In the future this will likely /// change to taking full ownership of it; in the meantime, you must ensure /// that the PCLK is enabled for the `Adc` struct's lifetime. /// - /// NOTE: If you plan to run the chip above 100°C, then the maximum GCLK + /// NOTE (D5x specific): If you plan to run the chip above 100°C, then the maximum GCLK /// frequency for the ADC is restricted to 90Mhz for stable performance. #[inline] + #[atsamd_hal_macros::hal_macro_helper] pub(crate) fn new( adc: I::Instance, settings: AdcSettings, @@ -203,10 +204,16 @@ impl Adc { // at the time of creation of the Adc struct; however we can't guarantee // that the clock will stay enabled for the duration of its lifetime. + #[hal_cfg("adc-d5x")] if pclk.freq() > fugit::HertzU32::from_raw(100_000_000) { // Clock source is too fast return Err(Error::ClockTooFast); } + #[hal_cfg(any("adc-d21", "adc-d11"))] + if pclk.freq() > fugit::HertzU32::from_raw(48_000_000) { + // Clock source is too fast + return Err(Error::ClockTooFast); + } let mut new_adc = Self { adc, From 3afdf163bd8a9fe177907de25c265f1a1ddd43a6 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Sat, 17 Jan 2026 18:02:33 -0500 Subject: [PATCH 113/114] feat(clock)!: Dynamic PCLK source ID. PCLK source ID can be either type-checked or runtime-checked. Also change ADC peripehral to use dynamic source IDs. Signed-off-by: Justin Beaurivage --- boards/atsame54_xpro/examples/mcan.rs | 2 +- boards/examples/m4-adc.rs | 6 +- boards/metro_m4/examples/async_adc.rs | 8 +- hal/src/clock/v2/gclk.rs | 27 +++++ hal/src/clock/v2/pclk.rs | 148 +++++++++++++++++++++++--- hal/src/clock/v2/reset_thumbv6m.rs | 9 +- hal/src/peripherals/adc/builder.rs | 12 ++- hal/src/peripherals/adc/mod.rs | 19 ++-- 8 files changed, 197 insertions(+), 34 deletions(-) diff --git a/boards/atsame54_xpro/examples/mcan.rs b/boards/atsame54_xpro/examples/mcan.rs index d79541b3561c..d2f9ad8fb671 100644 --- a/boards/atsame54_xpro/examples/mcan.rs +++ b/boards/atsame54_xpro/examples/mcan.rs @@ -83,7 +83,7 @@ type Aux = mcan::bus::Aux< clock::types::Can1, hal::can::Dependencies< clock::types::Can1, - clock::gclk::Gclk0Id, + clock::pclk::PclkSource, bsp::Ata6561Rx, bsp::Ata6561Tx, bsp::pac::Can1, diff --git a/boards/examples/m4-adc.rs b/boards/examples/m4-adc.rs index f6278c5fadf7..0afcc86f8238 100644 --- a/boards/examples/m4-adc.rs +++ b/boards/examples/m4-adc.rs @@ -51,13 +51,13 @@ fn main() -> ! { // Overruns if clock divider < 32 in debug mode .with_clock_divider(Prescaler::Div32) .with_vref(atsamd_hal::adc::Reference::Arefa) - .enable(peripherals.adc0, apb_adc0, &pclk_adc0) + .enable(peripherals.adc0, apb_adc0, pclk_adc0) .unwrap(); let mut adc_pin = pins.a0.into_alternate(); loop { - let res = adc.read(&mut adc_pin); + let _res = adc.read(&mut adc_pin); #[cfg(feature = "use_semihosting")] - let _ = cortex_m_semihosting::hprintln!("ADC value: {}", res); + let _ = cortex_m_semihosting::hprintln!("ADC value: {}", _res); } } diff --git a/boards/metro_m4/examples/async_adc.rs b/boards/metro_m4/examples/async_adc.rs index a9fe0763369f..a4121ba277bf 100644 --- a/boards/metro_m4/examples/async_adc.rs +++ b/boards/metro_m4/examples/async_adc.rs @@ -42,21 +42,21 @@ async fn main(_s: embassy_executor::Spawner) -> ! { let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); // ...and enable the ADC0 PCLK. Both of these are required for the // ADC to run. - let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); + let (pclk_adc0, _gclk0) = Pclk::enable_dyn(tokens.pclks.adc0, clocks.gclk0); let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) .with_clock_cycles_per_sample(5) .with_clock_divider(Prescaler::Div32) .with_vref(atsamd_hal::adc::Reference::Arefa) - .enable(peripherals.adc0, apb_adc0, &pclk_adc0) + .enable(peripherals.adc0, apb_adc0, pclk_adc0) .unwrap() .into_future(Irqs); let mut adc_pin = pins.a0.into_alternate(); loop { - let res = adc.read(&mut adc_pin).await; + let _res = adc.read(&mut adc_pin).await; #[cfg(feature = "use_semihosting")] - cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap(); + cortex_m_semihosting::hprintln!("ADC Result: {}", _res).unwrap(); } } diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 09037dd0f24e..af07992cd9b6 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -462,6 +462,7 @@ impl GclkToken { /// The variants of this enum identify one generic clock generator. /// /// `DynGclkId` is the value-level equivalent of [`GclkId`]. +#[derive(Clone, Copy, PartialEq, Eq)] #[hal_macro_helper] pub enum DynGclkId { Gclk0, @@ -484,6 +485,32 @@ pub enum DynGclkId { Gclk11, } +impl core::fmt::Debug for DynGclkId { + #[hal_macro_helper] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Gclk0 => write!(f, "Gclk0"), + Self::Gclk1 => write!(f, "Gclk1"), + Self::Gclk2 => write!(f, "Gclk2"), + Self::Gclk3 => write!(f, "Gclk3"), + Self::Gclk4 => write!(f, "Gclk4"), + Self::Gclk5 => write!(f, "Gclk5"), + #[hal_cfg("gclk6")] + Self::Gclk6 => write!(f, "Gclk6"), + #[hal_cfg("gclk7")] + Self::Gclk7 => write!(f, "Gclk7"), + #[hal_cfg("gclk8")] + Self::Gclk8 => write!(f, "Gclk8"), + #[hal_cfg("gclk9")] + Self::Gclk9 => write!(f, "Gclk9"), + #[hal_cfg("gclk10")] + Self::Gclk10 => write!(f, "Gclk10"), + #[hal_cfg("gclk11")] + Self::Gclk11 => write!(f, "Gclk11"), + } + } +} + //============================================================================== // GclkId //============================================================================== diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index ace79da62e7a..02a04286dd95 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -547,6 +547,28 @@ impl From for Genselect { } } +impl PclkSourceId for DynPclkSourceId { + fn source_id(&self) -> DynGclkId { + *self + } +} + +impl Sealed for DynPclkSourceId {} + +//============================================================================== +// PclkSourceId +//============================================================================== + +pub struct PclkSource { + _src: PhantomData, +} + +impl GclkId for PclkSource { + const DYN: DynGclkId = G::DYN; + const NUM: usize = G::NUM; + type Divider = G::Divider; +} + //============================================================================== // PclkSourceId //============================================================================== @@ -566,9 +588,19 @@ impl From for Genselect { /// [`Gclk`]: super::gclk::Gclk /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums -pub trait PclkSourceId: GclkId {} +pub trait PclkSourceId: Sealed { + fn source_id(&self) -> DynGclkId; +} -impl PclkSourceId for G {} +// PclkSource implements PclkSourceId via its GclkId implementation +impl PclkSourceId for G { + #[inline] + fn source_id(&self) -> DynGclkId { + Self::DYN + } +} + +impl Sealed for PclkSource {} //============================================================================== // Pclk @@ -606,24 +638,41 @@ where I: PclkSourceId, { token: PclkToken

, - src: PhantomData, + src: I, freq: Hertz, } -impl Pclk +/// [`Pclk`] with a dynamic source ID ([`DynPclkSourceId`]). +pub type DynPclk

= Pclk; + +impl From>> for DynPclk

where P: PclkId, - I: PclkSourceId, + G: GclkId, +{ + fn from(value: Pclk>) -> Self { + Pclk { + token: value.token, + freq: value.freq, + src: G::DYN, + } + } +} + +impl Pclk> +where + P: PclkId, + G: GclkId, { pub(super) fn new(token: PclkToken

, freq: Hertz) -> Self { Self { token, - src: PhantomData, + src: PclkSource { _src: PhantomData }, freq, } } - /// Create and enable a [`Pclk`] + /// Create and enable a [`Pclk`] with a type-checked source ID. /// /// Creating a [`Pclk`] immediately enables the corresponding peripheral /// channel clock. It also [`Increment`]s the [`Source`]'s [`Enabled`] @@ -636,15 +685,15 @@ where #[inline] pub fn enable(mut token: PclkToken

, gclk: S) -> (Self, S::Inc) where - S: Source + Increment, + S: Source + Increment, { let freq = gclk.freq(); - token.enable(I::DYN); - let pclk = Pclk::new(token, freq); + token.enable(G::DYN); + let pclk = Self::new(token, freq); (pclk, gclk.inc()) } - /// Disable and destroy a [`Pclk`] + /// Disable and destroy a [`Pclk`]. /// /// Consume the [`Pclk`], release the [`PclkToken`], and [`Decrement`] the /// [`EnabledGclk`]'s counter @@ -654,12 +703,87 @@ where #[inline] pub fn disable(mut self, gclk: S) -> (PclkToken

, S::Dec) where - S: Source + Decrement, + S: Source + Decrement, + { + self.token.disable(); + (self.token, gclk.dec()) + } +} + +impl

DynPclk

+where + P: PclkId, +{ + pub(super) fn new(token: PclkToken

, freq: Hertz) -> Self { + Self { + token, + src: G::DYN, + freq, + } + } + + /// Create and enable a [`Pclk`] with an underlying [`DynPclkSourceId`] + /// source ID type. + /// + /// Some peripherals require a dynamic PCLK source ID type parameter; use + /// this method to create a [`Pclk`] where this type parameter is + /// type-erased. + /// + /// Creating a [`Pclk`] immediately enables the corresponding peripheral + /// channel clock. It also [`Increment`]s the [`Source`]'s [`Enabled`] + /// counter. + /// + /// Note that the [`Source`] will always be an [`EnabledGclk`]. + /// + /// [`Enabled`]: super::Enabled + /// [`EnabledGclk`]: super::gclk::EnabledGclk + #[inline] + pub fn enable_dyn(mut token: PclkToken

, gclk: S) -> (Self, S::Inc) + where + S: Source + Increment, + { + let freq = gclk.freq(); + token.enable(G::DYN); + let pclk = Self::new::(token, freq); + (pclk, gclk.inc()) + } + + /// Disable and destroy a [`Pclk`]. + /// + /// Consume the [`Pclk`], release the [`PclkToken`], and [`Decrement`] the + /// [`EnabledGclk`]'s counter. + /// + /// # Panics + /// + /// Panics if the [`Pclk`]'s underlying GCLK source ID does not match the ID + /// of the provided [`Source`]. + /// + /// [`Enabled`]: super::Enabled + /// [`EnabledGclk`]: super::gclk::EnabledGclk + #[inline] + pub fn disable(mut self, gclk: S) -> (PclkToken

, S::Dec) + where + S: Source + Decrement, { + // Make sure that we can only decrement the source we are actually using + assert_eq!( + G::DYN, + self.src, + "Expected GCLK ID {:?}, found {:?}", + G::DYN, + self.src + ); + self.token.disable(); (self.token, gclk.dec()) } +} +impl Pclk +where + P: PclkId, + I: PclkSourceId, +{ /// Return the [`Pclk`] frequency #[inline] pub fn freq(&self) -> Hertz { diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index 1c44f83f3268..a9831beadbcb 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -6,7 +6,10 @@ use atsamd_hal_macros::hal_macro_helper; use typenum::U1; -use crate::pac::{Gclk, Pm, Sysctrl}; +use crate::{ + clock::v2::pclk::PclkSource, + pac::{Gclk, Pm, Sysctrl}, +}; use super::*; @@ -97,7 +100,7 @@ pub struct Clocks { /// Always-enabled OSCULP oscillators pub osculp: OscUlpClocks, /// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2) - pub wdt: pclk::Pclk, + pub wdt: pclk::Pclk>, } /// Type-level tokens for unused clocks at power-on reset @@ -155,7 +158,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl let osculp32k = Enabled::<_, U0>::new(osculp32k::OscUlp32k::new()); let (gclk2, osculp32k) = gclk::Gclk2::from_source(gclk::GclkToken::new(), osculp32k); let gclk2 = Enabled::new(gclk2); - let wdt = pclk::Pclk::new(pclk::PclkToken::new(), gclk2.freq()); + let wdt = pclk::Pclk::<_, PclkSource<_>>::new(pclk::PclkToken::new(), gclk2.freq()); let osculp = OscUlpClocks { base, osculp1k, diff --git a/hal/src/peripherals/adc/builder.rs b/hal/src/peripherals/adc/builder.rs index cb81c09d3b7c..3654a37da9fd 100644 --- a/hal/src/peripherals/adc/builder.rs +++ b/hal/src/peripherals/adc/builder.rs @@ -244,15 +244,19 @@ impl AdcBuilder { Ok(adc_clk_freq / clocks_per_sample) } - /// Turn the builder into an ADC + /// Turn the builder into an ADC. + /// + /// This function will convert the provided + /// [`Pclk`](crate::clock::v2::pclk::Pclk) into a [`DynPclk`](crate::clock::v2::pclk::DynPclk). + #[hal_cfg("adc-d5x")] #[inline] - pub fn enable( + pub fn enable( self, adc: I::Instance, clk: crate::clock::v2::apb::ApbClk, - pclk: &crate::clock::v2::pclk::Pclk, + pclk: impl Into>, ) -> Result, BuilderError> { let settings = self.to_settings()?; - Adc::new(adc, settings, clk, pclk).map_err(|e| e.into()) + Adc::new(adc, settings, clk, pclk.into()).map_err(|e| e.into()) } } diff --git a/hal/src/peripherals/adc/mod.rs b/hal/src/peripherals/adc/mod.rs index eed8cdc28650..55968beceddd 100644 --- a/hal/src/peripherals/adc/mod.rs +++ b/hal/src/peripherals/adc/mod.rs @@ -48,7 +48,10 @@ pub use builder::*; #[hal_cfg(any("adc-d11", "adc-d21"))] use crate::pac::adc as adc0; #[hal_cfg("adc-d5x")] -use crate::pac::adc0; +use crate::{ + clock::v2::{apb::ApbClk, pclk::DynPclk}, + pac::adc0, +}; pub use adc0::refctrl::Refselselect as Reference; @@ -160,7 +163,8 @@ where pub struct Adc { adc: I::Instance, - _apbclk: crate::clock::v2::apb::ApbClk, + _apbclk: ApbClk, + _pclk: DynPclk, cfg: AdcSettings, discard: bool, } @@ -189,11 +193,11 @@ impl Adc { /// frequency for the ADC is restricted to 90Mhz for stable performance. #[inline] #[atsamd_hal_macros::hal_macro_helper] - pub(crate) fn new( + pub(crate) fn new( adc: I::Instance, settings: AdcSettings, - clk: crate::clock::v2::apb::ApbClk, - pclk: &crate::clock::v2::pclk::Pclk, + clk: ApbClk, + pclk: DynPclk, ) -> Result { // TODO: Ideally, the ADC struct would take ownership of the Pclk type here. // However, since clock::v2 is not implemented for all chips yet, the @@ -218,6 +222,7 @@ impl Adc { let mut new_adc = Self { adc, _apbclk: clk, + _pclk: pclk, cfg: settings, discard: true, }; @@ -369,9 +374,9 @@ impl Adc { /// Return the underlying ADC PAC object and the enabled APB ADC clock. #[inline] - pub fn free(mut self) -> (I::Instance, crate::clock::v2::apb::ApbClk) { + pub fn free(mut self) -> (I::Instance, ApbClk, DynPclk) { self.software_reset(); - (self.adc, self._apbclk) + (self.adc, self._apbclk, self._pclk) } /// Reset the peripheral. From 5adb203e2d48e703296336f7547698d3f27e110d Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Tue, 2 Jun 2026 13:51:29 -0400 Subject: [PATCH 114/114] Also builds on thumbv6m targets! --- hal/src/peripherals/adc/builder.rs | 9 ++++----- hal/src/peripherals/adc/mod.rs | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/hal/src/peripherals/adc/builder.rs b/hal/src/peripherals/adc/builder.rs index 3654a37da9fd..a42ee1a8e7fa 100644 --- a/hal/src/peripherals/adc/builder.rs +++ b/hal/src/peripherals/adc/builder.rs @@ -1,5 +1,7 @@ use atsamd_hal_macros::hal_cfg; +use crate::clock::v2::{apb::ApbClk, pclk::DynPclk}; + #[hal_cfg("adc-d5x")] use crate::pac::adc0; @@ -13,9 +15,7 @@ pub use adc0::ctrlb::Prescalerselect as Prescaler; pub use adc0::ctrla::Prescalerselect as Prescaler; pub use adc0::avgctrl::Samplenumselect as SampleCount; - pub use adc0::ctrlb::Resselselect as Resolution; - pub use adc0::refctrl::Refselselect as Reference; use super::{Adc, AdcInstance}; @@ -248,13 +248,12 @@ impl AdcBuilder { /// /// This function will convert the provided /// [`Pclk`](crate::clock::v2::pclk::Pclk) into a [`DynPclk`](crate::clock::v2::pclk::DynPclk). - #[hal_cfg("adc-d5x")] #[inline] pub fn enable( self, adc: I::Instance, - clk: crate::clock::v2::apb::ApbClk, - pclk: impl Into>, + clk: ApbClk, + pclk: impl Into>, ) -> Result, BuilderError> { let settings = self.to_settings()?; Adc::new(adc, settings, clk, pclk.into()).map_err(|e| e.into()) diff --git a/hal/src/peripherals/adc/mod.rs b/hal/src/peripherals/adc/mod.rs index 55968beceddd..099819737488 100644 --- a/hal/src/peripherals/adc/mod.rs +++ b/hal/src/peripherals/adc/mod.rs @@ -27,7 +27,12 @@ use core::ops::Deref; use atsamd_hal_macros::{hal_cfg, hal_module}; use pac::Peripherals; -use crate::{gpio::AnyPin, pac, typelevel::Sealed}; +use crate::{ + clock::v2::{apb::ApbClk, pclk::DynPclk}, + gpio::AnyPin, + pac, + typelevel::Sealed, +}; #[hal_module( any("adc-d11", "adc-d21") => "d11/mod.rs", @@ -48,10 +53,7 @@ pub use builder::*; #[hal_cfg(any("adc-d11", "adc-d21"))] use crate::pac::adc as adc0; #[hal_cfg("adc-d5x")] -use crate::{ - clock::v2::{apb::ApbClk, pclk::DynPclk}, - pac::adc0, -}; +use crate::pac::adc0; pub use adc0::refctrl::Refselselect as Reference; @@ -163,8 +165,8 @@ where pub struct Adc { adc: I::Instance, - _apbclk: ApbClk, - _pclk: DynPclk, + _apbclk: crate::clock::v2::apb::ApbClk, + _pclk: crate::clock::v2::pclk::DynPclk, cfg: AdcSettings, discard: bool, } @@ -196,8 +198,8 @@ impl Adc { pub(crate) fn new( adc: I::Instance, settings: AdcSettings, - clk: ApbClk, - pclk: DynPclk, + clk: crate::clock::v2::apb::ApbClk, + pclk: crate::clock::v2::pclk::DynPclk, ) -> Result { // TODO: Ideally, the ADC struct would take ownership of the Pclk type here. // However, since clock::v2 is not implemented for all chips yet, the