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

#![cfg_attr(all(target_arch = "arm", target_os = "none"), no_std)]

cfg_if::cfg_if! {
    if #[cfg(all(target_arch = "arm", target_os = "none"))] {
        mod target;
        pub use target::*;
    } else {
        mod host;
        pub use host::*;
    }
}