imxrt_ral

Macro read_reg

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

Read the value from a RORegister, RWRegister, UnsafeRORegister, or UnsafeRWRegister.

§Examples

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

To support register arrays, each macro form also supports one or more array indices after the register. For example, read_reg!(stm32ral::gpio, gpioa, ODR[2]); reads from the third register of an ODR register array.

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

In the whole-register usage, the macro simply returns the register’s value:

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

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

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

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.