Add embassy-imxrt

Adds initial support for MIMXRT600 series MCUs from NXP. Subsequent
PRs will add more drivers.
This commit is contained in:
Felipe Balbi 2025-04-03 08:47:25 -07:00
parent 0ec3e78c1b
commit aa9a16e569
21 changed files with 5041 additions and 0 deletions

2
ci.sh
View File

@ -53,6 +53,8 @@ cargo batch \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \
--- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt633s,defmt,unstable-pac \
--- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt685s,defmt,unstable-pac \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,gpiote,time,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \

13
docs/pages/imxrt.adoc Normal file
View File

@ -0,0 +1,13 @@
= Embassy iMXRT HAL
The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Embassy iMXRT HAL] is based on the following PACs (Peripheral Access Crate):
* link:https://github.com/OpenDevicePartnership/mimxrt685s-pac[mimxrt685s-pac]
* link:https://github.com/OpenDevicePartnership/mimxrt633s-pac[mimxrt633s-pac]
== Peripherals
The following peripherals have a HAL implementation at present
* GPIO

View File

@ -6,6 +6,7 @@ include::runtime.adoc[leveloffset = 2]
include::bootloader.adoc[leveloffset = 2]
include::time_keeping.adoc[leveloffset = 2]
include::hal.adoc[leveloffset = 2]
include::imxrt.adoc[leveloffset = 2]
include::nrf.adoc[leveloffset = 2]
include::stm32.adoc[leveloffset = 2]
include::sharing_peripherals.adoc[leveloffset = 2]

84
embassy-imxrt/Cargo.toml Normal file
View File

@ -0,0 +1,84 @@
[package]
name = "embassy-imxrt"
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller"
keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"]
categories = ["embedded", "hardware-support", "no-std", "asynchronous"]
repository = "https://github.com/embassy-rs/embassy"
documentation = "https://docs.embassy.dev/embassy-imxrt"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/"
features = ["defmt", "unstable-pac"]
flavors = [
{ regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" }
]
[package.metadata.docs.rs]
features = ["mimxrt685s", "defmt", "unstable-pac"]
rustdoc-args = ["--cfg", "docsrs"]
[features]
default = ["rt"]
## Cortex-M runtime (enabled by default)
rt = [
"mimxrt685s-pac?/rt",
"mimxrt633s-pac?/rt",
]
## Enable defmt
defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxrt685s-pac?/defmt", "mimxrt633s-pac?/defmt"]
## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable)
unstable-pac = []
# Features starting with `_` are for internal use only. They're not intended
# to be enabled by other crates, and are not covered by semver guarantees.
_mimxrt685s = []
_mimxrt633s = ["_espi"]
# Peripherals
_espi = []
#! ### Chip selection features
## MIMXRT685S
mimxrt685s = ["mimxrt685s-pac", "_mimxrt685s"]
## MIMXRT633S
mimxrt633s = ["mimxrt633s-pac", "_mimxrt633s"]
[dependencies]
embassy-sync = { version = "0.6.2", path = "../embassy-sync" }
embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false }
embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
defmt = { version = "1.0", optional = true }
log = { version = "0.4.14", optional = true }
nb = "1.0.0"
cfg-if = "1.0.0"
cortex-m-rt = ">=0.7.3,<0.8"
cortex-m = "0.7.6"
critical-section = "1.1"
embedded-io = { version = "0.6.1" }
embedded-io-async = { version = "0.6.1" }
rand_core = "0.6.4"
fixed = "1.23.1"
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
"unproven",
] }
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
embedded-hal-async = { version = "1.0" }
embedded-hal-nb = { version = "1.0" }
document-features = "0.2.7"
paste = "1.0"
# PACs
mimxrt685s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] }
mimxrt633s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] }

59
embassy-imxrt/README.md Normal file
View File

@ -0,0 +1,59 @@
# Embassy iMXRT HAL
## Introduction
HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so
raw register manipulation is not needed.
The Embassy iMXRT HAL targets the NXP iMXRT Family of MCUs. The HAL implements
both blocking and async APIs for many peripherals. The benefit of using the
async APIs is that the HAL takes care of waiting for peripherals to complete
operations in low power mode and handling of interrupts, so that applications
can focus on business logic.
NOTE: The Embassy HALs can be used both for non-async and async operations. For
async, you can choose which runtime you want to use.
For a complete list of available peripherals and features, see the
[embassy-imxrt documentation](https://docs.embassy.dev/embassy-imxrt).
## Hardware support
The `embassy-imxrt` HAL currently supports two main variants of the iMXRT
family:
* MIMXRT685S
([examples](https://github.com/OpenDevicePartnership/embassy-imxrt/tree/main/examples/rt685s-evk))
* MIMXRT633s
([examples](https://github.com/OpenDevicePartnership/embassy-imxrt/tree/main/examples/rt633))
Several peripherals are supported and tested on both supported chip variants. To
check what's available, make sure to the MCU you're targetting in the top menu
in the [documentation](https://docs.embassy.dev/embassy-imxrt).
## TrustZone support
TrustZone support is yet to be implemented.
## Time driver
If the `time-driver` feature is enabled, the HAL uses the RTC peripheral as a
global time driver for [embassy-time](https://crates.io/crates/embassy-time),
with a tick rate of 32768 Hz.
## Embedded-hal
The `embassy-imxrt` HAL implements the traits from
[embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and
[embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as
[embedded-io](https://crates.io/crates/embedded-io) and
[embedded-io-async](https://crates.io/crates/embedded-io-async).
## Interoperability
This crate can run on any executor.
Optionally, some features requiring
[`embassy-time`](https://crates.io/crates/embassy-time) can be activated with
the `time` feature. If you enable it, you must link an `embassy-time` driver in
your project.

View File

@ -0,0 +1,389 @@
pub use mimxrt633s_pac as pac;
#[allow(clippy::missing_safety_doc)]
pub mod interrupts {
embassy_hal_internal::interrupt_mod!(
ACMP,
ADC0,
CASPER,
CTIMER0,
CTIMER1,
CTIMER2,
CTIMER3,
CTIMER4,
DMA0,
DMA1,
DMIC0,
ESPI,
FLEXCOMM0,
FLEXCOMM1,
FLEXCOMM14,
FLEXCOMM15,
FLEXCOMM2,
FLEXCOMM3,
FLEXCOMM4,
FLEXCOMM5,
FLEXCOMM6,
FLEXCOMM7,
FLEXSPI,
GPIO_INTA,
GPIO_INTB,
HASHCRYPT,
HWVAD0,
HYPERVISOR,
I3C0,
MRT0,
MU_A,
OS_EVENT,
PIN_INT0,
PIN_INT1,
PIN_INT2,
PIN_INT3,
PIN_INT4,
PIN_INT5,
PIN_INT6,
PIN_INT7,
PMC_PMIC,
POWERQUAD,
PUF,
RNG,
RTC,
SCT0,
SECUREVIOLATION,
SGPIO_INTA,
SGPIO_INTB,
USB,
USBPHY_DCD,
USB_WAKEUP,
USDHC0,
USDHC1,
UTICK0,
WDT0,
WDT1,
);
}
embassy_hal_internal::peripherals!(
ACMP,
ADC0,
CASPER,
CRC,
CTIMER0_COUNT_CHANNEL0,
CTIMER0_COUNT_CHANNEL1,
CTIMER0_COUNT_CHANNEL2,
CTIMER0_COUNT_CHANNEL3,
CTIMER0_CAPTURE_CHANNEL0,
CTIMER0_CAPTURE_CHANNEL1,
CTIMER0_CAPTURE_CHANNEL2,
CTIMER0_CAPTURE_CHANNEL3,
CTIMER1_COUNT_CHANNEL0,
CTIMER1_COUNT_CHANNEL1,
CTIMER1_COUNT_CHANNEL2,
CTIMER1_COUNT_CHANNEL3,
CTIMER1_CAPTURE_CHANNEL0,
CTIMER1_CAPTURE_CHANNEL1,
CTIMER1_CAPTURE_CHANNEL2,
CTIMER1_CAPTURE_CHANNEL3,
CTIMER2_COUNT_CHANNEL0,
CTIMER2_COUNT_CHANNEL1,
CTIMER2_COUNT_CHANNEL2,
CTIMER2_COUNT_CHANNEL3,
CTIMER2_CAPTURE_CHANNEL0,
CTIMER2_CAPTURE_CHANNEL1,
CTIMER2_CAPTURE_CHANNEL2,
CTIMER2_CAPTURE_CHANNEL3,
CTIMER3_COUNT_CHANNEL0,
CTIMER3_COUNT_CHANNEL1,
CTIMER3_COUNT_CHANNEL2,
CTIMER3_COUNT_CHANNEL3,
CTIMER3_CAPTURE_CHANNEL0,
CTIMER3_CAPTURE_CHANNEL1,
CTIMER3_CAPTURE_CHANNEL2,
CTIMER3_CAPTURE_CHANNEL3,
CTIMER4_COUNT_CHANNEL0,
CTIMER4_COUNT_CHANNEL1,
CTIMER4_COUNT_CHANNEL2,
CTIMER4_COUNT_CHANNEL3,
CTIMER4_CAPTURE_CHANNEL0,
CTIMER4_CAPTURE_CHANNEL1,
CTIMER4_CAPTURE_CHANNEL2,
CTIMER4_CAPTURE_CHANNEL3,
DMA0,
DMA0_CH0,
DMA0_CH1,
DMA0_CH2,
DMA0_CH3,
DMA0_CH4,
DMA0_CH5,
DMA0_CH6,
DMA0_CH7,
DMA0_CH8,
DMA0_CH9,
DMA0_CH10,
DMA0_CH11,
DMA0_CH12,
DMA0_CH13,
DMA0_CH14,
DMA0_CH15,
DMA0_CH16,
DMA0_CH17,
DMA0_CH18,
DMA0_CH19,
DMA0_CH20,
DMA0_CH21,
DMA0_CH22,
DMA0_CH23,
DMA0_CH24,
DMA0_CH25,
DMA0_CH26,
DMA0_CH27,
DMA0_CH28,
DMA0_CH29,
DMA0_CH30,
DMA0_CH31,
DMA0_CH32,
DMA1,
DMA1_CH0,
DMA1_CH1,
DMA1_CH2,
DMA1_CH3,
DMA1_CH4,
DMA1_CH5,
DMA1_CH6,
DMA1_CH7,
DMA1_CH8,
DMA1_CH9,
DMA1_CH10,
DMA1_CH11,
DMA1_CH12,
DMA1_CH13,
DMA1_CH14,
DMA1_CH15,
DMA1_CH16,
DMA1_CH17,
DMA1_CH18,
DMA1_CH19,
DMA1_CH20,
DMA1_CH21,
DMA1_CH22,
DMA1_CH23,
DMA1_CH24,
DMA1_CH25,
DMA1_CH26,
DMA1_CH27,
DMA1_CH28,
DMA1_CH29,
DMA1_CH30,
DMA1_CH31,
DMA1_CH32,
DMIC0,
DSPWAKE,
ESPI,
FLEXCOMM0,
FLEXCOMM1,
FLEXCOMM14,
FLEXCOMM15,
FLEXCOMM2,
FLEXCOMM3,
FLEXCOMM4,
FLEXCOMM5,
FLEXCOMM6,
FLEXCOMM7,
FLEXSPI,
FREQME,
GPIO_INTA,
GPIO_INTB,
HASHCRYPT,
HSGPIO0,
HSGPIO1,
HSGPIO2,
HSGPIO3,
HSGPIO4,
HSGPIO5,
HSGPIO6,
HSGPIO7,
HWVAD0,
HYPERVISOR,
I3C0,
MRT0,
MU_A,
OS_EVENT,
PIN_INT0,
PIN_INT1,
PIN_INT2,
PIN_INT3,
PIN_INT4,
PIN_INT5,
PIN_INT6,
PIN_INT7,
PIO0_0,
PIO0_1,
PIO0_10,
PIO0_11,
PIO0_12,
PIO0_13,
PIO0_14,
PIO0_15,
PIO0_16,
PIO0_17,
PIO0_18,
PIO0_19,
PIO0_2,
PIO0_20,
PIO0_21,
PIO0_22,
PIO0_23,
PIO0_24,
PIO0_25,
PIO0_26,
PIO0_27,
PIO0_28,
PIO0_29,
PIO0_3,
PIO0_30,
PIO0_31,
PIO0_4,
PIO0_5,
PIO0_6,
PIO0_7,
PIO0_8,
PIO0_9,
PIO1_0,
PIO1_1,
PIO1_10,
PIO1_11,
PIO1_12,
PIO1_13,
PIO1_14,
PIO1_15,
PIO1_16,
PIO1_17,
PIO1_18,
PIO1_19,
PIO1_2,
PIO1_20,
PIO1_21,
PIO1_22,
PIO1_23,
PIO1_24,
PIO1_25,
PIO1_26,
PIO1_27,
PIO1_28,
PIO1_29,
PIO1_3,
PIO1_30,
PIO1_31,
PIO1_4,
PIO1_5,
PIO1_6,
PIO1_7,
PIO1_8,
PIO1_9,
PIO2_0,
PIO2_1,
PIO2_10,
PIO2_11,
PIO2_12,
PIO2_13,
PIO2_14,
PIO2_15,
PIO2_16,
PIO2_17,
PIO2_18,
PIO2_19,
PIO2_2,
PIO2_20,
PIO2_21,
PIO2_22,
PIO2_23,
PIO2_24,
PIO2_25,
PIO2_26,
PIO2_27,
PIO2_28,
PIO2_29,
PIO2_3,
PIO2_30,
PIO2_31,
PIO2_4,
PIO2_5,
PIO2_6,
PIO2_7,
PIO2_8,
PIO2_9,
PIO3_0,
PIO3_1,
PIO3_10,
PIO3_11,
PIO3_12,
PIO3_13,
PIO3_14,
PIO3_15,
PIO3_16,
PIO3_17,
PIO3_18,
PIO3_19,
PIO3_2,
PIO3_20,
PIO3_21,
PIO3_22,
PIO3_23,
PIO3_24,
PIO3_25,
PIO3_26,
PIO3_27,
PIO3_28,
PIO3_29,
PIO3_3,
PIO3_30,
PIO3_31,
PIO3_4,
PIO3_5,
PIO3_6,
PIO3_7,
PIO3_8,
PIO3_9,
PIO4_0,
PIO4_1,
PIO4_10,
PIO4_2,
PIO4_3,
PIO4_4,
PIO4_5,
PIO4_6,
PIO4_7,
PIO4_8,
PIO4_9,
PIO7_24,
PIO7_25,
PIO7_26,
PIO7_27,
PIO7_28,
PIO7_29,
PIO7_30,
PIO7_31,
PIOFC15_SCL,
PIOFC15_SDA,
PMC_PMIC,
PIMCTL,
POWERQUAD,
PUF,
RNG,
RTC,
SCT0,
SECGPIO,
SECUREVIOLATION,
SEMA42,
SGPIO_INTA,
SGPIO_INTB,
USBHSD,
USBHSH,
USBPHY,
USB_WAKEUP,
USDHC0,
USDHC1,
UTICK0,
WDT0,
WDT1,
);

View File

@ -0,0 +1,388 @@
pub use mimxrt685s_pac as pac;
#[allow(clippy::missing_safety_doc)]
pub mod interrupts {
embassy_hal_internal::interrupt_mod!(
ACMP,
ADC0,
CASPER,
CTIMER0,
CTIMER1,
CTIMER2,
CTIMER3,
CTIMER4,
DMA0,
DMA1,
DMIC0,
DSPWAKE,
FLEXCOMM0,
FLEXCOMM1,
FLEXCOMM14,
FLEXCOMM15,
FLEXCOMM2,
FLEXCOMM3,
FLEXCOMM4,
FLEXCOMM5,
FLEXCOMM6,
FLEXCOMM7,
FLEXSPI,
GPIO_INTA,
GPIO_INTB,
HASHCRYPT,
HWVAD0,
HYPERVISOR,
I3C0,
MRT0,
MU_A,
OS_EVENT,
PIN_INT0,
PIN_INT1,
PIN_INT2,
PIN_INT3,
PIN_INT4,
PIN_INT5,
PIN_INT6,
PIN_INT7,
PMC_PMIC,
POWERQUAD,
PUF,
RNG,
RTC,
SCT0,
SECUREVIOLATION,
SGPIO_INTA,
SGPIO_INTB,
USB,
USBPHY_DCD,
USB_WAKEUP,
USDHC0,
USDHC1,
UTICK0,
WDT0,
WDT1,
);
}
embassy_hal_internal::peripherals!(
ACMP,
ADC0,
CASPER,
CRC,
CTIMER0_COUNT_CHANNEL0,
CTIMER0_COUNT_CHANNEL1,
CTIMER0_COUNT_CHANNEL2,
CTIMER0_COUNT_CHANNEL3,
CTIMER0_CAPTURE_CHANNEL0,
CTIMER0_CAPTURE_CHANNEL1,
CTIMER0_CAPTURE_CHANNEL2,
CTIMER0_CAPTURE_CHANNEL3,
CTIMER1_COUNT_CHANNEL0,
CTIMER1_COUNT_CHANNEL1,
CTIMER1_COUNT_CHANNEL2,
CTIMER1_COUNT_CHANNEL3,
CTIMER1_CAPTURE_CHANNEL0,
CTIMER1_CAPTURE_CHANNEL1,
CTIMER1_CAPTURE_CHANNEL2,
CTIMER1_CAPTURE_CHANNEL3,
CTIMER2_COUNT_CHANNEL0,
CTIMER2_COUNT_CHANNEL1,
CTIMER2_COUNT_CHANNEL2,
CTIMER2_COUNT_CHANNEL3,
CTIMER2_CAPTURE_CHANNEL0,
CTIMER2_CAPTURE_CHANNEL1,
CTIMER2_CAPTURE_CHANNEL2,
CTIMER2_CAPTURE_CHANNEL3,
CTIMER3_COUNT_CHANNEL0,
CTIMER3_COUNT_CHANNEL1,
CTIMER3_COUNT_CHANNEL2,
CTIMER3_COUNT_CHANNEL3,
CTIMER3_CAPTURE_CHANNEL0,
CTIMER3_CAPTURE_CHANNEL1,
CTIMER3_CAPTURE_CHANNEL2,
CTIMER3_CAPTURE_CHANNEL3,
CTIMER4_COUNT_CHANNEL0,
CTIMER4_COUNT_CHANNEL1,
CTIMER4_COUNT_CHANNEL2,
CTIMER4_COUNT_CHANNEL3,
CTIMER4_CAPTURE_CHANNEL0,
CTIMER4_CAPTURE_CHANNEL1,
CTIMER4_CAPTURE_CHANNEL2,
CTIMER4_CAPTURE_CHANNEL3,
DMA0,
DMA0_CH0,
DMA0_CH1,
DMA0_CH2,
DMA0_CH3,
DMA0_CH4,
DMA0_CH5,
DMA0_CH6,
DMA0_CH7,
DMA0_CH8,
DMA0_CH9,
DMA0_CH10,
DMA0_CH11,
DMA0_CH12,
DMA0_CH13,
DMA0_CH14,
DMA0_CH15,
DMA0_CH16,
DMA0_CH17,
DMA0_CH18,
DMA0_CH19,
DMA0_CH20,
DMA0_CH21,
DMA0_CH22,
DMA0_CH23,
DMA0_CH24,
DMA0_CH25,
DMA0_CH26,
DMA0_CH27,
DMA0_CH28,
DMA0_CH29,
DMA0_CH30,
DMA0_CH31,
DMA0_CH32,
DMA1,
DMA1_CH0,
DMA1_CH1,
DMA1_CH2,
DMA1_CH3,
DMA1_CH4,
DMA1_CH5,
DMA1_CH6,
DMA1_CH7,
DMA1_CH8,
DMA1_CH9,
DMA1_CH10,
DMA1_CH11,
DMA1_CH12,
DMA1_CH13,
DMA1_CH14,
DMA1_CH15,
DMA1_CH16,
DMA1_CH17,
DMA1_CH18,
DMA1_CH19,
DMA1_CH20,
DMA1_CH21,
DMA1_CH22,
DMA1_CH23,
DMA1_CH24,
DMA1_CH25,
DMA1_CH26,
DMA1_CH27,
DMA1_CH28,
DMA1_CH29,
DMA1_CH30,
DMA1_CH31,
DMA1_CH32,
DMIC0,
DSPWAKE,
FLEXCOMM0,
FLEXCOMM1,
FLEXCOMM14,
FLEXCOMM15,
FLEXCOMM2,
FLEXCOMM3,
FLEXCOMM4,
FLEXCOMM5,
FLEXCOMM6,
FLEXCOMM7,
FLEXSPI,
FREQME,
GPIO_INTA,
GPIO_INTB,
HASHCRYPT,
HSGPIO0,
HSGPIO1,
HSGPIO2,
HSGPIO3,
HSGPIO4,
HSGPIO5,
HSGPIO6,
HSGPIO7,
HWVAD0,
HYPERVISOR,
I3C0,
MRT0,
MU_A,
OS_EVENT,
PIN_INT0,
PIN_INT1,
PIN_INT2,
PIN_INT3,
PIN_INT4,
PIN_INT5,
PIN_INT6,
PIN_INT7,
PIO0_0,
PIO0_1,
PIO0_10,
PIO0_11,
PIO0_12,
PIO0_13,
PIO0_14,
PIO0_15,
PIO0_16,
PIO0_17,
PIO0_18,
PIO0_19,
PIO0_2,
PIO0_20,
PIO0_21,
PIO0_22,
PIO0_23,
PIO0_24,
PIO0_25,
PIO0_26,
PIO0_27,
PIO0_28,
PIO0_29,
PIO0_3,
PIO0_30,
PIO0_31,
PIO0_4,
PIO0_5,
PIO0_6,
PIO0_7,
PIO0_8,
PIO0_9,
PIO1_0,
PIO1_1,
PIO1_10,
PIO1_11,
PIO1_12,
PIO1_13,
PIO1_14,
PIO1_15,
PIO1_16,
PIO1_17,
PIO1_18,
PIO1_19,
PIO1_2,
PIO1_20,
PIO1_21,
PIO1_22,
PIO1_23,
PIO1_24,
PIO1_25,
PIO1_26,
PIO1_27,
PIO1_28,
PIO1_29,
PIO1_3,
PIO1_30,
PIO1_31,
PIO1_4,
PIO1_5,
PIO1_6,
PIO1_7,
PIO1_8,
PIO1_9,
PIO2_0,
PIO2_1,
PIO2_10,
PIO2_11,
PIO2_12,
PIO2_13,
PIO2_14,
PIO2_15,
PIO2_16,
PIO2_17,
PIO2_18,
PIO2_19,
PIO2_2,
PIO2_20,
PIO2_21,
PIO2_22,
PIO2_23,
PIO2_24,
PIO2_25,
PIO2_26,
PIO2_27,
PIO2_28,
PIO2_29,
PIO2_3,
PIO2_30,
PIO2_31,
PIO2_4,
PIO2_5,
PIO2_6,
PIO2_7,
PIO2_8,
PIO2_9,
PIO3_0,
PIO3_1,
PIO3_10,
PIO3_11,
PIO3_12,
PIO3_13,
PIO3_14,
PIO3_15,
PIO3_16,
PIO3_17,
PIO3_18,
PIO3_19,
PIO3_2,
PIO3_20,
PIO3_21,
PIO3_22,
PIO3_23,
PIO3_24,
PIO3_25,
PIO3_26,
PIO3_27,
PIO3_28,
PIO3_29,
PIO3_3,
PIO3_30,
PIO3_31,
PIO3_4,
PIO3_5,
PIO3_6,
PIO3_7,
PIO3_8,
PIO3_9,
PIO4_0,
PIO4_1,
PIO4_10,
PIO4_2,
PIO4_3,
PIO4_4,
PIO4_5,
PIO4_6,
PIO4_7,
PIO4_8,
PIO4_9,
PIO7_24,
PIO7_25,
PIO7_26,
PIO7_27,
PIO7_28,
PIO7_29,
PIO7_30,
PIO7_31,
PIOFC15_SCL,
PIOFC15_SDA,
PMC_PMIC,
PIMCTL,
POWERQUAD,
PUF,
RNG,
RTC,
SCT0,
SECGPIO,
SECUREVIOLATION,
SEMA42,
SGPIO_INTA,
SGPIO_INTB,
USBHSD,
USBHSH,
USBPHY,
USB_WAKEUP,
USDHC0,
USDHC1,
UTICK0,
WDT0,
WDT1,
);

1687
embassy-imxrt/src/clocks.rs Normal file

File diff suppressed because it is too large Load Diff

257
embassy-imxrt/src/fmt.rs Normal file
View File

@ -0,0 +1,257 @@
#![macro_use]
#![allow(unused)]
use core::fmt::{Debug, Display, LowerHex};
#[collapse_debuginfo(yes)]
macro_rules! assert {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::assert!($($x)*);
#[cfg(feature = "defmt")]
::defmt::assert!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! assert_eq {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::assert_eq!($($x)*);
#[cfg(feature = "defmt")]
::defmt::assert_eq!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! assert_ne {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::assert_ne!($($x)*);
#[cfg(feature = "defmt")]
::defmt::assert_ne!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! debug_assert {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::debug_assert!($($x)*);
#[cfg(feature = "defmt")]
::defmt::debug_assert!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! debug_assert_eq {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::debug_assert_eq!($($x)*);
#[cfg(feature = "defmt")]
::defmt::debug_assert_eq!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! debug_assert_ne {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::debug_assert_ne!($($x)*);
#[cfg(feature = "defmt")]
::defmt::debug_assert_ne!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! todo {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::todo!($($x)*);
#[cfg(feature = "defmt")]
::defmt::todo!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! unreachable {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::unreachable!($($x)*);
#[cfg(feature = "defmt")]
::defmt::unreachable!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! panic {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::panic!($($x)*);
#[cfg(feature = "defmt")]
::defmt::panic!($($x)*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! trace {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "defmt")]
::defmt::trace!($s $(, $x)*);
#[cfg(not(feature = "defmt"))]
let _ = ($( & $x ),*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! debug {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "defmt")]
::defmt::debug!($s $(, $x)*);
#[cfg(not(feature = "defmt"))]
let _ = ($( & $x ),*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! info {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "defmt")]
::defmt::info!($s $(, $x)*);
#[cfg(not(feature = "defmt"))]
let _ = ($( & $x ),*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! warn {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "defmt")]
::defmt::warn!($s $(, $x)*);
#[cfg(not(feature = "defmt"))]
let _ = ($( & $x ),*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! error {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "defmt")]
::defmt::error!($s $(, $x)*);
#[cfg(not(feature = "defmt"))]
let _ = ($( & $x ),*);
}
};
}
#[cfg(feature = "defmt")]
#[collapse_debuginfo(yes)]
macro_rules! unwrap {
($($x:tt)*) => {
::defmt::unwrap!($($x)*)
};
}
#[cfg(not(feature = "defmt"))]
#[collapse_debuginfo(yes)]
macro_rules! unwrap {
($arg:expr) => {
match $crate::fmt::Try::into_result($arg) {
::core::result::Result::Ok(t) => t,
::core::result::Result::Err(e) => {
::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
}
}
};
($arg:expr, $($msg:expr),+ $(,)? ) => {
match $crate::fmt::Try::into_result($arg) {
::core::result::Result::Ok(t) => t,
::core::result::Result::Err(e) => {
::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
}
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct NoneError;
pub trait Try {
type Ok;
type Error;
fn into_result(self) -> Result<Self::Ok, Self::Error>;
}
impl<T> Try for Option<T> {
type Ok = T;
type Error = NoneError;
#[inline]
fn into_result(self) -> Result<T, NoneError> {
self.ok_or(NoneError)
}
}
impl<T, E> Try for Result<T, E> {
type Ok = T;
type Error = E;
#[inline]
fn into_result(self) -> Self {
self
}
}
pub(crate) struct Bytes<'a>(pub &'a [u8]);
impl Debug for Bytes<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
impl Display for Bytes<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
impl LowerHex for Bytes<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for Bytes<'_> {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(fmt, "{:02x}", self.0)
}
}

1060
embassy-imxrt/src/gpio.rs Normal file

File diff suppressed because it is too large Load Diff

717
embassy-imxrt/src/iopctl.rs Normal file
View File

@ -0,0 +1,717 @@
//! IO Pad Controller (IOPCTL)
//!
//! Also known as IO Pin Configuration (IOCON)
use crate::pac::{iopctl, Iopctl};
// A generic pin of any type.
//
// The actual pin type used here is arbitrary,
// as all PioM_N types provide the same methods.
//
// Merely need some pin type to cast a raw pointer
// to in order to access the provided methods.
#[allow(non_camel_case_types)]
type PioM_N = iopctl::Pio0_0;
/// Pin function number.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Function {
/// Function 0
F0,
/// Function 1
F1,
/// Function 2
F2,
/// Function 3
F3,
/// Function 4
F4,
/// Function 5
F5,
/// Function 6
F6,
/// Function 7
F7,
/// Function 8
F8,
}
/// Internal pull-up/down resistors on a pin.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Pull {
/// No pull-up or pull-down resistor selected
None,
/// Pull-up resistor
Up,
/// Pull-down resistor
Down,
}
/// Pin slew rate.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SlewRate {
/// Standard slew rate
Standard,
/// Slow slew rate
Slow,
}
/// Output drive strength of a pin.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DriveStrength {
/// Normal
Normal,
/// Full
Full,
}
/// Output drive mode of a pin.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DriveMode {
/// Push-Pull
PushPull,
/// Pseudo Open-Drain
OpenDrain,
}
/// Input inverter of a pin.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Inverter {
/// No inverter
Disabled,
/// Enable input inverter on the input port. A low signal will be
/// seen as a high signal by the pin.
Enabled,
}
trait SealedPin {}
trait ToAnyPin: SealedPin {
#[inline]
fn to_raw(port: u8, pin: u8) -> AnyPin {
// SAFETY: This is safe since this is only called from within the module,
// where the port and pin numbers have been verified to be correct.
unsafe { AnyPin::steal(port, pin) }
}
}
trait ToFC15Pin: SealedPin {
#[inline]
fn to_raw(pin: u8) -> FC15Pin {
// SAFETY: This is safe since this is only called from within the module,
// where the port and pin numbers have been verified to be correct.
unsafe { FC15Pin::steal(pin) }
}
}
/// A pin that can be configured via iopctl.
#[allow(private_bounds)]
pub trait IopctlPin: SealedPin {
/// Sets the function number of a pin.
///
/// This number corresponds to a specific function that the pin supports.
///
/// Typically, function 0 corresponds to GPIO while other numbers correspond to a special function.
///
/// See Section 7.5.3 in reference manual for list of pins and their supported functions.
fn set_function(&self, function: Function) -> &Self;
/// Enables either a pull-up or pull-down resistor on a pin.
///
/// Setting this to [`Pull::None`] will disable the resistor.
fn set_pull(&self, pull: Pull) -> &Self;
/// Enables the input buffer of a pin.
///
/// This must be enabled for any pin acting as an input,
/// and some peripheral pins acting as output may need this enabled as well.
///
/// If there is any doubt, it is best to enable the input buffer.
///
/// See Section 7.4.2.3 of reference manual.
fn enable_input_buffer(&self) -> &Self;
/// Disables the input buffer of a pin.
fn disable_input_buffer(&self) -> &Self;
/// Sets the slew rate of a pin.
///
/// This controls the speed at which a pin can toggle,
/// which is voltage and load dependent.
fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self;
/// Sets the output drive strength of a pin.
///
/// A drive strength of [`DriveStrength::Full`] has twice the
/// high and low drive capability of the [`DriveStrength::Normal`] setting.
fn set_drive_strength(&self, strength: DriveStrength) -> &Self;
/// Enables the analog multiplexer of a pin.
///
/// This must be called to allow analog functionalities of a pin.
///
/// To protect the analog input, [`IopctlPin::set_function`] should be
/// called with [`Function::F0`] to disable digital functions.
///
/// Additionally, [`IopctlPin::disable_input_buffer`] and [`IopctlPin::set_pull`]
/// with [`Pull::None`] should be called.
fn enable_analog_multiplex(&self) -> &Self;
/// Disables the analog multiplexer of a pin.
fn disable_analog_multiplex(&self) -> &Self;
/// Sets the ouput drive mode of a pin.
///
/// A pin configured as [`DriveMode::OpenDrain`] actually operates in
/// a "pseudo" open-drain mode which is somewhat different than true open-drain.
///
/// See Section 7.4.2.7 of reference manual.
fn set_drive_mode(&self, mode: DriveMode) -> &Self;
/// Sets the input inverter of an input pin.
///
/// Setting this to [`Inverter::Enabled`] will invert
/// the input signal.
fn set_input_inverter(&self, inverter: Inverter) -> &Self;
/// Returns a pin to its reset state.
fn reset(&self) -> &Self;
}
/// Represents a pin peripheral created at run-time from given port and pin numbers.
pub struct AnyPin {
pin_port: u8,
reg: &'static PioM_N,
}
impl AnyPin {
/// Creates a pin from raw port and pin numbers which can then be configured.
///
/// This should ONLY be called when there is no other choice
/// (e.g. from a type-erased GPIO pin).
///
/// Otherwise, pin peripherals should be configured directly.
///
/// # Safety
///
/// The caller MUST ensure valid port and pin numbers are provided,
/// and that multiple instances of [`AnyPin`] with the same port
/// and pin combination are not being used simultaneously.
///
/// Failure to uphold these requirements will result in undefined behavior.
///
/// See Table 297 in reference manual for a list of valid
/// pin and port number combinations.
#[must_use]
pub unsafe fn steal(port: u8, pin: u8) -> Self {
// Calculates the offset from the beginning of the IOPCTL register block
// address to the register address representing the pin.
//
// See Table 297 in reference manual for how this offset is calculated.
let offset = ((port as usize) << 7) + ((pin as usize) << 2);
// SAFETY: This is safe assuming the caller of this function satisfies the safety requirements above.
let reg = unsafe { &*Iopctl::ptr().byte_offset(offset as isize).cast() };
Self {
pin_port: port * 32 + pin,
reg,
}
}
/// Returns the pin's port and pin combination.
#[must_use]
pub fn pin_port(&self) -> usize {
self.pin_port as usize
}
}
/// Represents a FC15 pin peripheral created at run-time from given pin number.
pub struct FC15Pin {
reg: &'static PioM_N,
}
impl FC15Pin {
/// Creates an FC15 pin from raw pin number which can then be configured.
///
/// This should ONLY be called when there is no other choice
/// (e.g. from a type-erased GPIO pin).
///
/// Otherwise, pin peripherals should be configured directly.
///
/// # Safety
///
/// The caller MUST ensure valid port and pin numbers are provided,
/// and that multiple instances of [`AnyPin`] with the same port
/// and pin combination are not being used simultaneously.
///
/// Failure to uphold these requirements will result in undefined behavior.
///
/// See Table 297 in reference manual for a list of valid
/// pin and port number combinations.
#[must_use]
pub unsafe fn steal(pin: u8) -> Self {
// Table 297: FC15_I2C_SCL offset = 0x400, FC15_I2C_SCL offset = 0x404
let iopctl = unsafe { crate::pac::Iopctl::steal() };
let reg = if pin == 0 {
&*iopctl.fc15_i2c_scl().as_ptr().cast()
} else {
&*iopctl.fc15_i2c_sda().as_ptr().cast()
};
Self { reg }
}
}
// This allows AnyPin/FC15Pin to be used in HAL constructors that require types
// which impl Peripheral. Used primarily by GPIO HAL to convert type-erased
// GPIO pins back into an Output or Input pin specifically.
embassy_hal_internal::impl_peripheral!(AnyPin);
impl SealedPin for AnyPin {}
embassy_hal_internal::impl_peripheral!(FC15Pin);
impl SealedPin for FC15Pin {}
macro_rules! impl_iopctlpin {
($pintype:ident) => {
impl IopctlPin for $pintype {
fn set_function(&self, function: Function) -> &Self {
critical_section::with(|_| match function {
Function::F0 => {
self.reg.modify(|_, w| w.fsel().function_0());
}
Function::F1 => {
self.reg.modify(|_, w| w.fsel().function_1());
}
Function::F2 => {
self.reg.modify(|_, w| w.fsel().function_2());
}
Function::F3 => {
self.reg.modify(|_, w| w.fsel().function_3());
}
Function::F4 => {
self.reg.modify(|_, w| w.fsel().function_4());
}
Function::F5 => {
self.reg.modify(|_, w| w.fsel().function_5());
}
Function::F6 => {
self.reg.modify(|_, w| w.fsel().function_6());
}
Function::F7 => {
self.reg.modify(|_, w| w.fsel().function_7());
}
Function::F8 => {
self.reg.modify(|_, w| w.fsel().function_8());
}
});
self
}
fn set_pull(&self, pull: Pull) -> &Self {
critical_section::with(|_| {
match pull {
Pull::None => {
self.reg.modify(|_, w| w.pupdena().disabled());
}
Pull::Up => {
self.reg.modify(|_, w| w.pupdena().enabled().pupdsel().pull_up());
}
Pull::Down => {
self.reg
.modify(|_, w| w.pupdena().enabled().pupdsel().pull_down());
}
}
self
})
}
fn enable_input_buffer(&self) -> &Self {
critical_section::with(|_| self.reg.modify(|_, w| w.ibena().enabled()));
self
}
fn disable_input_buffer(&self) -> &Self {
critical_section::with(|_| self.reg.modify(|_, w| w.ibena().disabled()));
self
}
fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self {
critical_section::with(|_| match slew_rate {
SlewRate::Standard => {
self.reg.modify(|_, w| w.slewrate().normal());
}
SlewRate::Slow => {
self.reg.modify(|_, w| w.slewrate().slow());
}
});
self
}
fn set_drive_strength(&self, strength: DriveStrength) -> &Self {
critical_section::with(|_| match strength {
DriveStrength::Normal => {
self.reg.modify(|_, w| w.fulldrive().normal_drive());
}
DriveStrength::Full => {
self.reg.modify(|_, w| w.fulldrive().full_drive());
}
});
self
}
fn enable_analog_multiplex(&self) -> &Self {
critical_section::with(|_| self.reg.modify(|_, w| w.amena().enabled()));
self
}
fn disable_analog_multiplex(&self) -> &Self {
critical_section::with(|_| self.reg.modify(|_, w| w.amena().disabled()));
self
}
fn set_drive_mode(&self, mode: DriveMode) -> &Self {
critical_section::with(|_| match mode {
DriveMode::PushPull => {
self.reg.modify(|_, w| w.odena().disabled());
}
DriveMode::OpenDrain => {
self.reg.modify(|_, w| w.odena().enabled());
}
});
self
}
fn set_input_inverter(&self, inverter: Inverter) -> &Self {
critical_section::with(|_| match inverter {
Inverter::Disabled => {
self.reg.modify(|_, w| w.iiena().disabled());
}
Inverter::Enabled => {
self.reg.modify(|_, w| w.iiena().enabled());
}
});
self
}
fn reset(&self) -> &Self {
self.reg.reset();
self
}
}
};
}
impl_iopctlpin!(AnyPin);
impl_iopctlpin!(FC15Pin);
macro_rules! impl_FC15pin {
($pin_periph:ident, $pin_no:expr) => {
impl SealedPin for crate::peripherals::$pin_periph {}
impl ToFC15Pin for crate::peripherals::$pin_periph {}
impl IopctlPin for crate::peripherals::$pin_periph {
#[inline]
fn set_function(&self, _function: Function) -> &Self {
//No function configuration for FC15 pin
self
}
#[inline]
fn set_pull(&self, pull: Pull) -> &Self {
Self::to_raw($pin_no).set_pull(pull);
self
}
#[inline]
fn enable_input_buffer(&self) -> &Self {
Self::to_raw($pin_no).enable_input_buffer();
self
}
#[inline]
fn disable_input_buffer(&self) -> &Self {
Self::to_raw($pin_no).disable_input_buffer();
self
}
#[inline]
fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self {
Self::to_raw($pin_no).set_slew_rate(slew_rate);
self
}
#[inline]
fn set_drive_strength(&self, strength: DriveStrength) -> &Self {
Self::to_raw($pin_no).set_drive_strength(strength);
self
}
#[inline]
fn enable_analog_multiplex(&self) -> &Self {
Self::to_raw($pin_no).enable_analog_multiplex();
self
}
#[inline]
fn disable_analog_multiplex(&self) -> &Self {
Self::to_raw($pin_no).disable_analog_multiplex();
self
}
#[inline]
fn set_drive_mode(&self, mode: DriveMode) -> &Self {
Self::to_raw($pin_no).set_drive_mode(mode);
self
}
#[inline]
fn set_input_inverter(&self, inverter: Inverter) -> &Self {
Self::to_raw($pin_no).set_input_inverter(inverter);
self
}
#[inline]
fn reset(&self) -> &Self {
Self::to_raw($pin_no).reset();
self
}
}
};
}
macro_rules! impl_pin {
($pin_periph:ident, $pin_port:expr, $pin_no:expr) => {
impl SealedPin for crate::peripherals::$pin_periph {}
impl ToAnyPin for crate::peripherals::$pin_periph {}
impl IopctlPin for crate::peripherals::$pin_periph {
#[inline]
fn set_function(&self, function: Function) -> &Self {
Self::to_raw($pin_port, $pin_no).set_function(function);
self
}
#[inline]
fn set_pull(&self, pull: Pull) -> &Self {
Self::to_raw($pin_port, $pin_no).set_pull(pull);
self
}
#[inline]
fn enable_input_buffer(&self) -> &Self {
Self::to_raw($pin_port, $pin_no).enable_input_buffer();
self
}
#[inline]
fn disable_input_buffer(&self) -> &Self {
Self::to_raw($pin_port, $pin_no).disable_input_buffer();
self
}
#[inline]
fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self {
Self::to_raw($pin_port, $pin_no).set_slew_rate(slew_rate);
self
}
#[inline]
fn set_drive_strength(&self, strength: DriveStrength) -> &Self {
Self::to_raw($pin_port, $pin_no).set_drive_strength(strength);
self
}
#[inline]
fn enable_analog_multiplex(&self) -> &Self {
Self::to_raw($pin_port, $pin_no).enable_analog_multiplex();
self
}
#[inline]
fn disable_analog_multiplex(&self) -> &Self {
Self::to_raw($pin_port, $pin_no).disable_analog_multiplex();
self
}
#[inline]
fn set_drive_mode(&self, mode: DriveMode) -> &Self {
Self::to_raw($pin_port, $pin_no).set_drive_mode(mode);
self
}
#[inline]
fn set_input_inverter(&self, inverter: Inverter) -> &Self {
Self::to_raw($pin_port, $pin_no).set_input_inverter(inverter);
self
}
#[inline]
fn reset(&self) -> &Self {
Self::to_raw($pin_port, $pin_no).reset();
self
}
}
};
}
impl_pin!(PIO0_0, 0, 0);
impl_pin!(PIO0_1, 0, 1);
impl_pin!(PIO0_2, 0, 2);
impl_pin!(PIO0_3, 0, 3);
impl_pin!(PIO0_4, 0, 4);
impl_pin!(PIO0_5, 0, 5);
impl_pin!(PIO0_6, 0, 6);
impl_pin!(PIO0_7, 0, 7);
impl_pin!(PIO0_8, 0, 8);
impl_pin!(PIO0_9, 0, 9);
impl_pin!(PIO0_10, 0, 10);
impl_pin!(PIO0_11, 0, 11);
impl_pin!(PIO0_12, 0, 12);
impl_pin!(PIO0_13, 0, 13);
impl_pin!(PIO0_14, 0, 14);
impl_pin!(PIO0_15, 0, 15);
impl_pin!(PIO0_16, 0, 16);
impl_pin!(PIO0_17, 0, 17);
impl_pin!(PIO0_18, 0, 18);
impl_pin!(PIO0_19, 0, 19);
impl_pin!(PIO0_20, 0, 20);
impl_pin!(PIO0_21, 0, 21);
impl_pin!(PIO0_22, 0, 22);
impl_pin!(PIO0_23, 0, 23);
impl_pin!(PIO0_24, 0, 24);
impl_pin!(PIO0_25, 0, 25);
impl_pin!(PIO0_26, 0, 26);
impl_pin!(PIO0_27, 0, 27);
impl_pin!(PIO0_28, 0, 28);
impl_pin!(PIO0_29, 0, 29);
impl_pin!(PIO0_30, 0, 30);
impl_pin!(PIO0_31, 0, 31);
impl_pin!(PIO1_0, 1, 0);
impl_pin!(PIO1_1, 1, 1);
impl_pin!(PIO1_2, 1, 2);
impl_pin!(PIO1_3, 1, 3);
impl_pin!(PIO1_4, 1, 4);
impl_pin!(PIO1_5, 1, 5);
impl_pin!(PIO1_6, 1, 6);
impl_pin!(PIO1_7, 1, 7);
impl_pin!(PIO1_8, 1, 8);
impl_pin!(PIO1_9, 1, 9);
impl_pin!(PIO1_10, 1, 10);
impl_pin!(PIO1_11, 1, 11);
impl_pin!(PIO1_12, 1, 12);
impl_pin!(PIO1_13, 1, 13);
impl_pin!(PIO1_14, 1, 14);
impl_pin!(PIO1_15, 1, 15);
impl_pin!(PIO1_16, 1, 16);
impl_pin!(PIO1_17, 1, 17);
impl_pin!(PIO1_18, 1, 18);
impl_pin!(PIO1_19, 1, 19);
impl_pin!(PIO1_20, 1, 20);
impl_pin!(PIO1_21, 1, 21);
impl_pin!(PIO1_22, 1, 22);
impl_pin!(PIO1_23, 1, 23);
impl_pin!(PIO1_24, 1, 24);
impl_pin!(PIO1_25, 1, 25);
impl_pin!(PIO1_26, 1, 26);
impl_pin!(PIO1_27, 1, 27);
impl_pin!(PIO1_28, 1, 28);
impl_pin!(PIO1_29, 1, 29);
impl_pin!(PIO1_30, 1, 30);
impl_pin!(PIO1_31, 1, 31);
impl_pin!(PIO2_0, 2, 0);
impl_pin!(PIO2_1, 2, 1);
impl_pin!(PIO2_2, 2, 2);
impl_pin!(PIO2_3, 2, 3);
impl_pin!(PIO2_4, 2, 4);
impl_pin!(PIO2_5, 2, 5);
impl_pin!(PIO2_6, 2, 6);
impl_pin!(PIO2_7, 2, 7);
impl_pin!(PIO2_8, 2, 8);
impl_pin!(PIO2_9, 2, 9);
impl_pin!(PIO2_10, 2, 10);
impl_pin!(PIO2_11, 2, 11);
impl_pin!(PIO2_12, 2, 12);
impl_pin!(PIO2_13, 2, 13);
impl_pin!(PIO2_14, 2, 14);
impl_pin!(PIO2_15, 2, 15);
impl_pin!(PIO2_16, 2, 16);
impl_pin!(PIO2_17, 2, 17);
impl_pin!(PIO2_18, 2, 18);
impl_pin!(PIO2_19, 2, 19);
impl_pin!(PIO2_20, 2, 20);
impl_pin!(PIO2_21, 2, 21);
impl_pin!(PIO2_22, 2, 22);
impl_pin!(PIO2_23, 2, 23);
impl_pin!(PIO2_24, 2, 24);
// Note: These have have reset values of 0x41 to support SWD by default
impl_pin!(PIO2_25, 2, 25);
impl_pin!(PIO2_26, 2, 26);
impl_pin!(PIO2_27, 2, 27);
impl_pin!(PIO2_28, 2, 28);
impl_pin!(PIO2_29, 2, 29);
impl_pin!(PIO2_30, 2, 30);
impl_pin!(PIO2_31, 2, 31);
impl_pin!(PIO3_0, 3, 0);
impl_pin!(PIO3_1, 3, 1);
impl_pin!(PIO3_2, 3, 2);
impl_pin!(PIO3_3, 3, 3);
impl_pin!(PIO3_4, 3, 4);
impl_pin!(PIO3_5, 3, 5);
impl_pin!(PIO3_6, 3, 6);
impl_pin!(PIO3_7, 3, 7);
impl_pin!(PIO3_8, 3, 8);
impl_pin!(PIO3_9, 3, 9);
impl_pin!(PIO3_10, 3, 10);
impl_pin!(PIO3_11, 3, 11);
impl_pin!(PIO3_12, 3, 12);
impl_pin!(PIO3_13, 3, 13);
impl_pin!(PIO3_14, 3, 14);
impl_pin!(PIO3_15, 3, 15);
impl_pin!(PIO3_16, 3, 16);
impl_pin!(PIO3_17, 3, 17);
impl_pin!(PIO3_18, 3, 18);
impl_pin!(PIO3_19, 3, 19);
impl_pin!(PIO3_20, 3, 20);
impl_pin!(PIO3_21, 3, 21);
impl_pin!(PIO3_22, 3, 22);
impl_pin!(PIO3_23, 3, 23);
impl_pin!(PIO3_24, 3, 24);
impl_pin!(PIO3_25, 3, 25);
impl_pin!(PIO3_26, 3, 26);
impl_pin!(PIO3_27, 3, 27);
impl_pin!(PIO3_28, 3, 28);
impl_pin!(PIO3_29, 3, 29);
impl_pin!(PIO3_30, 3, 30);
impl_pin!(PIO3_31, 3, 31);
impl_pin!(PIO4_0, 4, 0);
impl_pin!(PIO4_1, 4, 1);
impl_pin!(PIO4_2, 4, 2);
impl_pin!(PIO4_3, 4, 3);
impl_pin!(PIO4_4, 4, 4);
impl_pin!(PIO4_5, 4, 5);
impl_pin!(PIO4_6, 4, 6);
impl_pin!(PIO4_7, 4, 7);
impl_pin!(PIO4_8, 4, 8);
impl_pin!(PIO4_9, 4, 9);
impl_pin!(PIO4_10, 4, 10);
impl_pin!(PIO7_24, 7, 24);
impl_pin!(PIO7_25, 7, 25);
impl_pin!(PIO7_26, 7, 26);
impl_pin!(PIO7_27, 7, 27);
impl_pin!(PIO7_28, 7, 28);
impl_pin!(PIO7_29, 7, 29);
impl_pin!(PIO7_30, 7, 30);
impl_pin!(PIO7_31, 7, 31);
// FC15 pins
impl_FC15pin!(PIOFC15_SCL, 0);
impl_FC15pin!(PIOFC15_SDA, 1);

130
embassy-imxrt/src/lib.rs Normal file
View File

@ -0,0 +1,130 @@
#![no_std]
#![allow(async_fn_in_trait)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
//! ## Feature flags
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
#[cfg(not(any(feature = "mimxrt633s", feature = "mimxrt685s",)))]
compile_error!(
"No chip feature activated. You must activate exactly one of the following features:
mimxrt633s,
mimxrt685s,
"
);
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;
pub mod clocks;
pub mod gpio;
pub mod iopctl;
// This mod MUST go last, so that it sees all the `impl_foo!' macros
#[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")]
#[cfg_attr(feature = "mimxrt685s", path = "chips/mimxrt685s.rs")]
mod chip;
// Reexports
pub use chip::interrupts::*;
#[cfg(feature = "unstable-pac")]
pub use chip::pac;
#[cfg(not(feature = "unstable-pac"))]
pub(crate) use chip::pac;
pub use chip::{peripherals, Peripherals};
pub use embassy_hal_internal::{Peri, PeripheralType};
#[cfg(feature = "rt")]
pub use crate::pac::NVIC_PRIO_BITS;
/// Macro to bind interrupts to handlers.
///
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right \[`Binding`\]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
///
/// Example of how to bind one interrupt:
///
/// ```rust,ignore
/// use embassy_imxrt::{bind_interrupts, flexspi, peripherals};
///
/// bind_interrupts!(struct Irqs {
/// FLEXSPI_IRQ => flexspi::InterruptHandler<peripherals::FLEXSPI>;
/// });
/// ```
///
// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
#[macro_export]
macro_rules! bind_interrupts {
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
#[derive(Copy, Clone)]
$vis struct $name;
$(
#[allow(non_snake_case)]
#[no_mangle]
unsafe extern "C" fn $irq() {
$(
<$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
)*
}
$(
unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
)*
)*
};
}
/// HAL configuration for iMX RT600.
pub mod config {
use crate::clocks::ClockConfig;
/// HAL configuration passed when initializing.
#[non_exhaustive]
pub struct Config {
/// Clock configuration.
pub clocks: ClockConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
clocks: ClockConfig::crystal(),
}
}
}
impl Config {
/// Create a new configuration with the provided clock config.
pub fn new(clocks: ClockConfig) -> Self {
Self { clocks }
}
}
}
/// Initialize the `embassy-imxrt` HAL with the provided configuration.
///
/// This returns the peripheral singletons that can be used for creating drivers.
///
/// This should only be called once at startup, otherwise it panics.
pub fn init(config: config::Config) -> Peripherals {
// Do this first, so that it panics if user is calling `init` a second time
// before doing anything important.
let peripherals = Peripherals::take();
unsafe {
if let Err(e) = clocks::init(config.clocks) {
error!("unable to initialize Clocks for reason: {:?}", e);
// Panic here?
}
gpio::init();
}
peripherals
}
pub(crate) mod sealed {
pub trait Sealed {}
}

View File

@ -0,0 +1,17 @@
[target.thumbv8m.main-none-eabihf]
runner = 'probe-rs run --chip MIMXRT685SFVKB'
rustflags = [
"-C", "linker=flip-link",
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
"-C", "link-arg=--nmagic",
]
[build]
target = "thumbv8m.main-none-eabihf" # Cortex-M33
[env]
DEFMT_LOG = "trace"

14
examples/mimxrt6/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# Generated by Cargo
# will have compiled files and executables
/debug
/target
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

View File

@ -0,0 +1,60 @@
[package]
name = "embassy-imxrt-examples"
version = "0.1.0"
edition = "2021"
license = "MIT or Apache-2.0"
[dependencies]
cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.3"
defmt = "1.0"
defmt-rtt = "1.0"
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
embassy-futures = { version = "0.1.1", path = "../../embassy-futures" }
embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac"] }
embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
embedded-hal-async = "1.0.0"
mimxrt600-fcb = "0.1.0"
panic-probe = { version = "0.3", features = ["print-defmt"] }
rand = { version = "0.8.5", default-features = false }
# cargo build/run
[profile.dev]
codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
opt-level = 3 # <-
overflow-checks = true # <-
# cargo test
[profile.test]
codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
opt-level = 3 # <-
overflow-checks = true # <-
# cargo build/run --release
[profile.release]
codegen-units = 1
debug = 2
debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = 3 # <-
overflow-checks = false # <-
# cargo test --release
[profile.bench]
codegen-units = 1
debug = 2
debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = 3 # <-
overflow-checks = false # <-

View File

@ -0,0 +1,18 @@
# embassy-imxrt-examples
## Introduction
These examples illustrates how to use the embassy-imxrt HAL.
## Adding Examples
Add uniquely named example to `src/bin` like `adc.rs`
## Build
`cd` to examples folder
`cargo build --bin <example_name>` for example, `cargo build --bin adc`
## Run
Assuming RT685 is powered and connected to Jlink debug probe and the latest probe-rs is installed via
`$ cargo install probe-rs-tools --git https://github.com/probe-rs/probe-rs --locked`
`cd` to examples folder
`cargo run --bin <example_name>` for example, `cargo run --bin adc`

45
examples/mimxrt6/build.rs Normal file
View File

@ -0,0 +1,45 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");
// Inject crate version into the .biv section.
File::create(out.join("biv.rs"))
.unwrap()
.write_all(
format!(
r##"
#[link_section = ".biv"]
#[used]
static BOOT_IMAGE_VERSION: u32 = 0x{:02x}{:02x}{:02x}00;
"##,
env!("CARGO_PKG_VERSION_MAJOR")
.parse::<u8>()
.expect("should have major version"),
env!("CARGO_PKG_VERSION_MINOR")
.parse::<u8>()
.expect("should have minor version"),
env!("CARGO_PKG_VERSION_PATCH")
.parse::<u8>()
.expect("should have patch version"),
)
.as_bytes(),
)
.unwrap();
}

34
examples/mimxrt6/memory.x Normal file
View File

@ -0,0 +1,34 @@
MEMORY {
OTFAD : ORIGIN = 0x08000000, LENGTH = 256
FCB : ORIGIN = 0x08000400, LENGTH = 512
BIV : ORIGIN = 0x08000600, LENGTH = 4
KEYSTORE : ORIGIN = 0x08000800, LENGTH = 2K
FLASH : ORIGIN = 0x08001000, LENGTH = 1M
RAM : ORIGIN = 0x20080000, LENGTH = 1536K
}
SECTIONS {
.otfad : {
. = ALIGN(4);
KEEP(* (.otfad))
. = ALIGN(4);
} > OTFAD
.fcb : {
. = ALIGN(4);
KEEP(* (.fcb))
. = ALIGN(4);
} > FCB
.biv : {
. = ALIGN(4);
KEEP(* (.biv))
. = ALIGN(4);
} > BIV
.keystore : {
. = ALIGN(4);
KEEP(* (.keystore))
. = ALIGN(4);
} > KEYSTORE
}

View File

@ -0,0 +1,29 @@
#![no_std]
#![no_main]
extern crate embassy_imxrt_examples;
use defmt::info;
use embassy_executor::Spawner;
use embassy_imxrt::gpio;
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_imxrt::init(Default::default());
info!("Initializing GPIO");
let mut led = gpio::Output::new(
p.PIO0_26,
gpio::Level::Low,
gpio::DriveMode::PushPull,
gpio::DriveStrength::Normal,
gpio::SlewRate::Standard,
);
loop {
info!("Toggling LED");
led.toggle();
cortex_m::asm::delay(5_000_000);
}
}

View File

@ -0,0 +1,17 @@
#![no_std]
#![no_main]
extern crate embassy_imxrt_examples;
use defmt::info;
use embassy_executor::Spawner;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
let _p = embassy_imxrt::init(Default::default());
loop {
info!("Hello");
cortex_m::asm::delay(5_000_000);
}
}

View File

@ -0,0 +1,20 @@
#![no_std]
use mimxrt600_fcb::FlexSPIFlashConfigurationBlock;
use {defmt_rtt as _, panic_probe as _};
// auto-generated version information from Cargo.toml
include!(concat!(env!("OUT_DIR"), "/biv.rs"));
#[link_section = ".otfad"]
#[used]
static OTFAD: [u8; 256] = [0; 256];
#[rustfmt::skip]
#[link_section = ".fcb"]
#[used]
static FCB: FlexSPIFlashConfigurationBlock = FlexSPIFlashConfigurationBlock::build();
#[link_section = ".keystore"]
#[used]
static KEYSTORE: [u8; 2048] = [0; 2048];