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.