From fd706afaec4c850666900c3e50904820a5d34d81 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 18 Nov 2023 19:12:49 +0200 Subject: [PATCH] Replace registers module with ral-registers --- CHANGELOG.md | 1 + Cargo.toml | 1 + src/ral/mod.rs | 4 +- src/ral/register.rs | 610 -------------------------------------------- 4 files changed, 4 insertions(+), 612 deletions(-) delete mode 100644 src/ral/register.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 43ffdcc..425f786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed * Use `critical-section` crate for critical sections. +* Replaced bundled RAL macros with `ral-registers` ## [v0.4.0] - 2023-11-18 diff --git a/Cargo.toml b/Cargo.toml index 4e9099d..d25d028 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ critical-section = "1.0" embedded-hal = "0.2.4" vcell = "0.1.0" usb-device = "0.3" +ral-registers = "0.1.3" [package.metadata.docs.rs] features = ['fs'] diff --git a/src/ral/mod.rs b/src/ral/mod.rs index 7d5032e..a87223c 100644 --- a/src/ral/mod.rs +++ b/src/ral/mod.rs @@ -2,10 +2,10 @@ pub mod instances; pub mod peripherals; -pub mod register; pub mod stm32f429; -pub use crate::{modify_reg, read_reg, write_reg}; +pub use ral_registers as register; +pub use ral_registers::{modify_reg, read_reg, write_reg}; pub mod otg_global { #[cfg(feature = "fs")] diff --git a/src/ral/register.rs b/src/ral/register.rs deleted file mode 100644 index 4584e7c..0000000 --- a/src/ral/register.rs +++ /dev/null @@ -1,610 +0,0 @@ -#![allow(unused)] -use core::cell::UnsafeCell; - -/// A read-write register of type T. -/// -/// Contains one value of type T and provides volatile read/write functions to it. -/// -/// # Safety -/// This register should be used where reads and writes to this peripheral register do not -/// lead to memory unsafety. For example, it is a poor choice for a DMA target, but less -/// worrisome for a GPIO output data register. -/// -/// Access to this register must be synchronised; if multiple threads (or the main thread and an -/// interrupt service routine) are accessing it simultaneously you may encounter data races. -pub struct RWRegister { - register: UnsafeCell, -} - -impl RWRegister { - /// Reads the value of the register. - #[inline(always)] - pub fn read(&self) -> T { - unsafe { ::core::ptr::read_volatile(self.register.get()) } - } - - /// Writes a new value to the register. - #[inline(always)] - pub fn write(&self, val: T) { - unsafe { ::core::ptr::write_volatile(self.register.get(), val) } - } -} - -/// A read-write register of type T, where read/write access is unsafe. -/// -/// Contains one value of type T and provides volatile read/write functions to it. -/// -/// # Safety -/// This register should be used where reads and writes to this peripheral may invoke -/// undefined behaviour or memory unsafety. For example, any registers you write a memory -/// address into. -/// -/// Access to this register must be synchronised; if multiple threads (or the main thread and an -/// interrupt service routine) are accessing it simultaneously you may encounter data races. -pub struct UnsafeRWRegister { - register: UnsafeCell, -} - -impl UnsafeRWRegister { - /// Reads the value of the register. - #[inline(always)] - pub unsafe fn read(&self) -> T { - ::core::ptr::read_volatile(self.register.get()) - } - - /// Writes a new value to the register. - #[inline(always)] - pub unsafe fn write(&self, val: T) { - ::core::ptr::write_volatile(self.register.get(), val) - } -} - -/// A read-only register of type T. -/// -/// Contains one value of type T and provides a volatile read function to it. -/// -/// # Safety -/// This register should be used where reads and writes to this peripheral register do not -/// lead to memory unsafety. -/// -/// Access to this register must be synchronised; if multiple threads (or the main thread and an -/// interrupt service routine) are accessing it simultaneously you may encounter data races. -pub struct RORegister { - register: UnsafeCell, -} - -impl RORegister { - /// Reads the value of the register. - #[inline(always)] - pub fn read(&self) -> T { - unsafe { ::core::ptr::read_volatile(self.register.get()) } - } -} - -/// A read-only register of type T, where read access is unsafe. -/// -/// Contains one value of type T and provides a volatile read function to it. -/// -/// # Safety -/// This register should be used where reads to this peripheral may invoke -/// undefined behaviour or memory unsafety. -/// -/// Access to this register must be synchronised; if multiple threads (or the main thread and an -/// interrupt service routine) are accessing it simultaneously you may encounter data races. -pub struct UnsafeRORegister { - register: UnsafeCell, -} - -impl UnsafeRORegister { - /// Reads the value of the register. - #[inline(always)] - pub unsafe fn read(&self) -> T { - ::core::ptr::read_volatile(self.register.get()) - } -} - -/// A write-only register of type T. -/// -/// Contains one value of type T and provides a volatile write function to it. -/// -/// # Safety -/// This register should be used where writes to this peripheral register do not lead to memory -/// unsafety. -/// -/// Access to this register must be synchronised; if multiple threads (or the main thread and an -/// interrupt service routine) are accessing it simultaneously you may encounter data races. -pub struct WORegister { - register: UnsafeCell, -} - -impl WORegister { - /// Writes a new value to the register. - #[inline(always)] - pub fn write(&self, val: T) { - unsafe { ::core::ptr::write_volatile(self.register.get(), val) } - } -} - -/// A write-only register of type T, where write access is unsafe. -/// -/// Contains one value of type T and provides a volatile write function to it. -/// -/// # Safety -/// This register should be used where reads and writes to this peripheral may invoke -/// undefined behaviour or memory unsafety. -/// -/// Access to this register must be synchronised; if multiple threads (or the main thread and an -/// interrupt service routine) are accessing it simultaneously you may encounter data races. -pub struct UnsafeWORegister { - register: UnsafeCell, -} - -impl UnsafeWORegister { - /// Writes a new value to the register. - #[inline(always)] - pub unsafe fn write(&self, val: T) { - ::core::ptr::write_volatile(self.register.get(), val) - } -} - -/// Write to a RWRegister or UnsafeRWRegister. -/// -/// # Examples -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// // Safely acquire the peripheral instance (will panic if already acquired) -/// let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// -/// // Write some value to the register. -/// write_reg!(stm32ral::gpio, gpioa, ODR, 1<<3); -/// -/// // Write values to specific fields. Unspecified fields are written to 0. -/// write_reg!(stm32ral::gpio, gpioa, MODER, MODER3: Output, MODER4: Analog); -/// -/// // Unsafe access without requiring you to first `take()` the instance -/// unsafe { write_reg!(stm32ral::gpio, GPIOA, MODER, MODER3: Output, MODER4: Analog) }; -/// # } -/// ``` -/// -/// # Usage -/// Like `modify_reg!`, this macro can be used in two ways, either with a single value to write to -/// the whole register, or with multiple fields each with their own value. -/// -/// In both cases, the first arguments are: -/// * the path to the peripheral module: `stm32ral::gpio`, -/// * a reference to the instance of that peripheral: 'gpioa' (anything which dereferences to -/// `RegisterBlock`, such as `Instance`, `&Instance`, `&RegisterBlock`, or -/// `*const RegisterBlock`), -/// * the register you wish you access: `MODER` (a field on the `RegisterBlock`). -/// -/// In the single-value usage, the final argument is just the value to write: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // Turn on PA3 (and turn everything else off). -/// write_reg!(stm32ral::gpio, gpioa, ODR, 1<<3); -/// # } -/// ``` -/// -/// Otherwise, the remaining arguments are each `Field: Value` pairs: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// // Set PA3 to Output, PA4 to Analog, and everything else to 0 (which is Input). -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// write_reg!(stm32ral::gpio, gpioa, MODER, MODER3: 0b01, MODER4: 0b11); -/// # } -/// ``` -/// For fields with annotated values, you can also specify a named value: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// // As above, but with named values. -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// write_reg!(stm32ral::gpio, gpioa, MODER, MODER3: Output, MODER4: Analog); -/// # } -/// ``` -/// -/// This macro expands to calling `(*$instance).$register.write(value)`, -/// where in the second usage, the value is computed as the bitwise OR of -/// each field value, which are masked and shifted appropriately for the given field. -/// The named values are brought into scope by `use $peripheral::$register::$field::*` for -/// each field. The same constants could just be specified manually: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// // As above, but being explicit about named values. -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// write_reg!(stm32ral::gpio, gpioa, MODER, MODER3: stm32ral::gpio::MODER::MODER3::RW::Output, -/// MODER4: stm32ral::gpio::MODER::MODER4::RW::Analog); -/// # } -/// ``` -/// -/// The fully expanded form is equivalent to: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// // As above, but expanded. -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// (*gpioa).MODER.write( -/// ((stm32ral::gpio::MODER::MODER3::RW::Output << stm32ral::gpio::MODER::MODER3::offset) -/// & stm32ral::gpio::MODER::MODER3::mask) -/// | -/// ((stm32ral::gpio::MODER::MODER4::RW::Analog << stm32ral::gpio::MODER::MODER4::offset) -/// & stm32ral::gpio::MODER::MODER4::mask) -/// ); -/// # } -/// ``` -/// -/// # Safety -/// This macro will require an unsafe function or block when used with an UnsafeRWRegister, -/// but not if used with RWRegister. -/// -/// When run in an unsafe context, peripheral instances are directly accessible without requiring -/// having called `take()` beforehand: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// unsafe { write_reg!(stm32ral::gpio, GPIOA, MODER, MODER3: Output, MODER4: Analog) }; -/// # } -/// ``` -/// This works because `GPIOA` is a `*const RegisterBlock` in the `stm32ral::gpio` module; -/// and the macro brings such constants into scope and then dereferences the provided reference. -#[macro_export] -#[doc(hidden)] -macro_rules! write_reg { - ( $periph:path, $instance:expr, $reg:ident, $( $field:ident : $value:expr ),+ ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - #[allow(unused_imports)] - (*$instance).$reg.write( - $({ use $periph::{$reg::$field::{mask, offset, W::*, RW::*}}; ($value << offset) & mask }) | * - ); - }}; - ( $periph:path, $instance:expr, $reg:ident, $value:expr ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - (*$instance).$reg.write($value); - }}; -} - -/// Modify a RWRegister or UnsafeRWRegister. -/// -/// # Examples -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// // Safely acquire the peripheral instance (will panic if already acquired) -/// let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// -/// // Update the register to ensure bit 3 is set. -/// modify_reg!(stm32ral::gpio, gpioa, ODR, |reg| reg | (1<<3)); -/// -/// // Write values to specific fields. Unspecified fields are left unchanged. -/// modify_reg!(stm32ral::gpio, gpioa, MODER, MODER3: Output, MODER4: Analog); -/// -/// // Unsafe access without requiring you to first `take()` the instance -/// unsafe { modify_reg!(stm32ral::gpio, GPIOA, MODER, MODER3: Output, MODER4: Analog) }; -/// # } -/// ``` -/// -/// # Usage -/// Like `write_reg!`, this macro can be used in two ways, either with a modification of the entire -/// register, or by specifying which fields to change and what value to change them to. -/// -/// In both cases, the first arguments are: -/// * the path to the peripheral module: `stm32ral::gpio`, -/// * a reference to the instance of that peripheral: 'gpioa' (anything which dereferences to -/// `RegisterBlock`, such as `Instance`, `&Instance`, `&RegisterBlock`, or -/// `*const RegisterBlock`), -/// * the register you wish you access: `MODER` (a field on the `RegisterBlock`). -/// -/// In the whole-register usage, the final argument is a closure that accepts the current value -/// of the register and returns the new value to write: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // Turn on PA3 without affecting anything else. -/// modify_reg!(stm32ral::gpio, gpioa, ODR, |reg| reg | (1<<3)); -/// # } -/// ``` -/// -/// Otherwise, the remaining arguments are `Field: Value` pairs: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // Set PA3 to Output, PA4 to Analog, and leave everything else unchanged. -/// modify_reg!(stm32ral::gpio, gpioa, MODER, MODER3: 0b01, MODER4: 0b11); -/// # } -/// ``` -/// -/// For fields with annotated values, you can also specify a named value: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // As above, but with named values. -/// modify_reg!(stm32ral::gpio, gpioa, MODER, MODER3: Output, MODER4: Analog); -/// # } -/// ``` -/// -/// This macro expands to calling `(*instance).register.write(value)`. -/// When called with a closure, `(*instance).register.read()` is called, the result -/// passed in to the closure, and the return value of the closure is used for `value`. -/// When called with `Field: Value` arguments, the current value is read and then masked -/// according to the specified fields, and then ORd with the OR of each field value, -/// each masked and shifted appropriately for the field. The named values are brought into scope -/// by `use peripheral::register::field::*` for each field. The same constants could just be -/// specified manually: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // As above, but being explicit about named values. -/// modify_reg!(stm32ral::gpio, gpioa, MODER, MODER3: stm32ral::gpio::MODER::MODER3::RW::Output, -/// MODER4: stm32ral::gpio::MODER::MODER4::RW::Analog); -/// # } -/// ``` -/// -/// The fully expanded form is equivalent to: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // As above, but expanded. -/// (*gpioa).MODER.write( -/// ( -/// // First read the current value... -/// (*gpioa).MODER.read() -/// // Then AND it with an appropriate mask... -/// & -/// !( stm32ral::gpio::MODER::MODER3::mask | stm32ral::gpio::MODER::MODER4::mask ) -/// ) -/// // Then OR with each field value. -/// | -/// ((stm32ral::gpio::MODER::MODER3::RW::Output << stm32ral::gpio::MODER::MODER3::offset) -/// & stm32ral::gpio::MODER::MODER3::mask) -/// | -/// ((stm32ral::gpio::MODER::MODER4::RW::Analog << stm32ral::gpio::MODER::MODER3::offset) -/// & stm32ral::gpio::MODER::MODER3::mask) -/// ); -/// # } -/// ``` -/// -/// # Safety -/// This macro will require an unsafe function or block when used with an UnsafeRWRegister, -/// but not if used with RWRegister. -/// -/// When run in an unsafe context, peripheral instances are directly accessible without requiring -/// having called `take()` beforehand: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// unsafe { modify_reg!(stm32ral::gpio, GPIOA, MODER, MODER3: Output, MODER4: Analog) }; -/// # } -/// ``` -/// This works because `GPIOA` is a `*const RegisterBlock` in the `stm32ral::gpio` module; -/// and the macro brings such constants into scope and then dereferences the provided reference. -#[macro_export] -#[doc(hidden)] -macro_rules! modify_reg { - ( $periph:path, $instance:expr, $reg:ident, $( $field:ident : $value:expr ),+ ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - #[allow(unused_imports)] - (*$instance).$reg.write( - ((*$instance).$reg.read() & !( $({ use $periph::{$reg::$field::mask}; mask }) | * )) - | $({ use $periph::{$reg::$field::{mask, offset, W::*, RW::*}}; ($value << offset) & mask }) | *); - }}; - ( $periph:path, $instance:expr, $reg:ident, $fn:expr ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - (*$instance).$reg.write($fn((*$instance).$reg.read())); - }}; -} - -/// Read the value from a RORegister, RWRegister, UnsafeRORegister, or UnsafeRWRegister. -/// -/// # Examples -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// // Safely acquire the peripheral instance (will panic if already acquired) -/// let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// -/// // Read the whole register. -/// let val = read_reg!(stm32ral::gpio, gpioa, IDR); -/// -/// // Read one field from the register. -/// let val = read_reg!(stm32ral::gpio, gpioa, IDR, IDR2); -/// -/// // Read multiple fields from the register. -/// let (val1, val2, val3) = read_reg!(stm32ral::gpio, gpioa, IDR, IDR0, IDR1, IDR2); -/// -/// // Check if one field is equal to a specific value, with the field's named values in scope. -/// while read_reg!(stm32ral::gpio, gpioa, IDR, IDR2 == High) {} -/// -/// // Unsafe access without requiring you to first `take()` the instance -/// let val = unsafe { read_reg!(stm32ral::gpio, GPIOA, IDR) }; -/// # } -/// ``` -/// -/// # Usage -/// Like `write_reg!`, this macro can be used multiple ways, either reading the entire register or -/// reading a one or more fields from it and potentially performing a comparison with one field. -/// -/// In all cases, the first arguments are: -/// * the path to the peripheral module: `stm32ral::gpio`, -/// * a reference to the instance of that peripheral: 'gpioa' (anything which dereferences to -/// `RegisterBlock`, such as `Instance`, `&Instance`, `&RegisterBlock`, or -/// `*const RegisterBlock`), -/// * the register you wish to access: `IDR` (a field on the `RegisterBlock`). -/// -/// In the whole-register usage, the macro simply returns the register's value: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // Read the entire value of GPIOA.IDR into `val`. -/// let val = read_reg!(stm32ral::gpio, gpioa, IDR); -/// # } -/// ``` -/// -/// For reading individual fields, the macro masks and shifts appropriately: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // Read just the value of the field GPIOA.IDR2 into `val`. -/// let val = read_reg!(stm32ral::gpio, gpioa, IDR, IDR2); -/// -/// // As above, but expanded for exposition: -/// let val = ((*gpioa).IDR.read() & stm32ral::gpio::IDR::IDR2::mask) -/// >> stm32ral::gpio::IDR::IDR2::offset; -/// -/// // Read multiple fields -/// let (val1, val2) = read_reg!(stm32ral::gpio, gpioa, IDR, IDR2, IDR3); -/// -/// // As above, but expanded for exposition: -/// let (val1, val2) = { let val = (*gpioa).IDR.read(); -/// ((val & stm32ral::gpio::IDR::IDR2::mask) >> stm32ral::gpio::IDR::IDR2::offset, -/// (val & stm32ral::gpio::IDR::IDR3::mask) >> stm32ral::gpio::IDR::IDR3::offset, -/// )}; -/// # } -/// ``` -/// -/// For comparing a single field, the macro masks and shifts and then performs the comparison: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// # let rcc = stm32ral::rcc::RCC::take().unwrap(); -/// // Loop while PA2 is High. -/// while read_reg!(stm32ral::gpio, gpioa, IDR, IDR2 == High) {} -/// -/// // Only proceed if the clock is not the HSI. -/// if read_reg!(stm32ral::rcc, rcc, CFGR, SWS != HSI) { } -/// -/// // Equivalent expansion: -/// if (((*rcc).CFGR.read() & stm32ral::rcc::CFGR::SWS::mask) -/// >> stm32ral::rcc::CFGR::SWS::offset) != stm32ral::rcc::CFGR::SWS::R::HSI { } -/// # } -/// ``` -/// -/// # Safety -/// This macro will require an unsafe function or block when used with an UnsafeRWRegister or -/// UnsafeRORegister, but not if used with RWRegister, or RORegister. -/// -/// When run in an unsafe context, peripheral instances are directly accessible without requiring -/// having called `take()` beforehand: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// let val = unsafe { read_reg!(stm32ral::gpio, GPIOA, MODER) }; -/// # } -/// ``` -/// This works because `GPIOA` is a `*const RegisterBlock` in the `stm32ral::gpio` module; -/// and the macro brings such constants into scope and then dereferences the provided reference. -#[macro_export] -#[doc(hidden)] -macro_rules! read_reg { - ( $periph:path, $instance:expr, $reg:ident, $( $field:ident ),+ ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - let val = ((*$instance).$reg.read()); - ( $({ - #[allow(unused_imports)] - use $periph::{$reg::$field::{mask, offset, R::*, RW::*}}; - (val & mask) >> offset - }) , *) - }}; - ( $periph:path, $instance:expr, $reg:ident, $field:ident $($cmp:tt)* ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - #[allow(unused_imports)] - use $periph::{$reg::$field::{mask, offset, R::*, RW::*}}; - (((*$instance).$reg.read() & mask) >> offset) $($cmp)* - }}; - ( $periph:path, $instance:expr, $reg:ident ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - ((*$instance).$reg.read()) - }}; -} - -/// Reset a RWRegister, UnsafeRWRegister, WORegister, or UnsafeWORegister to its reset value. -/// -/// # Examples -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// // Safely acquire the peripheral instance (will panic if already acquired) -/// let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// -/// // Reset PA14 and PA15 to their reset state -/// reset_reg!(stm32ral::gpio, gpioa, GPIOA, MODER, MODER14, MODER15); -/// -/// // Reset the entire GPIOA.MODER to its reset state -/// reset_reg!(stm32ral::gpio, gpioa, GPIOA, MODER); -/// # } -/// ``` -/// -/// # Usage -/// Like `write_reg!`, this macro can be used in two ways, either resetting the entire register -/// or just resetting specific fields within in. The register or fields are written with their -/// reset values. -/// -/// In both cases, the first arguments are: -/// * the path to the peripheral module: `stm32ral::gpio`, -/// * a reference to the instance of that peripheral: 'gpioa' (anything which dereferences to -/// `RegisterBlock`, such as `Instance`, `&Instance`, `&RegisterBlock`, or -/// `*const RegisterBlock`), -/// * the module for the instance of that peripheral: `GPIOA`, -/// * the register you wish to access: `MODER` (a field on the `RegisterBlock`). -/// -/// In the whole-register usage, that's it: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // Reset the entire GPIOA.MODER -/// reset_reg!(stm32ral::gpio, gpioa, GPIOA, MODER); -/// # } -/// ``` -/// -/// Otherwise, the remaining arguments are each field names: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); -/// // Reset the JTAG pins -/// reset_reg!(stm32ral::gpio, gpioa, GPIOA, MODER, MODER13, MODER14, MODER15); -/// reset_reg!(stm32ral::gpio, gpioa, GPIOB, MODER, MODER3, MODER4); -/// # } -/// ``` -/// -/// The second form is only available to RWRegister and UnsafeRWRegister, since `.read()` is -/// not available for WORegister and UnsafeWORegister. -/// -/// This macro expands to calling `(*$instance).$register.write(value)`, where -/// `value` is either the register's reset value, or the current read value of the register -/// masked appropriately and combined with the reset value for each field. -/// -/// # Safety -/// This macro will require an unsafe function or block when used with an UnsafeRWRegister or -/// UnsafeRORegister, but not if used with RWRegister or RORegister. -/// -/// When run in an unsafe context, peripheral instances are directly accessible without requiring -/// having called `take()` beforehand: -/// ```rust,no_run -/// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { -/// unsafe { reset_reg!(stm32ral::gpio, GPIOA, GPIOA, MODER) }; -/// # } -/// ``` -/// This works because `GPIOA` is a `*const RegisterBlock` in the `stm32ral::gpio` module; -/// and the macro brings such constants into scope and then dereferences the provided reference. -/// -/// Note that the second argument is a `*const` and the third is a path; despite both being written -/// `GPIOA` they are not the same thing. -#[macro_export] -#[doc(hidden)] -macro_rules! reset_reg { - ( $periph:path, $instance:expr, $instancemod:path, $reg:ident, $( $field:ident ),+ ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - use $periph::{$instancemod::{reset}}; - #[allow(unused_imports)] - (*$instance).$reg.write({ - let resetmask: u32 = $({ use $periph::{$reg::$field::mask}; mask }) | *; - ((*$instance).$reg.read() & !resetmask) | (reset.$reg & resetmask) - }); - }}; - ( $periph:path, $instance:expr, $instancemod:path, $reg:ident ) => {{ - #[allow(unused_imports)] - use $periph::{*}; - use $periph::{$instancemod::{reset}}; - (*$instance).$reg.write(reset.$reg); - }}; -}