imxrt_ral

Macro write_reg

source
macro_rules! write_reg {
    ( $periph:path, $instance:expr, $reg:ident $([$offset:expr])*, $( $field:ident : $value:expr ),+ $(,)? ) => { ... };
    ( $periph:path, $instance:expr, $reg:ident $([$offset:expr])*, $value:expr ) => { ... };
}
Expand description

Write to a RWRegister or UnsafeRWRegister.

§Examples

// 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) };

To support register arrays, each macro form also supports one or more array indices after the register. For example, write_reg!(stm32ral::gpio, gpioa, ODR[2], 42); writes the value 42 to the third register in an ODR register array.

§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 (and offset, for arrays) you wish you access: MODER (a field on the RegisterBlock).

In the single-value usage, the final argument is just the value to write:

// 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:

// Set PA3 to Output, PA4 to Analog, and everything else to 0 (which is Input).
write_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.
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:

// As above, but being explicit about named values.
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:

// As above, but expanded.
(*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:

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.