imxrt_rt/lib.rs
1//! Runtime and startup support for i.MX RT processors.
2//!
3//! This crate builds on `cortex-m-rt` and adds support for i.MX RT processors.
4//! Using this runtime crate, you can specify FlexRAM sizes and section allocations,
5//! then use it to boot your i.MX RT processor.
6//!
7//! The crate achieves this with
8//!
9//! - a build-time API to define the memory map.
10//! - a runtime library to configure the embedded processor.
11//!
12//! Both APIs are exposed from the same package. The interface changes depending on the
13//! build environment.
14//!
15//! # Getting started
16//!
17//! Make sure you're familiar with [`cortex-m-rt`][cmrt] features. This crate re-exports
18//! the `cortex-m-rt` interface. Use this interface to implement your program's entrypoint,
19//! register exceptions, and interrupts. You should be familiar with specifing a linker
20//! script for your embedded project.
21//!
22//! [cmrt]: https://docs.rs/cortex-m-rt/0.7.3/cortex_m_rt/
23//!
24//! # Dependencies
25//!
26//! In your embedded target, depend on `imxrt-rt` in both of
27//!
28//! - the `[dependencies]` section of your Cargo.toml
29//! - the `[build-dependencies]` section of your Cargo.toml
30//!
31//! Use the same crate version in both locations. If you enable features, you must enable
32//! features in both locations. See the features section for more information.
33//!
34//! ```text
35//! [dependencies.imxrt-rt]
36//! version = # $VERSION
37//!
38//! [build-dependencies.imxrt-rt]
39//! version = # Same as $VERSION
40//! ```
41//!
42//! # Linker script
43//!
44//! **Link against `imxrt-link.x`**, which is automatically made available on the linker search path.
45//! Do not link against `link.x` from `cortex-m-rt`.
46//!
47//! You may change the name of the linker script by using the `RuntimeBuilder`.
48//!
49//! # Host configuration
50//!
51//! In your project, create a `build.rs` script that configures the runtime. The simplest `build.rs`
52//! looks like this:
53//!
54//! ```no_run
55//! use imxrt_rt::{Family, RuntimeBuilder};
56//!
57//! /// CHANGE ME depending on your board's flash size.
58//! const FLASH_SIZE: usize = 16 * 1024 * 1024; // 16 MiB.
59//! /// CHANGE ME depending on your board's chip.
60//! const FAMILY: Family = Family::Imxrt1060;
61//!
62//! fn main() {
63//! RuntimeBuilder::from_flexspi(FAMILY, FLASH_SIZE)
64//! .build()
65//! .unwrap();
66//! }
67//! ```
68//!
69//! This script works for any i.MX RT 1060-based system that has 16 MiB of external flash.
70//! Change the flash size and chip family based on your hardware. It uses the default configuration,
71//! which tries to give a reasonable memory layout for all processors.
72//! To understand the default configuration, see the [`RuntimeBuilder`] documentation.
73//!
74//! A more advanced runtime configuration looks like this:
75//!
76//! ```no_run
77//! # use imxrt_rt::{Family, RuntimeBuilder};
78//! use imxrt_rt::{FlexRamBanks, Memory};
79//! # const FLASH_SIZE: usize = 16 * 1024 * 1024; // 16 MiB.
80//! # const FAMILY: Family = Family::Imxrt1060;
81//!
82//! fn main() {
83//! RuntimeBuilder::from_flexspi(FAMILY, FLASH_SIZE)
84//! .flexram_banks(FlexRamBanks {
85//! ocram: 0,
86//! dtcm: FAMILY.flexram_bank_count() / 2 + 2,
87//! itcm: FAMILY.flexram_bank_count() / 2 - 2,
88//! })
89//! .text(Memory::Itcm)
90//! .vectors(Memory::Itcm)
91//! .rodata(Memory::Dtcm)
92//! .data(Memory::Dtcm)
93//! .bss(Memory::Dtcm)
94//! .uninit(Memory::Dtcm)
95//! .stack(Memory::Dtcm)
96//! .stack_size(4 * 1024)
97//! .heap(Memory::Dtcm)
98//! .heap_size(512)
99//! .build()
100//! .unwrap();
101//! }
102//! ```
103//!
104//! This configuration maximizes the TCM allocation by removing OCRAM blocks. It takes two
105//! banks from ITCM, and gives them to DTCM. It ensures that all sections are allocated to
106//! DTCM instead of OCRAM. It reduces the stack size, and reserves space for a small heap.
107//!
108//! No matter the configuration, the runtime ensures that all contents are copied from flash
109//! into their respective locations before `main()` is called.
110//!
111//! # Target integration
112//!
113//! If your runtime uses flash, link against a FlexSPI configuration block (FCB) crate. The
114//! crate is expected to export a `static FLEXSPI_CONFIGURATION_BLOCK` that describes how the
115//! FlexSPI peripheral interacts with your external flash chip. If an FCB crate doesn't exist
116//! for your hardware, you can use the [`imxrt-boot-gen` crate](https://docs.rs/imxrt-boot-gen/0.2.0/imxrt_boot_gen/)
117//! to define one. See the [`teensy4-fcb` crate](https://docs.rs/teensy4-fcb/0.3.0/teensy4_fcb/)
118//! for an example of an FCB crate that is compatible with this runtime.
119//!
120//! Finally, use `imxrt-rt` in your firmware just as you would use `cortex-m-rt`. See the [`cortex-m-rt`
121//! documentation][cmrt] for examples.
122//!
123//! # Feature flags
124//!
125//! `imxrt-rt` supports the features available in `cortex-m-rt` version 0.7.3. If you enable a feature,
126//! you must enable it in both the `[dependencies]` and `[build-dependencies]` section of your package
127//! manifest. For example, if the `cortex-m-rt` `"device"` feature were needed, then enable this crate's
128//! `"device"` feature in both places.
129//!
130//! ```text
131//! [dependencies.imxrt-rt]
132//! version = # $VERSION
133//! features = ["device"] # Add the feature here...
134//!
135//! [build-dependencies.imxrt-rt]
136//! version = # Same as $VERSION
137//! features = ["device"] # ... and here
138//! ```
139//!
140//! # Limitations
141//!
142//! The crate considers the assignment of FlexRAM memory banks to ITCM/DTCM/OCRAM
143//! an implementation detail. Additionally, the implementation does not care
144//! about the assignment of memory bank power domains. This seems to matter most on
145//! the 1050, which has the widest spread of bank-to-power domain assignment
146//! (according to AN12077).
147//!
148//! There is no support for ECC on 1160 or 1170. The runtime assumes that OCRAM and TCM ECC
149//! is disabled, and that the corresponding memory banks can be used for OCRAM.
150//!
151//! The runtime installs a `cortex-m-rt` `pre_init` function to configure the runtime.
152//! You cannot also define a `pre_init` function, and this crate does not support any
153//! other mechanism for running code before `main()`.
154//!
155//! The implementation assumes all flash is FlexSPI.
156//!
157//! ## Using `#[exception]` to register exception handlers
158//!
159//! This section only applies to Cortex-M exception handlers, not device-specific
160//! interrupt handlers. If you're not sure of the difference, consult the [`cortex-m-rt`][cmrt]
161//! documentation.
162//!
163//! Given the way this crate (ab)uses `cortex-m-rt`, and given the way the `cortex-m-rt`
164//! macros work, you may encounter issues using the `#[exception]` macro to register
165//! exception handlers. Fortunately, today's workaround is simple.
166//!
167//! Within the package that registers the exception handler, add a direct dependency
168//! on `cortex-m-rt` 0.7, similar to what's shown below.
169//!
170//! ```toml
171//! [dependencies]
172//! cortex-m-rt = "0.7"
173//! ```
174//!
175//! With this in place, your package should be able to use the `#[exception]` macro
176//! exported by `imxrt-rt`. See the `imxrt-rt` package examples for a demonstration.
177
178#![cfg_attr(all(target_arch = "arm", target_os = "none"), no_std)]
179
180cfg_if::cfg_if! {
181 if #[cfg(all(target_arch = "arm", target_os = "none"))] {
182 mod target;
183 pub use target::*;
184 } else {
185 mod host;
186 pub use host::*;
187 }
188}