Register access layer
The imxrt-ral
crate provides a
register access layer (RAL) for i.MX RT 10xx and 11xx microcontrollers. Use the
RAL to
- manage peripherals as low-level resources.
- conveniently access registers and register fields.
imxrt-ral
also provides a device-specific interrupt table. Once you link the
runtime with the RAL,
- enable
imxrt-rt
's"device"
feature. - enable
imxrt-ral
's"rt"
feature.
ℹ️ The RAL is very similar to the peripheral access crate (PAC) found in other embedded Rust ecosystems. The major difference is the API used to access registers.
This example improves on the previous walkthrough by using
imxrt-ral
to access registers. Note the imxrt-ral
feature flag for the
target MCU. Also note that the "device"
feature for the runtime is enabled,
and the "rt"
feature for imxrt-ral
is enabled; even though the example
doesn't use interrupts, you should prefer the device-specific vector table when
available.
# Cargo.toml
[dependencies]
imxrt-ral = { version = "0.5", features = ["imxrt1011", "rt"] }
imxrt-rt = { version = "0.1", features = ["device"] }
# As before...
imxrt1010evk-fcb = "0.1"
panic-halt = "0.2"
[build-dependencies]
imxrt-rt = { version = "0.1", features = ["device"] }
//! build.rs (unchanged) use imxrt_rt::{Family, RuntimeBuilder}; fn main() { RuntimeBuilder::from_flexspi(Family::Imxrt1010, 16 * 1024 * 1024) .build() .unwrap(); }
//! main.rs #![no_main] #![no_std] use imxrt_ral as ral; use imxrt1010evk_fcb as _; use imxrt_rt::entry; use panic_halt as _; const LED_OFFSET: u32 = 1 << 11; #[entry] fn main() -> ! { // Safety: we're the only code that "owns" the IOMUXC and GPIO1 peripherals. let iomuxc = unsafe { ral::iomuxc::IOMUXC::instance() }; let gpio1 = unsafe { ral::gpio::GPIO1::instance() }; // Configure the pad named "GPIO_11" as a GPIO pin // (as opposed to a UART TX pin, for example). ral::write_reg!(ral::iomuxc, iomuxc, SW_MUX_CTL_PAD_GPIO_11, 5); // Set the GPIO as an output with a RMW operation. ral::modify_reg!(ral::gpio, gpio1, GDIR, |gdir| gdir | LED_OFFSET); // Turn on the LED. ral::write_reg!(ral::gpio, gpio1, DR_SET, LED_OFFSET); loop {} }
Acquiring peripheral instances is still unsafe
. However, macros make it easier
to read, write, and modify registers; and there's no need to maintain register
addresses.
Consider using imxrt-ral
when you want to implement higher-level peripheral
drivers. These kinds of convenient, re-usable, and portable peripheral drivers
are the topic of the next section: the hardware abstraction layer.