macro_rules! modify_reg { ( $periph:path, $instance:expr, $reg:ident $([$offset:expr])*, $( $field:ident : $value:expr ),+ $(,)? ) => { ... }; ( $periph:path, $instance:expr, $reg:ident $([$offset:expr])*, $fn:expr ) => { ... }; }
Expand description
Modify a RWRegister or UnsafeRWRegister.
§Examples
// 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) };
To support register arrays, each macro form also supports one or more array indices after the
register. For example, modify_reg!(stm32ral::gpio, gpioa, ODR[2], |reg| reg | (1<<3));
sets
a high bit in the third register of an ODR
register array.
§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 asInstance
,&Instance
,&RegisterBlock
, or*const RegisterBlock
), - the register (and offset, for arrays) you wish you access:
MODER
(a field on theRegisterBlock
).
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:
// 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:
// 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:
// 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:
// 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:
// 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:
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.