Merge branch 'embassy-rs:main' into obe1line-stm32c071

This commit is contained in:
obe1line 2025-07-23 12:40:48 +10:00 committed by GitHub
commit eb15a55519
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
61 changed files with 3928 additions and 76 deletions

View File

@ -36,6 +36,8 @@
// "examples/nrf52840-rtic/Cargo.toml",
// "examples/nrf5340/Cargo.toml",
// "examples/nrf-rtos-trace/Cargo.toml",
// "examples/mimxrt1011/Cargo.toml",
// "examples/mimxrt1062-evk/Cargo.toml",
// "examples/rp/Cargo.toml",
// "examples/std/Cargo.toml",
// "examples/stm32c0/Cargo.toml",

5
ci.sh
View File

@ -183,6 +183,8 @@ cargo batch \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf --features lpc55,defmt \
--- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1011,rt,defmt,time-driver-pit \
--- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1062,rt,defmt,time-driver-pit \
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1104dgs20,defmt,time-driver-any \
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507pm,defmt,time-driver-any \
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,defmt,time-driver-any \
@ -266,6 +268,8 @@ cargo batch \
--- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \
--- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \
--- build --release --manifest-path examples/mimxrt1011/Cargo.toml --target thumbv7em-none-eabihf --artifact-dir out/examples/mimxrt1011 \
--- build --release --manifest-path examples/mimxrt1062-evk/Cargo.toml --target thumbv7em-none-eabihf --artifact-dir out/examples/mimxrt1062-evk \
--- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \
--- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \
--- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \
@ -379,6 +383,7 @@ rm out/tests/pimoroni-pico-plus-2/pwm
# flaky
rm out/tests/rpi-pico/pwm
rm out/tests/rpi-pico/cyw43-perf
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
echo No teleprobe token found, skipping running HIL tests

View File

@ -1,7 +1,7 @@
[package]
edition = "2021"
name = "embassy-boot-nrf"
version = "0.5.0"
version = "0.6.0"
description = "Bootloader lib for nRF chips"
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
@ -26,7 +26,7 @@ log = { version = "0.4.17", optional = true }
embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
embassy-nrf = { version = "0.5.0", path = "../embassy-nrf", default-features = false }
embassy-boot = { version = "0.4.0", path = "../embassy-boot" }
embassy-boot = { version = "0.5.0", path = "../embassy-boot" }
cortex-m = { version = "0.7.6" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.1"

View File

@ -1,7 +1,7 @@
[package]
edition = "2021"
name = "embassy-boot-rp"
version = "0.5.0"
version = "0.6.0"
description = "Bootloader lib for RP2040 chips"
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
@ -26,7 +26,7 @@ log = { version = "0.4", optional = true }
embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
embassy-rp = { version = "0.6.0", path = "../embassy-rp", default-features = false }
embassy-boot = { version = "0.4.0", path = "../embassy-boot" }
embassy-boot = { version = "0.5.0", path = "../embassy-boot" }
embassy-time = { version = "0.4.0", path = "../embassy-time" }
cortex-m = { version = "0.7.6" }

View File

@ -1,7 +1,7 @@
[package]
edition = "2021"
name = "embassy-boot-stm32"
version = "0.3.0"
version = "0.4.0"
description = "Bootloader lib for STM32 chips"
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
@ -26,7 +26,7 @@ log = { version = "0.4", optional = true }
embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32", default-features = false }
embassy-boot = { version = "0.4.0", path = "../embassy-boot" }
embassy-boot = { version = "0.5.0", path = "../embassy-boot" }
cortex-m = { version = "0.7.6" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.1"

View File

@ -1,7 +1,7 @@
[package]
edition = "2021"
name = "embassy-boot"
version = "0.4.0"
version = "0.5.0"
description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks."
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"

View File

@ -36,7 +36,10 @@ embassy-embedded-hal = { version = "0.3.1", path = "../embassy-embedded-hal", de
embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true }
embedded-hal = { version = "1.0" }
embedded-hal-nb = { version = "1.0" }
embedded-hal-async = { version = "1.0" }
embedded-io = "0.6.1"
embedded-io-async = "0.6.1"
defmt = { version = "1.0.1", optional = true }
fixed = "1.29"
@ -51,6 +54,7 @@ mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag
[build-dependencies]
proc-macro2 = "1.0.94"
quote = "1.0.40"
cfg_aliases = "0.2.1"
# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-235158ac2865d8aac3a1eceb2d62026eb12bf38f", default-features = false, features = ["metadata"] }

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,11 @@
#![macro_use]
mod buffered;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
pub use buffered::*;
use embassy_embedded_hal::SetConfig;
use embassy_hal_internal::PeripheralType;
@ -128,8 +131,8 @@ pub struct Config {
// pub manchester: bool,
// TODO: majority voting
// TODO: fifo level select - need power domain info in metapac
/// If true: the built-in FIFO is enabled.
pub fifo_enable: bool,
// TODO: glitch suppression
/// If true: invert TX pin signal values (V<sub>DD</sub> = 0/mark, Gnd = 1/idle).
@ -169,6 +172,7 @@ impl Default for Config {
msb_order: BitOrder::LsbFirst,
loop_back_enable: false,
// manchester: false,
fifo_enable: false,
invert_tx: false,
invert_rx: false,
invert_rts: false,
@ -185,7 +189,7 @@ impl Default for Config {
///
/// ### Notes on [`embedded_io::Read`]
///
/// `embedded_io::Read` requires guarantees that the base [`UartRx`] cannot provide.
/// [`embedded_io::Read`] requires guarantees that the base [`UartRx`] cannot provide.
///
/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`]
/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`.
@ -199,8 +203,7 @@ impl<'d, M: Mode> SetConfig for Uart<'d, M> {
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.tx.set_config(config)?;
self.rx.set_config(config)
self.set_config(config)
}
}
@ -236,6 +239,12 @@ impl core::fmt::Display for Error {
impl core::error::Error for Error {}
impl embedded_io::Error for Error {
fn kind(&self) -> embedded_io::ErrorKind {
embedded_io::ErrorKind::Other
}
}
/// Rx-only UART Driver.
///
/// Can be obtained from [`Uart::split`], or can be constructed independently,
@ -260,7 +269,7 @@ impl<'d, M: Mode> SetConfig for UartRx<'d, M> {
impl<'d> UartRx<'d, Blocking> {
/// Create a new rx-only UART with no hardware flow control.
///
/// Useful if you only want Uart Rx. It saves 1 pin .
/// Useful if you only want Uart Rx. It saves 1 pin.
pub fn new_blocking<T: Instance>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
@ -286,19 +295,6 @@ impl<'d> UartRx<'d, Blocking> {
}
impl<'d, M: Mode> UartRx<'d, M> {
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
if let Some(ref rx) = self.rx {
rx.update_pf(config.rx_pf());
}
if let Some(ref rts) = self.rts {
rts.update_pf(config.rts_pf());
}
reconfigure(self.info, self.state, config)
}
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = self.info.regs;
@ -315,6 +311,19 @@ impl<'d, M: Mode> UartRx<'d, M> {
Ok(())
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
if let Some(ref rx) = self.rx {
rx.update_pf(config.rx_pf());
}
if let Some(ref rts) = self.rts {
rts.update_pf(config.rts_pf());
}
reconfigure(self.info, self.state, config)
}
/// Set baudrate
pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
set_baudrate(&self.info, self.state.clock.load(Ordering::Relaxed), baudrate)
@ -378,19 +387,6 @@ impl<'d> UartTx<'d, Blocking> {
}
impl<'d, M: Mode> UartTx<'d, M> {
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
if let Some(ref tx) = self.tx {
tx.update_pf(config.tx_pf());
}
if let Some(ref cts) = self.cts {
cts.update_pf(config.cts_pf());
}
reconfigure(self.info, self.state, config)
}
/// Perform a blocking UART write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = self.info.regs;
@ -427,6 +423,24 @@ impl<'d, M: Mode> UartTx<'d, M> {
});
}
/// Check if UART is busy.
pub fn busy(&self) -> bool {
busy(self.info.regs)
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
if let Some(ref tx) = self.tx {
tx.update_pf(config.tx_pf());
}
if let Some(ref cts) = self.cts {
cts.update_pf(config.cts_pf());
}
reconfigure(self.info, self.state, config)
}
/// Set baudrate
pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
set_baudrate(&self.info, self.state.clock.load(Ordering::Relaxed), baudrate)
@ -489,6 +503,11 @@ impl<'d, M: Mode> Uart<'d, M> {
self.tx.blocking_flush()
}
/// Check if UART is busy.
pub fn busy(&self) -> bool {
self.tx.busy()
}
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.blocking_read(buffer)
@ -508,6 +527,12 @@ impl<'d, M: Mode> Uart<'d, M> {
(&mut self.tx, &mut self.rx)
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.tx.set_config(config)?;
self.rx.set_config(config)
}
/// Send break character
pub fn send_break(&self) {
self.tx.send_break();
@ -557,8 +582,16 @@ pub(crate) struct Info {
}
pub(crate) struct State {
/// The clock rate of the UART. This might be configured.
pub(crate) clock: AtomicU32,
/// The clock rate of the UART in Hz.
clock: AtomicU32,
}
impl State {
pub const fn new() -> Self {
Self {
clock: AtomicU32::new(0),
}
}
}
impl<'d, M: Mode> UartRx<'d, M> {
@ -746,7 +779,8 @@ fn configure(
info.regs.ctl0().modify(|w| {
w.set_lbe(config.loop_back_enable);
w.set_rxe(enable_rx);
// Errata UART_ERR_02, must set RXE to allow use of EOT.
w.set_rxe(enable_rx | enable_tx);
w.set_txe(enable_tx);
// RXD_OUT_EN and TXD_OUT_EN?
w.set_menc(false);
@ -754,13 +788,18 @@ fn configure(
w.set_rtsen(enable_rts);
w.set_ctsen(enable_cts);
// oversampling is set later
// TODO: config
w.set_fen(false);
w.set_fen(config.fifo_enable);
// TODO: config
w.set_majvote(false);
w.set_msbfirst(matches!(config.msb_order, BitOrder::MsbFirst));
});
info.regs.ifls().modify(|w| {
// TODO: Need power domain info for other options.
w.set_txiflsel(vals::Iflssel::AT_LEAST_ONE);
w.set_rxiflsel(vals::Iflssel::AT_LEAST_ONE);
});
info.regs.lcrh().modify(|w| {
let eps = if matches!(config.parity, Parity::ParityEven) {
vals::Eps::EVEN
@ -1021,9 +1060,29 @@ fn read_with_error(r: Regs) -> Result<u8, Error> {
Ok(rx.data())
}
/// This function assumes CTL0.ENABLE is set (for errata cases).
fn busy(r: Regs) -> bool {
// Errata UART_ERR_08
if cfg!(any(
mspm0g151x, mspm0g351x, mspm0l110x, mspm0l130x, mspm0l134x, mspm0c110x,
)) {
let stat = r.stat().read();
// "Poll TXFIFO status and the CTL0.ENABLE register bit to identify BUSY status."
!stat.txfe()
} else {
r.stat().read().busy()
}
}
// TODO: Implement when dma uart is implemented.
fn dma_enabled(_r: Regs) -> bool {
false
}
pub(crate) trait SealedInstance {
fn info() -> &'static Info;
fn state() -> &'static State;
fn buffered_state() -> &'static BufferedState;
}
macro_rules! impl_uart_instance {
@ -1041,12 +1100,16 @@ macro_rules! impl_uart_instance {
}
fn state() -> &'static crate::uart::State {
use crate::interrupt::typelevel::Interrupt;
use crate::uart::State;
static STATE: State = State {
clock: core::sync::atomic::AtomicU32::new(0),
};
static STATE: State = State::new();
&STATE
}
fn buffered_state() -> &'static crate::uart::BufferedState {
use crate::uart::BufferedState;
static STATE: BufferedState = BufferedState::new();
&STATE
}
}

View File

@ -10,23 +10,52 @@ critical-section = "1.1.2"
embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
defmt = { version = "1", optional = true }
log = { version = "0.4.27", optional = true }
embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true }
embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true }
## Chip dependencies
lpc55-pac = { version = "0.5.0", optional = true }
nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e" }
imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] }
[build-dependencies]
cfg_aliases = "0.2.1"
nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e", features = ["metadata"], optional = true }
proc-macro2 = "1.0.95"
quote = "1.0.15"
[features]
default = ["rt"]
# Enable PACs as optional dependencies, since some chip families will use different pac crates.
rt = ["lpc55-pac?/rt"]
# Enable PACs as optional dependencies, since some chip families will use different pac crates (temporarily).
rt = ["lpc55-pac?/rt", "nxp-pac?/rt"]
## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"]
log = ["dep:log"]
## Use Periodic Interrupt Timer (PIT) as the time driver for `embassy-time`, with a tick rate of 1 MHz
time-driver-pit = ["_time_driver", "embassy-time?/tick-hz-1_000_000"]
## Reexport the PAC for the currently enabled chip at `embassy_nxp::pac` (unstable)
unstable-pac = []
# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version.
# This is unstable because semver-minor (non-breaking) releases of embassy-nxp may major-bump (breaking) the PAC version.
# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
# There are no plans to make this stable.
## internal use only
#
# This feature is unfortunately a hack around the fact that cfg_aliases cannot apply to the buildscript
# that creates the aliases.
_rt1xxx = []
# A timer driver is enabled.
_time_driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"]
#! ### Chip selection features
lpc55 = ["lpc55-pac"]
lpc55 = ["dep:lpc55-pac"]
mimxrt1011 = ["nxp-pac/mimxrt1011", "_rt1xxx", "dep:imxrt-rt"]
mimxrt1062 = ["nxp-pac/mimxrt1062", "_rt1xxx", "dep:imxrt-rt"]

138
embassy-nxp/build.rs Normal file
View File

@ -0,0 +1,138 @@
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::{env, fs};
use cfg_aliases::cfg_aliases;
#[cfg(feature = "_rt1xxx")]
use nxp_pac::metadata;
#[allow(unused)]
use proc_macro2::TokenStream;
#[allow(unused)]
use quote::quote;
#[path = "./build_common.rs"]
mod common;
fn main() {
let mut cfgs = common::CfgSet::new();
common::set_target_cfgs(&mut cfgs);
let chip_name = match env::vars()
.map(|(a, _)| a)
.filter(|x| x.starts_with("CARGO_FEATURE_MIMXRT") || x.starts_with("CARGO_FEATURE_LPC"))
.get_one()
{
Ok(x) => x,
Err(GetOneError::None) => panic!("No mimxrt/lpc Cargo feature enabled"),
Err(GetOneError::Multiple) => panic!("Multiple mimxrt/lpc Cargo features enabled"),
}
.strip_prefix("CARGO_FEATURE_")
.unwrap()
.to_ascii_lowercase();
cfg_aliases! {
rt1xxx: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
gpio1: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
gpio2: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
gpio3: { feature = "mimxrt1062" },
gpio4: { feature = "mimxrt1062" },
gpio5: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
}
eprintln!("chip: {chip_name}");
generate_code();
}
#[cfg(feature = "_rt1xxx")]
fn generate_iomuxc() -> TokenStream {
use proc_macro2::{Ident, Span};
let pads = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| {
let name = Ident::new(&registers.name, Span::call_site());
let address = registers.pad_ctl;
quote! {
pub const #name: u32 = #address;
}
});
let muxes = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| {
let name = Ident::new(&registers.name, Span::call_site());
let address = registers.mux_ctl;
quote! {
pub const #name: u32 = #address;
}
});
quote! {
pub mod iomuxc {
pub mod pads {
#(#pads)*
}
pub mod muxes {
#(#muxes)*
}
}
}
}
fn generate_code() {
#[allow(unused)]
use std::fmt::Write;
let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
#[allow(unused_mut)]
let mut output = String::new();
#[cfg(feature = "_rt1xxx")]
writeln!(&mut output, "{}", generate_iomuxc()).unwrap();
let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string();
fs::write(&out_file, output).unwrap();
rustfmt(&out_file);
}
/// rustfmt a given path.
/// Failures are logged to stderr and ignored.
fn rustfmt(path: impl AsRef<Path>) {
let path = path.as_ref();
match Command::new("rustfmt").args([path]).output() {
Err(e) => {
eprintln!("failed to exec rustfmt {:?}: {:?}", path, e);
}
Ok(out) => {
if !out.status.success() {
eprintln!("rustfmt {:?} failed:", path);
eprintln!("=== STDOUT:");
std::io::stderr().write_all(&out.stdout).unwrap();
eprintln!("=== STDERR:");
std::io::stderr().write_all(&out.stderr).unwrap();
}
}
}
}
enum GetOneError {
None,
Multiple,
}
trait IteratorExt: Iterator {
fn get_one(self) -> Result<Self::Item, GetOneError>;
}
impl<T: Iterator> IteratorExt for T {
fn get_one(mut self) -> Result<Self::Item, GetOneError> {
match self.next() {
None => Err(GetOneError::None),
Some(res) => match self.next() {
Some(_) => Err(GetOneError::Multiple),
None => Ok(res),
},
}
}
}

View File

@ -0,0 +1,94 @@
// NOTE: this file is copy-pasted between several Embassy crates, because there is no
// straightforward way to share this code:
// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
// reside in the crate's directory,
// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
// symlinks don't work on Windows.
use std::collections::HashSet;
use std::env;
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
/// them (`cargo:rust-check-cfg=cfg(X)`).
#[derive(Debug)]
pub struct CfgSet {
enabled: HashSet<String>,
declared: HashSet<String>,
}
impl CfgSet {
pub fn new() -> Self {
Self {
enabled: HashSet::new(),
declared: HashSet::new(),
}
}
/// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
///
/// All configs that can potentially be enabled should be unconditionally declared using
/// [`Self::declare()`].
pub fn enable(&mut self, cfg: impl AsRef<str>) {
if self.enabled.insert(cfg.as_ref().to_owned()) {
println!("cargo:rustc-cfg={}", cfg.as_ref());
}
}
pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
for cfg in cfgs.iter() {
self.enable(cfg.as_ref());
}
}
/// Declare a valid config for conditional compilation, without enabling it.
///
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
pub fn declare(&mut self, cfg: impl AsRef<str>) {
if self.declared.insert(cfg.as_ref().to_owned()) {
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
}
}
pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
for cfg in cfgs.iter() {
self.declare(cfg.as_ref());
}
}
pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
let cfg = cfg.into();
if enable {
self.enable(cfg.clone());
}
self.declare(cfg);
}
}
/// Sets configs that describe the target platform.
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
let target = env::var("TARGET").unwrap();
if target.starts_with("thumbv6m-") {
cfgs.enable_all(&["cortex_m", "armv6m"]);
} else if target.starts_with("thumbv7m-") {
cfgs.enable_all(&["cortex_m", "armv7m"]);
} else if target.starts_with("thumbv7em-") {
cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
} else if target.starts_with("thumbv8m.base") {
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
} else if target.starts_with("thumbv8m.main") {
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
}
cfgs.declare_all(&[
"cortex_m",
"armv6m",
"armv7m",
"armv7em",
"armv8m",
"armv8m_base",
"armv8m_main",
]);
cfgs.set("has_fpu", target.ends_with("-eabihf"));
}

View File

@ -0,0 +1,113 @@
// This must be imported so that __preinit is defined.
use imxrt_rt as _;
pub use nxp_pac as pac;
embassy_hal_internal::peripherals! {
// External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
// peripheral types (e.g. I2C).
GPIO_00,
GPIO_01,
GPIO_02,
GPIO_03,
GPIO_04,
GPIO_05,
GPIO_06,
GPIO_07,
GPIO_08,
GPIO_09,
GPIO_10,
GPIO_11,
GPIO_12,
GPIO_13,
GPIO_AD_00,
GPIO_AD_01,
GPIO_AD_02,
GPIO_AD_03,
GPIO_AD_04,
GPIO_AD_05,
GPIO_AD_06,
GPIO_AD_07,
GPIO_AD_08,
GPIO_AD_09,
GPIO_AD_10,
GPIO_AD_11,
GPIO_AD_12,
GPIO_AD_13,
GPIO_AD_14,
GPIO_SD_00,
GPIO_SD_01,
GPIO_SD_02,
GPIO_SD_03,
GPIO_SD_04,
GPIO_SD_05,
GPIO_SD_06,
GPIO_SD_07,
GPIO_SD_08,
GPIO_SD_09,
GPIO_SD_10,
GPIO_SD_11,
GPIO_SD_12,
GPIO_SD_13,
PMIC_ON_REQ,
}
impl_gpio! {
// GPIO Bank 1
GPIO_00(Gpio1, 0);
GPIO_01(Gpio1, 1);
GPIO_02(Gpio1, 2);
GPIO_03(Gpio1, 3);
GPIO_04(Gpio1, 4);
GPIO_05(Gpio1, 5);
GPIO_06(Gpio1, 6);
GPIO_07(Gpio1, 7);
GPIO_08(Gpio1, 8);
GPIO_09(Gpio1, 9);
GPIO_10(Gpio1, 10);
GPIO_11(Gpio1, 11);
GPIO_12(Gpio1, 12);
GPIO_13(Gpio1, 13);
GPIO_AD_00(Gpio1, 14);
GPIO_AD_01(Gpio1, 15);
GPIO_AD_02(Gpio1, 16);
GPIO_AD_03(Gpio1, 17);
GPIO_AD_04(Gpio1, 18);
GPIO_AD_05(Gpio1, 19);
GPIO_AD_06(Gpio1, 20);
GPIO_AD_07(Gpio1, 21);
GPIO_AD_08(Gpio1, 22);
GPIO_AD_09(Gpio1, 23);
GPIO_AD_10(Gpio1, 24);
GPIO_AD_11(Gpio1, 25);
GPIO_AD_12(Gpio1, 26);
GPIO_AD_13(Gpio1, 27);
GPIO_AD_14(Gpio1, 28);
// GPIO Bank 2
GPIO_SD_00(Gpio2, 0);
GPIO_SD_01(Gpio2, 1);
GPIO_SD_02(Gpio2, 2);
GPIO_SD_03(Gpio2, 3);
GPIO_SD_04(Gpio2, 4);
GPIO_SD_05(Gpio2, 5);
GPIO_SD_06(Gpio2, 6);
GPIO_SD_07(Gpio2, 7);
GPIO_SD_08(Gpio2, 8);
GPIO_SD_09(Gpio2, 9);
GPIO_SD_10(Gpio2, 10);
GPIO_SD_11(Gpio2, 11);
GPIO_SD_12(Gpio2, 12);
GPIO_SD_13(Gpio2, 13);
// GPIO Bank 5
PMIC_ON_REQ(Gpio5, 0);
}
pub(crate) mod _generated {
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(non_snake_case)]
#![allow(missing_docs)]
include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
}

View File

@ -0,0 +1,282 @@
// This must be imported so that __preinit is defined.
use imxrt_rt as _;
pub use nxp_pac as pac;
embassy_hal_internal::peripherals! {
// External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
// peripheral types (e.g. I2C).
GPIO_AD_B0_00,
GPIO_AD_B0_01,
GPIO_AD_B0_02,
GPIO_AD_B0_03,
GPIO_AD_B0_04,
GPIO_AD_B0_05,
GPIO_AD_B0_06,
GPIO_AD_B0_07,
GPIO_AD_B0_08,
GPIO_AD_B0_09,
GPIO_AD_B0_10,
GPIO_AD_B0_11,
GPIO_AD_B0_12,
GPIO_AD_B0_13,
GPIO_AD_B0_14,
GPIO_AD_B0_15,
GPIO_AD_B1_00,
GPIO_AD_B1_01,
GPIO_AD_B1_02,
GPIO_AD_B1_03,
GPIO_AD_B1_04,
GPIO_AD_B1_05,
GPIO_AD_B1_06,
GPIO_AD_B1_07,
GPIO_AD_B1_08,
GPIO_AD_B1_09,
GPIO_AD_B1_10,
GPIO_AD_B1_11,
GPIO_AD_B1_12,
GPIO_AD_B1_13,
GPIO_AD_B1_14,
GPIO_AD_B1_15,
GPIO_B0_00,
GPIO_B0_01,
GPIO_B0_02,
GPIO_B0_03,
GPIO_B0_04,
GPIO_B0_05,
GPIO_B0_06,
GPIO_B0_07,
GPIO_B0_08,
GPIO_B0_09,
GPIO_B0_10,
GPIO_B0_11,
GPIO_B0_12,
GPIO_B0_13,
GPIO_B0_14,
GPIO_B0_15,
GPIO_B1_00,
GPIO_B1_01,
GPIO_B1_02,
GPIO_B1_03,
GPIO_B1_04,
GPIO_B1_05,
GPIO_B1_06,
GPIO_B1_07,
GPIO_B1_08,
GPIO_B1_09,
GPIO_B1_10,
GPIO_B1_11,
GPIO_B1_12,
GPIO_B1_13,
GPIO_B1_14,
GPIO_B1_15,
GPIO_EMC_00,
GPIO_EMC_01,
GPIO_EMC_02,
GPIO_EMC_03,
GPIO_EMC_04,
GPIO_EMC_05,
GPIO_EMC_06,
GPIO_EMC_07,
GPIO_EMC_08,
GPIO_EMC_09,
GPIO_EMC_10,
GPIO_EMC_11,
GPIO_EMC_12,
GPIO_EMC_13,
GPIO_EMC_14,
GPIO_EMC_15,
GPIO_EMC_16,
GPIO_EMC_17,
GPIO_EMC_18,
GPIO_EMC_19,
GPIO_EMC_20,
GPIO_EMC_21,
GPIO_EMC_22,
GPIO_EMC_23,
GPIO_EMC_24,
GPIO_EMC_25,
GPIO_EMC_26,
GPIO_EMC_27,
GPIO_EMC_28,
GPIO_EMC_29,
GPIO_EMC_30,
GPIO_EMC_31,
GPIO_EMC_32,
GPIO_EMC_33,
GPIO_EMC_34,
GPIO_EMC_35,
GPIO_EMC_36,
GPIO_EMC_37,
GPIO_EMC_38,
GPIO_EMC_39,
GPIO_EMC_40,
GPIO_EMC_41,
GPIO_SD_B0_00,
GPIO_SD_B0_01,
GPIO_SD_B0_02,
GPIO_SD_B0_03,
GPIO_SD_B0_04,
GPIO_SD_B0_05,
GPIO_SD_B1_00,
GPIO_SD_B1_01,
GPIO_SD_B1_02,
GPIO_SD_B1_03,
GPIO_SD_B1_04,
GPIO_SD_B1_05,
GPIO_SD_B1_06,
GPIO_SD_B1_07,
GPIO_SD_B1_08,
GPIO_SD_B1_09,
GPIO_SD_B1_10,
GPIO_SD_B1_11,
WAKEUP,
PMIC_ON_REQ,
PMIC_STBY_REQ,
}
impl_gpio! {
// GPIO Bank 1
GPIO_AD_B0_00(Gpio1, 0);
GPIO_AD_B0_01(Gpio1, 1);
GPIO_AD_B0_02(Gpio1, 2);
GPIO_AD_B0_03(Gpio1, 3);
GPIO_AD_B0_04(Gpio1, 4);
GPIO_AD_B0_05(Gpio1, 5);
GPIO_AD_B0_06(Gpio1, 6);
GPIO_AD_B0_07(Gpio1, 7);
GPIO_AD_B0_08(Gpio1, 8);
GPIO_AD_B0_09(Gpio1, 9);
GPIO_AD_B0_10(Gpio1, 10);
GPIO_AD_B0_11(Gpio1, 11);
GPIO_AD_B0_12(Gpio1, 12);
GPIO_AD_B0_13(Gpio1, 13);
GPIO_AD_B0_14(Gpio1, 14);
GPIO_AD_B0_15(Gpio1, 15);
GPIO_AD_B1_00(Gpio1, 16);
GPIO_AD_B1_01(Gpio1, 17);
GPIO_AD_B1_02(Gpio1, 18);
GPIO_AD_B1_03(Gpio1, 19);
GPIO_AD_B1_04(Gpio1, 20);
GPIO_AD_B1_05(Gpio1, 21);
GPIO_AD_B1_06(Gpio1, 22);
GPIO_AD_B1_07(Gpio1, 23);
GPIO_AD_B1_08(Gpio1, 24);
GPIO_AD_B1_09(Gpio1, 25);
GPIO_AD_B1_10(Gpio1, 26);
GPIO_AD_B1_11(Gpio1, 27);
GPIO_AD_B1_12(Gpio1, 28);
GPIO_AD_B1_13(Gpio1, 29);
GPIO_AD_B1_14(Gpio1, 30);
GPIO_AD_B1_15(Gpio1, 31);
// GPIO Bank 2
GPIO_B0_00(Gpio2, 0);
GPIO_B0_01(Gpio2, 1);
GPIO_B0_02(Gpio2, 2);
GPIO_B0_03(Gpio2, 3);
GPIO_B0_04(Gpio2, 4);
GPIO_B0_05(Gpio2, 5);
GPIO_B0_06(Gpio2, 6);
GPIO_B0_07(Gpio2, 7);
GPIO_B0_08(Gpio2, 8);
GPIO_B0_09(Gpio2, 9);
GPIO_B0_10(Gpio2, 10);
GPIO_B0_11(Gpio2, 11);
GPIO_B0_12(Gpio2, 12);
GPIO_B0_13(Gpio2, 13);
GPIO_B0_14(Gpio2, 14);
GPIO_B0_15(Gpio2, 15);
GPIO_B1_00(Gpio2, 16);
GPIO_B1_01(Gpio2, 17);
GPIO_B1_02(Gpio2, 18);
GPIO_B1_03(Gpio2, 19);
GPIO_B1_04(Gpio2, 20);
GPIO_B1_05(Gpio2, 21);
GPIO_B1_06(Gpio2, 22);
GPIO_B1_07(Gpio2, 23);
GPIO_B1_08(Gpio2, 24);
GPIO_B1_09(Gpio2, 25);
GPIO_B1_10(Gpio2, 26);
GPIO_B1_11(Gpio2, 27);
GPIO_B1_12(Gpio2, 28);
GPIO_B1_13(Gpio2, 29);
GPIO_B1_14(Gpio2, 30);
GPIO_B1_15(Gpio2, 31);
// GPIO Bank 4 (EMC is 4, then 3)
GPIO_EMC_00(Gpio4, 0);
GPIO_EMC_01(Gpio4, 1);
GPIO_EMC_02(Gpio4, 2);
GPIO_EMC_03(Gpio4, 3);
GPIO_EMC_04(Gpio4, 4);
GPIO_EMC_05(Gpio4, 5);
GPIO_EMC_06(Gpio4, 6);
GPIO_EMC_07(Gpio4, 7);
GPIO_EMC_08(Gpio4, 8);
GPIO_EMC_09(Gpio4, 9);
GPIO_EMC_10(Gpio4, 10);
GPIO_EMC_11(Gpio4, 11);
GPIO_EMC_12(Gpio4, 12);
GPIO_EMC_13(Gpio4, 13);
GPIO_EMC_14(Gpio4, 14);
GPIO_EMC_15(Gpio4, 15);
GPIO_EMC_16(Gpio4, 16);
GPIO_EMC_17(Gpio4, 17);
GPIO_EMC_18(Gpio4, 18);
GPIO_EMC_19(Gpio4, 19);
GPIO_EMC_20(Gpio4, 20);
GPIO_EMC_21(Gpio4, 21);
GPIO_EMC_22(Gpio4, 22);
GPIO_EMC_23(Gpio4, 23);
GPIO_EMC_24(Gpio4, 24);
GPIO_EMC_25(Gpio4, 25);
GPIO_EMC_26(Gpio4, 26);
GPIO_EMC_27(Gpio4, 27);
GPIO_EMC_28(Gpio4, 28);
GPIO_EMC_29(Gpio4, 29);
GPIO_EMC_30(Gpio4, 30);
GPIO_EMC_31(Gpio4, 31);
// GPIO Bank 3
GPIO_EMC_32(Gpio3, 18);
GPIO_EMC_33(Gpio3, 19);
GPIO_EMC_34(Gpio3, 20);
GPIO_EMC_35(Gpio3, 21);
GPIO_EMC_36(Gpio3, 22);
GPIO_EMC_37(Gpio3, 23);
GPIO_EMC_38(Gpio3, 24);
GPIO_EMC_39(Gpio3, 25);
GPIO_EMC_40(Gpio3, 26);
GPIO_EMC_41(Gpio3, 27);
GPIO_SD_B0_00(Gpio3, 12);
GPIO_SD_B0_01(Gpio3, 13);
GPIO_SD_B0_02(Gpio3, 14);
GPIO_SD_B0_03(Gpio3, 15);
GPIO_SD_B0_04(Gpio3, 16);
GPIO_SD_B0_05(Gpio3, 17);
GPIO_SD_B1_00(Gpio3, 0);
GPIO_SD_B1_01(Gpio3, 1);
GPIO_SD_B1_02(Gpio3, 2);
GPIO_SD_B1_03(Gpio3, 3);
GPIO_SD_B1_04(Gpio3, 4);
GPIO_SD_B1_05(Gpio3, 5);
GPIO_SD_B1_06(Gpio3, 6);
GPIO_SD_B1_07(Gpio3, 7);
GPIO_SD_B1_08(Gpio3, 8);
GPIO_SD_B1_09(Gpio3, 9);
GPIO_SD_B1_10(Gpio3, 10);
GPIO_SD_B1_11(Gpio3, 11);
WAKEUP(Gpio5, 0);
PMIC_ON_REQ(Gpio5, 1);
PMIC_STBY_REQ(Gpio5, 2);
}
pub(crate) mod _generated {
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(non_snake_case)]
#![allow(missing_docs)]
include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
}

284
embassy-nxp/src/fmt.rs Normal file
View File

@ -0,0 +1,284 @@
//! Copied from embassy-rp
#![macro_use]
#![allow(unused)]
use core::fmt::{Debug, Display, LowerHex};
#[cfg(all(feature = "defmt", feature = "log"))]
compile_error!("You may not enable both `defmt` and `log` features.");
#[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! unimplemented {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::unimplemented!($($x)*);
#[cfg(feature = "defmt")]
::defmt::unimplemented!($($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 = "log")]
::log::trace!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::trace!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! debug {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::debug!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::debug!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! info {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::info!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::info!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! warn {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::warn!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::warn!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
#[collapse_debuginfo(yes)]
macro_rules! error {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::error!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::error!($s $(, $x)*);
#[cfg(not(any(feature = "log", 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<'a> Debug for Bytes<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
impl<'a> Display for Bytes<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
impl<'a> LowerHex for Bytes<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
#[cfg(feature = "defmt")]
impl<'a> defmt::Format for Bytes<'a> {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(fmt, "{:02x}", self.0)
}
}

View File

@ -1,5 +1,7 @@
//! General purpose input/output (GPIO) driver.
#![macro_use]
#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")]
#[cfg_attr(rt1xxx, path = "./gpio/rt1xxx.rs")]
mod inner;
pub use inner::*;

View File

@ -7,6 +7,7 @@ pub(crate) fn init() {
syscon_reg()
.ahbclkctrl0
.modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable());
info!("GPIO initialized");
}
/// The GPIO pin level for pins set on "Digital" mode.

View File

@ -0,0 +1,945 @@
#![macro_use]
use core::future::Future;
use core::ops::Not;
use core::pin::Pin as FuturePin;
use core::task::{Context, Poll};
use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
use nxp_pac::gpio::vals::Icr;
use nxp_pac::iomuxc::vals::Pus;
use crate::chip::{mux_address, pad_address};
use crate::pac::common::{Reg, RW};
use crate::pac::gpio::Gpio;
#[cfg(feature = "rt")]
use crate::pac::interrupt;
use crate::pac::iomuxc::regs::{Ctl, MuxCtl};
use crate::pac::{self};
/// The GPIO pin level for pins set on "Digital" mode.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum Level {
/// Logical low. Corresponds to 0V.
Low,
/// Logical high. Corresponds to VDD.
High,
}
impl From<bool> for Level {
fn from(val: bool) -> Self {
match val {
true => Self::High,
false => Self::Low,
}
}
}
impl From<Level> for bool {
fn from(level: Level) -> bool {
match level {
Level::Low => false,
Level::High => true,
}
}
}
impl Not for Level {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Level::Low => Level::High,
Level::High => Level::Low,
}
}
}
/// Pull setting for a GPIO input set on "Digital" mode.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Pull {
/// No pull.
None,
// TODO: What Does PUE::KEEPER mean here?
// 22 kOhm pull-up resistor.
Up22K,
// 47 kOhm pull-up resistor.
Up47K,
// 100 kOhm pull-up resistor.
Up100K,
// 100 kOhm pull-down resistor.
Down100K,
}
/// Drive strength of an output
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Drive {
Disabled,
_150R,
_75R,
_50R,
_37R,
_30R,
_25R,
_20R,
}
/// Slew rate of an output
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SlewRate {
Slow,
Fast,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Bank {
/// Bank 1
#[cfg(gpio1)]
Gpio1,
/// Bank 2
#[cfg(gpio2)]
Gpio2,
/// Bank 3
#[cfg(gpio3)]
Gpio3,
/// Bank 4
#[cfg(gpio4)]
Gpio4,
/// Bank 5
#[cfg(gpio5)]
Gpio5,
}
/// GPIO flexible pin.
///
/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
/// mode.
pub struct Flex<'d> {
pub(crate) pin: Peri<'d, AnyPin>,
}
impl<'d> Flex<'d> {
/// Wrap the pin in a `Flex`.
///
/// The pin remains disconnected. The initial output level is unspecified, but can be changed
/// before the pin is put into output mode.
#[inline]
pub fn new(pin: Peri<'d, impl Pin>) -> Self {
Self { pin: pin.into() }
}
/// Set the pin's pull.
#[inline]
pub fn set_pull(&mut self, pull: Pull) {
let (pke, pue, pus) = match pull {
Pull::None => (false, true, Pus::PUS_0_100K_OHM_PULL_DOWN),
Pull::Up22K => (true, true, Pus::PUS_3_22K_OHM_PULL_UP),
Pull::Up47K => (true, true, Pus::PUS_1_47K_OHM_PULL_UP),
Pull::Up100K => (true, true, Pus::PUS_2_100K_OHM_PULL_UP),
Pull::Down100K => (true, true, Pus::PUS_0_100K_OHM_PULL_DOWN),
};
self.pin.pad().modify(|w| {
w.set_pke(pke);
w.set_pue(pue);
w.set_pus(pus);
});
}
// Set the pin's slew rate.
#[inline]
pub fn set_slewrate(&mut self, rate: SlewRate) {
self.pin.pad().modify(|w| {
w.set_sre(match rate {
SlewRate::Slow => false,
SlewRate::Fast => true,
});
});
}
/// Set the pin's Schmitt trigger.
#[inline]
pub fn set_schmitt(&mut self, enable: bool) {
self.pin.pad().modify(|w| {
w.set_hys(enable);
});
}
/// Put the pin into input mode.
///
/// The pull setting is left unchanged.
#[inline]
pub fn set_as_input(&mut self) {
self.pin.mux().modify(|w| {
w.set_mux_mode(GPIO_MUX_MODE);
});
// Setting direction is RMW
critical_section::with(|_cs| {
self.pin.block().gdir().modify(|w| {
w.set_gdir(self.pin.pin_number() as usize, false);
});
})
}
/// Put the pin into output mode.
///
/// The pin level will be whatever was set before (or low by default). If you want it to begin
/// at a specific level, call `set_high`/`set_low` on the pin first.
#[inline]
pub fn set_as_output(&mut self) {
self.pin.mux().modify(|w| {
w.set_mux_mode(GPIO_MUX_MODE);
});
// Setting direction is RMW
critical_section::with(|_cs| {
self.pin.block().gdir().modify(|w| {
w.set_gdir(self.pin.pin_number() as usize, true);
});
})
}
/// Put the pin into input + open-drain output mode.
///
/// The hardware will drive the line low if you set it to low, and will leave it floating if you set
/// it to high, in which case you can read the input to figure out whether another device
/// is driving the line low.
///
/// The pin level will be whatever was set before (or low by default). If you want it to begin
/// at a specific level, call `set_high`/`set_low` on the pin first.
///
/// The internal weak pull-up and pull-down resistors will be disabled.
#[inline]
pub fn set_as_input_output(&mut self) {
self.pin.pad().modify(|w| {
w.set_ode(true);
});
}
/// Set the pin as "disconnected", ie doing nothing and consuming the lowest
/// amount of power possible.
///
/// This is currently the same as [`Self::set_as_analog()`] but is semantically different
/// really. Drivers should `set_as_disconnected()` pins when dropped.
///
/// Note that this also disables the pull-up and pull-down resistors.
#[inline]
pub fn set_as_disconnected(&mut self) {
self.pin.pad().modify(|w| {
w.set_ode(false);
w.set_pke(false);
w.set_pue(false);
w.set_pus(Pus::PUS_0_100K_OHM_PULL_DOWN);
});
}
/// Get whether the pin input level is high.
#[inline]
pub fn is_high(&self) -> bool {
self.pin.block().psr().read().psr(self.pin.pin_number() as usize)
}
/// Get whether the pin input level is low.
#[inline]
pub fn is_low(&self) -> bool {
!self.is_high()
}
/// Returns current pin level
#[inline]
pub fn get_level(&self) -> Level {
self.is_high().into()
}
/// Set the output as high.
#[inline]
pub fn set_high(&mut self) {
self.pin.block().dr_set().write(|w| {
w.set_dr_set(self.pin.pin_number() as usize, true);
});
}
/// Set the output as low.
#[inline]
pub fn set_low(&mut self) {
self.pin.block().dr_clear().write(|w| {
w.set_dr_clear(self.pin.pin_number() as usize, true);
});
}
/// Toggle pin output
#[inline]
pub fn toggle(&mut self) {
self.pin.block().dr_toggle().write(|w| {
w.set_dr_toggle(self.pin.pin_number() as usize, true);
});
}
/// Set the output level.
#[inline]
pub fn set_level(&mut self, level: Level) {
match level {
Level::Low => self.set_low(),
Level::High => self.set_high(),
}
}
/// Get the current pin output level.
#[inline]
pub fn get_output_level(&self) -> Level {
self.is_set_high().into()
}
/// Is the output level high?
///
/// If the [`Flex`] is set as an input, then this is equivalent to [`Flex::is_high`].
#[inline]
pub fn is_set_high(&self) -> bool {
self.pin.block().dr().read().dr(self.pin.pin_number() as usize)
}
/// Is the output level low?
///
/// If the [`Flex`] is set as an input, then this is equivalent to [`Flex::is_low`].
#[inline]
pub fn is_set_low(&self) -> bool {
!self.is_set_high()
}
/// Wait until the pin is high. If it is already high, return immediately.
#[inline]
pub async fn wait_for_high(&mut self) {
InputFuture::new(self.pin.reborrow(), InterruptConfiguration::High).await
}
/// Wait until the pin is low. If it is already low, return immediately.
#[inline]
pub async fn wait_for_low(&mut self) {
InputFuture::new(self.pin.reborrow(), InterruptConfiguration::Low).await
}
/// Wait for the pin to undergo a transition from low to high.
#[inline]
pub async fn wait_for_rising_edge(&mut self) {
InputFuture::new(self.pin.reborrow(), InterruptConfiguration::RisingEdge).await
}
/// Wait for the pin to undergo a transition from high to low.
#[inline]
pub async fn wait_for_falling_edge(&mut self) {
InputFuture::new(self.pin.reborrow(), InterruptConfiguration::FallingEdge).await
}
/// Wait for the pin to undergo any transition, i.e low to high OR high to low.
#[inline]
pub async fn wait_for_any_edge(&mut self) {
InputFuture::new(self.pin.reborrow(), InterruptConfiguration::AnyEdge).await
}
}
impl<'d> Drop for Flex<'d> {
fn drop(&mut self) {
self.set_as_disconnected();
}
}
/// GPIO input driver.
pub struct Input<'d> {
pin: Flex<'d>,
}
impl<'d> Input<'d> {
/// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
#[inline]
pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
let mut pin = Flex::new(pin);
pin.set_as_input();
pin.set_pull(pull);
Self { pin }
}
/// Get whether the pin input level is high.
#[inline]
pub fn is_high(&self) -> bool {
self.pin.is_high()
}
/// Get whether the pin input level is low.
#[inline]
pub fn is_low(&self) -> bool {
self.pin.is_low()
}
/// Get the current pin input level.
#[inline]
pub fn get_level(&self) -> Level {
self.pin.get_level()
}
/// Wait until the pin is high. If it is already high, return immediately.
#[inline]
pub async fn wait_for_high(&mut self) {
self.pin.wait_for_high().await
}
/// Wait until the pin is low. If it is already low, return immediately.
#[inline]
pub async fn wait_for_low(&mut self) {
self.pin.wait_for_low().await
}
/// Wait for the pin to undergo a transition from low to high.
#[inline]
pub async fn wait_for_rising_edge(&mut self) {
self.pin.wait_for_rising_edge().await
}
/// Wait for the pin to undergo a transition from high to low.
#[inline]
pub async fn wait_for_falling_edge(&mut self) {
self.pin.wait_for_falling_edge().await
}
/// Wait for the pin to undergo any transition, i.e low to high OR high to low.
#[inline]
pub async fn wait_for_any_edge(&mut self) {
self.pin.wait_for_any_edge().await
}
}
/// GPIO output driver.
///
/// Note that pins will **return to their floating state** when `Output` is dropped.
/// If pins should retain their state indefinitely, either keep ownership of the
/// `Output`, or pass it to [`core::mem::forget`].
pub struct Output<'d> {
pin: Flex<'d>,
}
impl<'d> Output<'d> {
/// Create GPIO output driver for a [Pin] with the provided [Level] configuration.
#[inline]
pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
let mut pin = Flex::new(pin);
pin.set_as_output();
pin.set_level(initial_output);
Self { pin }
}
/// Set the output as high.
#[inline]
pub fn set_high(&mut self) {
self.pin.set_high();
}
/// Set the output as low.
#[inline]
pub fn set_low(&mut self) {
self.pin.set_low();
}
/// Set the output level.
#[inline]
pub fn set_level(&mut self, level: Level) {
self.pin.set_level(level)
}
/// Is the output pin set as high?
#[inline]
pub fn is_set_high(&self) -> bool {
self.pin.is_set_high()
}
/// Is the output pin set as low?
#[inline]
pub fn is_set_low(&self) -> bool {
self.pin.is_set_low()
}
/// What level output is set to
#[inline]
pub fn get_output_level(&self) -> Level {
self.pin.get_output_level()
}
/// Toggle pin output
#[inline]
pub fn toggle(&mut self) {
self.pin.toggle();
}
}
/// GPIO output open-drain driver.
///
/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped.
/// If pins should retain their state indefinitely, either keep ownership of the
/// `OutputOpenDrain`, or pass it to [`core::mem::forget`].
pub struct OutputOpenDrain<'d> {
pin: Flex<'d>,
}
impl<'d> OutputOpenDrain<'d> {
/// Create a new GPIO open drain output driver for a [Pin] with the provided [Level].
#[inline]
pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
let mut pin = Flex::new(pin);
pin.set_level(initial_output);
pin.set_as_input_output();
Self { pin }
}
/// Get whether the pin input level is high.
#[inline]
pub fn is_high(&self) -> bool {
!self.pin.is_low()
}
/// Get whether the pin input level is low.
#[inline]
pub fn is_low(&self) -> bool {
self.pin.is_low()
}
/// Get the current pin input level.
#[inline]
pub fn get_level(&self) -> Level {
self.pin.get_level()
}
/// Set the output as high.
#[inline]
pub fn set_high(&mut self) {
self.pin.set_high();
}
/// Set the output as low.
#[inline]
pub fn set_low(&mut self) {
self.pin.set_low();
}
/// Set the output level.
#[inline]
pub fn set_level(&mut self, level: Level) {
self.pin.set_level(level);
}
/// Get whether the output level is set to high.
#[inline]
pub fn is_set_high(&self) -> bool {
self.pin.is_set_high()
}
/// Get whether the output level is set to low.
#[inline]
pub fn is_set_low(&self) -> bool {
self.pin.is_set_low()
}
/// Get the current output level.
#[inline]
pub fn get_output_level(&self) -> Level {
self.pin.get_output_level()
}
/// Toggle pin output
#[inline]
pub fn toggle(&mut self) {
self.pin.toggle()
}
/// Wait until the pin is high. If it is already high, return immediately.
#[inline]
pub async fn wait_for_high(&mut self) {
self.pin.wait_for_high().await
}
/// Wait until the pin is low. If it is already low, return immediately.
#[inline]
pub async fn wait_for_low(&mut self) {
self.pin.wait_for_low().await
}
/// Wait for the pin to undergo a transition from low to high.
#[inline]
pub async fn wait_for_rising_edge(&mut self) {
self.pin.wait_for_rising_edge().await
}
/// Wait for the pin to undergo a transition from high to low.
#[inline]
pub async fn wait_for_falling_edge(&mut self) {
self.pin.wait_for_falling_edge().await
}
/// Wait for the pin to undergo any transition, i.e low to high OR high to low.
#[inline]
pub async fn wait_for_any_edge(&mut self) {
self.pin.wait_for_any_edge().await
}
}
#[allow(private_bounds)]
pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
/// Returns the pin number within a bank
#[inline]
fn pin(&self) -> u8 {
self.pin_number()
}
#[inline]
fn bank(&self) -> Bank {
self._bank()
}
}
/// Type-erased GPIO pin.
pub struct AnyPin {
pub(crate) pin_number: u8,
pub(crate) bank: Bank,
}
impl AnyPin {
/// Unsafely create a new type-erased pin.
///
/// # Safety
///
/// You must ensure that youre only using one instance of this type at a time.
pub unsafe fn steal(bank: Bank, pin_number: u8) -> Peri<'static, Self> {
Peri::new_unchecked(Self { pin_number, bank })
}
}
impl_peripheral!(AnyPin);
impl Pin for AnyPin {}
impl SealedPin for AnyPin {
#[inline]
fn pin_number(&self) -> u8 {
self.pin_number
}
#[inline]
fn _bank(&self) -> Bank {
self.bank
}
}
// Impl details
/// Mux mode for GPIO pins. This is constant across all RT1xxx parts.
const GPIO_MUX_MODE: u8 = 0b101;
// FIXME: These don't always need to be 32 entries. GPIO5 on RT1101 contains a single pin and GPIO2 only 14.
#[cfg(gpio1)]
static GPIO1_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
#[cfg(gpio2)]
static GPIO2_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
#[cfg(gpio3)]
static GPIO3_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
#[cfg(gpio4)]
static GPIO4_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
#[cfg(gpio5)]
static GPIO5_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
/// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate.
pub(crate) trait SealedPin: Sized {
fn pin_number(&self) -> u8;
fn _bank(&self) -> Bank;
#[inline]
fn block(&self) -> Gpio {
match self._bank() {
#[cfg(gpio1)]
Bank::Gpio1 => pac::GPIO1,
#[cfg(gpio2)]
Bank::Gpio2 => pac::GPIO2,
#[cfg(gpio3)]
Bank::Gpio3 => pac::GPIO3,
#[cfg(gpio4)]
Bank::Gpio4 => pac::GPIO4,
#[cfg(gpio5)]
Bank::Gpio5 => pac::GPIO5,
}
}
#[inline]
fn mux(&self) -> Reg<MuxCtl, RW> {
// SAFETY: The generated mux address table is valid since it is generated from the SVD files.
let address = unsafe { mux_address(self._bank(), self.pin_number()).unwrap_unchecked() };
// SAFETY: The register at the address is an instance of MuxCtl.
unsafe { Reg::from_ptr(address as *mut _) }
}
#[inline]
fn pad(&self) -> Reg<Ctl, RW> {
// SAFETY: The generated pad address table is valid since it is generated from the SVD files.
let address = unsafe { pad_address(self._bank(), self.pin_number()).unwrap_unchecked() };
// SAFETY: The register at the address is an instance of Ctl.
unsafe { Reg::from_ptr(address as *mut _) }
}
fn waker(&self) -> &AtomicWaker {
match self._bank() {
#[cfg(gpio1)]
Bank::Gpio1 => &GPIO1_WAKERS[self.pin_number() as usize],
#[cfg(gpio2)]
Bank::Gpio2 => &GPIO2_WAKERS[self.pin_number() as usize],
#[cfg(gpio3)]
Bank::Gpio3 => &GPIO3_WAKERS[self.pin_number() as usize],
#[cfg(gpio4)]
Bank::Gpio4 => &GPIO4_WAKERS[self.pin_number() as usize],
#[cfg(gpio5)]
Bank::Gpio5 => &GPIO5_WAKERS[self.pin_number() as usize],
}
}
}
/// This enum matches the layout of Icr.
enum InterruptConfiguration {
Low,
High,
RisingEdge,
FallingEdge,
AnyEdge,
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct InputFuture<'d> {
pin: Peri<'d, AnyPin>,
}
impl<'d> InputFuture<'d> {
fn new(pin: Peri<'d, AnyPin>, config: InterruptConfiguration) -> Self {
let block = pin.block();
let (icr, edge_sel) = match config {
InterruptConfiguration::Low => (Icr::LOW_LEVEL, false),
InterruptConfiguration::High => (Icr::HIGH_LEVEL, false),
InterruptConfiguration::RisingEdge => (Icr::RISING_EDGE, false),
InterruptConfiguration::FallingEdge => (Icr::FALLING_EDGE, false),
InterruptConfiguration::AnyEdge => (Icr::FALLING_EDGE, true),
};
let index = if pin.pin_number() > 15 { 1 } else { 0 };
// Interrupt configuration performs RMW
critical_section::with(|_cs| {
// Disable interrupt so a level/edge detection change does not cause ISR to be set.
block.imr().modify(|w| {
w.set_imr(pin.pin_number() as usize, false);
});
block.icr(index).modify(|w| {
w.set_pin(pin.pin_number() as usize, icr);
});
block.edge_sel().modify(|w| {
w.set_edge_sel(pin.pin_number() as usize, edge_sel);
});
// Clear the previous interrupt.
block.isr().modify(|w| {
// "Status flags are cleared by writing a 1 to the corresponding bit position."
w.set_isr(pin.pin_number() as usize, true);
});
});
Self { pin }
}
}
impl<'d> Future for InputFuture<'d> {
type Output = ();
fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// We need to register/re-register the waker for each poll because any
// calls to wake will deregister the waker.
let waker = self.pin.waker();
waker.register(cx.waker());
// Enabling interrupt is RMW
critical_section::with(|_cs| {
self.pin.block().imr().modify(|w| {
w.set_imr(self.pin.pin_number() as usize, true);
});
});
let isr = self.pin.block().isr().read();
if isr.isr(self.pin.pin_number() as usize) {
return Poll::Ready(());
}
Poll::Pending
}
}
/// A macro to generate all GPIO pins.
///
/// This generates a lookup table for IOMUX register addresses.
macro_rules! impl_gpio {
(
$($name: ident($bank: ident, $pin_number: expr);)*
) => {
#[inline]
pub(crate) const fn pad_address(bank: crate::gpio::Bank, pin: u8) -> Option<u32> {
match (bank, pin) {
$(
(crate::gpio::Bank::$bank, $pin_number) => Some(crate::chip::_generated::iomuxc::pads::$name),
)*
_ => None
}
}
#[inline]
pub(crate) const fn mux_address(bank: crate::gpio::Bank, pin: u8) -> Option<u32> {
match (bank, pin) {
$(
(crate::gpio::Bank::$bank, $pin_number) => Some(crate::chip::_generated::iomuxc::muxes::$name),
)*
_ => None
}
}
$(
impl_pin!($name, $bank, $pin_number);
)*
};
}
macro_rules! impl_pin {
($name: ident, $bank: ident, $pin_num: expr) => {
impl crate::gpio::Pin for crate::peripherals::$name {}
impl crate::gpio::SealedPin for crate::peripherals::$name {
#[inline]
fn pin_number(&self) -> u8 {
$pin_num
}
#[inline]
fn _bank(&self) -> crate::gpio::Bank {
crate::gpio::Bank::$bank
}
}
impl From<peripherals::$name> for crate::gpio::AnyPin {
fn from(val: peripherals::$name) -> Self {
use crate::gpio::SealedPin;
Self {
pin_number: val.pin_number(),
bank: val._bank(),
}
}
}
};
}
pub(crate) fn init() {
#[cfg(feature = "rt")]
unsafe {
use embassy_hal_internal::interrupt::InterruptExt;
pac::Interrupt::GPIO1_COMBINED_0_15.enable();
pac::Interrupt::GPIO1_COMBINED_16_31.enable();
pac::Interrupt::GPIO2_COMBINED_0_15.enable();
pac::Interrupt::GPIO5_COMBINED_0_15.enable();
}
}
/// IRQ handler for GPIO pins.
///
/// If `high_bits` is false, then the interrupt is for pins 0 through 15. If true, then the interrupt
/// is for pins 16 through 31
#[cfg(feature = "rt")]
fn irq_handler(block: Gpio, wakers: &[AtomicWaker; 32], high_bits: bool) {
use crate::BitIter;
let isr = block.isr().read().0;
let imr = block.imr().read().0;
let mask = if high_bits { 0xFFFF_0000 } else { 0x0000_FFFF };
let bits = isr & imr & mask;
for bit in BitIter(bits) {
wakers[bit as usize].wake();
// Disable further interrupts for this pin. The input future will check ISR (which is kept
// until reset).
block.imr().modify(|w| {
w.set_imr(bit as usize, false);
});
}
}
#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
#[interrupt]
fn GPIO1_COMBINED_0_15() {
irq_handler(pac::GPIO1, &GPIO1_WAKERS, false);
}
#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
#[interrupt]
fn GPIO1_COMBINED_16_31() {
irq_handler(pac::GPIO1, &GPIO1_WAKERS, true);
}
#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
#[interrupt]
fn GPIO2_COMBINED_0_15() {
irq_handler(pac::GPIO2, &GPIO2_WAKERS, false);
}
#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
#[interrupt]
fn GPIO2_COMBINED_16_31() {
irq_handler(pac::GPIO2, &GPIO2_WAKERS, true);
}
#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
#[interrupt]
fn GPIO3_COMBINED_0_15() {
irq_handler(pac::GPIO3, &GPIO3_WAKERS, false);
}
#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
#[interrupt]
fn GPIO3_COMBINED_16_31() {
irq_handler(pac::GPIO3, &GPIO3_WAKERS, true);
}
#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
#[interrupt]
fn GPIO4_COMBINED_0_15() {
irq_handler(pac::GPIO4, &GPIO4_WAKERS, false);
}
#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
#[interrupt]
fn GPIO4_COMBINED_16_31() {
irq_handler(pac::GPIO4, &GPIO4_WAKERS, true);
}
#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
#[interrupt]
fn GPIO5_COMBINED_0_15() {
irq_handler(pac::GPIO5, &GPIO5_WAKERS, false);
}

View File

@ -1,11 +1,20 @@
#![no_std]
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;
pub mod gpio;
#[cfg(feature = "lpc55")]
pub mod pint;
#[cfg(feature = "_time_driver")]
#[cfg_attr(feature = "time-driver-pit", path = "time_driver/pit.rs")]
mod time_driver;
// This mod MUST go last, so that it sees all the `impl_foo!` macros
#[cfg_attr(feature = "lpc55", path = "chips/lpc55.rs")]
#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")]
#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")]
mod chip;
#[cfg(feature = "unstable-pac")]
@ -21,13 +30,66 @@ pub use embassy_hal_internal::{Peri, PeripheralType};
///
/// This should only be called once and at startup, otherwise it panics.
pub fn init(_config: config::Config) -> Peripherals {
#[cfg(feature = "lpc55")]
// Do this first, so that it panics if user is calling `init` a second time
// before doing anything important.
let peripherals = Peripherals::take();
#[cfg(feature = "mimxrt1011")]
{
gpio::init();
pint::init();
// The RT1010 Reference manual states that core clock root must be switched before
// reprogramming PLL2.
pac::CCM.cbcdr().modify(|w| {
w.set_periph_clk_sel(pac::ccm::vals::PeriphClkSel::PERIPH_CLK_SEL_1);
});
while matches!(
pac::CCM.cdhipr().read().periph_clk_sel_busy(),
pac::ccm::vals::PeriphClkSelBusy::PERIPH_CLK_SEL_BUSY_1
) {}
info!("Core clock root switched");
// 480 * 18 / 24 = 360
pac::CCM_ANALOG.pfd_480().modify(|x| x.set_pfd2_frac(12));
//480*18/24(pfd0)/4
pac::CCM_ANALOG.pfd_480().modify(|x| x.set_pfd0_frac(24));
pac::CCM.cscmr1().modify(|x| x.set_flexspi_podf(3.into()));
// CPU Core
pac::CCM_ANALOG.pfd_528().modify(|x| x.set_pfd3_frac(18));
cortex_m::asm::delay(500_000);
// Clock core clock with PLL 2.
pac::CCM
.cbcdr()
.modify(|x| x.set_periph_clk_sel(pac::ccm::vals::PeriphClkSel::PERIPH_CLK_SEL_0)); // false
while matches!(
pac::CCM.cdhipr().read().periph_clk_sel_busy(),
pac::ccm::vals::PeriphClkSelBusy::PERIPH_CLK_SEL_BUSY_1
) {}
pac::CCM
.cbcmr()
.write(|v| v.set_pre_periph_clk_sel(pac::ccm::vals::PrePeriphClkSel::PRE_PERIPH_CLK_SEL_0));
// TODO: Some for USB PLLs
// DCDC clock?
pac::CCM.ccgr6().modify(|v| v.set_cg0(1));
}
crate::Peripherals::take()
#[cfg(any(feature = "lpc55", rt1xxx))]
gpio::init();
#[cfg(feature = "lpc55")]
pint::init();
#[cfg(feature = "_time_driver")]
time_driver::init();
peripherals
}
/// HAL configuration for the NXP board.
@ -35,3 +97,20 @@ pub mod config {
#[derive(Default)]
pub struct Config {}
}
#[allow(unused)]
struct BitIter(u32);
impl Iterator for BitIter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
match self.0.trailing_zeros() {
32 => None,
b => {
self.0 &= !(1 << b);
Some(b)
}
}
}
}

View File

@ -101,6 +101,8 @@ pub(crate) fn init() {
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6);
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7);
};
info!("Pin interrupts initialized");
}
#[must_use = "futures do nothing unless you `.await` or poll them"]

View File

@ -0,0 +1,187 @@
//! Time driver using Periodic Interrupt Timer (PIT)
//!
//! This driver is used with the iMXRT1xxx parts.
//!
//! The PIT is run in lifetime mode. Timer 1 is chained to timer 0 to provide a free-running 64-bit timer.
//! The 64-bit timer is used to track how many ticks since boot.
//!
//! Timer 2 counts how many ticks there are within the current u32::MAX tick period. Timer 2 is restarted when
//! a new alarm is set (or every u32::MAX ticks). One caveat is that an alarm could be a few ticks late due to
//! restart. However the Cortex-M7 cores run at 500 MHz easily and the PIT will generally run at 1 MHz or lower.
//! Along with the fact that scheduling an alarm takes a critical section worst case an alarm may be a few
//! microseconds late.
//!
//! All PIT timers are clocked in lockstep, so the late start will not cause the now() count to drift.
use core::cell::{Cell, RefCell};
use core::task::Waker;
use critical_section::{CriticalSection, Mutex};
use embassy_hal_internal::interrupt::InterruptExt;
use embassy_time_driver::Driver as _;
use embassy_time_queue_utils::Queue;
use crate::pac::{self, interrupt};
struct Driver {
alarm: Mutex<Cell<u64>>,
queue: Mutex<RefCell<Queue>>,
}
impl embassy_time_driver::Driver for Driver {
fn now(&self) -> u64 {
loop {
// Even though reading LTMR64H will latch LTMR64L if another thread preempts between any of the
// three reads and calls now() then the value in LTMR64L will be wrong when execution returns to
// thread which was preempted.
let hi = pac::PIT.ltmr64h().read().lth();
let lo = pac::PIT.ltmr64l().read().ltl();
let hi2 = pac::PIT.ltmr64h().read().lth();
if hi == hi2 {
// PIT timers always count down.
return u64::MAX - ((hi as u64) << 32 | (lo as u64));
}
}
}
fn schedule_wake(&self, at: u64, waker: &Waker) {
critical_section::with(|cs| {
let mut queue = self.queue.borrow(cs).borrow_mut();
if queue.schedule_wake(at, waker) {
let mut next = queue.next_expiration(self.now());
while !self.set_alarm(cs, next) {
next = queue.next_expiration(self.now());
}
}
})
}
}
impl Driver {
fn init(&'static self) {
// Disable PIT clock during mux configuration.
pac::CCM.ccgr1().modify(|r| r.set_cg6(0b00));
// TODO: This forces the PIT to be driven by the oscillator. However that isn't the only option as you
// could divide the clock root by up to 64.
pac::CCM.cscmr1().modify(|r| {
// 1 MHz
r.set_perclk_podf(pac::ccm::vals::PerclkPodf::DIVIDE_24);
r.set_perclk_clk_sel(pac::ccm::vals::PerclkClkSel::PERCLK_CLK_SEL_1);
});
pac::CCM.ccgr1().modify(|r| r.set_cg6(0b11));
// Disable clock during init.
//
// It is important that the PIT clock is prepared to not exceed limit (50 MHz on RT1011), or else
// you will need to recover the device with boot mode switches when using any PIT registers.
pac::PIT.mcr().modify(|w| {
w.set_mdis(true);
});
pac::PIT.timer(0).ldval().write_value(u32::MAX);
pac::PIT.timer(1).ldval().write_value(u32::MAX);
pac::PIT.timer(2).ldval().write_value(0);
pac::PIT.timer(3).ldval().write_value(0);
pac::PIT.timer(1).tctrl().write(|w| {
// In lifetime mode, timer 1 is chained to timer 0 to form a 64-bit timer.
w.set_chn(true);
w.set_ten(true);
w.set_tie(false);
});
pac::PIT.timer(0).tctrl().write(|w| {
w.set_chn(false);
w.set_ten(true);
w.set_tie(false);
});
pac::PIT.timer(2).tctrl().write(|w| {
w.set_tie(true);
});
unsafe { interrupt::PIT.enable() };
pac::PIT.mcr().write(|w| {
w.set_mdis(false);
});
}
fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
let alarm = self.alarm.borrow(cs);
alarm.set(timestamp);
let timer = pac::PIT.timer(2);
let now = self.now();
if timestamp <= now {
alarm.set(u64::MAX);
return false;
}
timer.tctrl().modify(|x| x.set_ten(false));
timer.tflg().modify(|x| x.set_tif(true));
// If the next alarm happens in more than u32::MAX cycles then the alarm will be restarted later.
timer.ldval().write_value((timestamp - now) as u32);
timer.tctrl().modify(|x| x.set_ten(true));
true
}
fn trigger_alarm(&self, cs: CriticalSection) {
let mut next = self.queue.borrow_ref_mut(cs).next_expiration(self.now());
while !self.set_alarm(cs, next) {
next = self.queue.borrow_ref_mut(cs).next_expiration(self.now());
}
}
fn on_interrupt(&self) {
critical_section::with(|cs| {
let timer = pac::PIT.timer(2);
let alarm = self.alarm.borrow(cs);
let interrupted = timer.tflg().read().tif();
timer.tflg().write(|r| r.set_tif(true));
if interrupted {
// A new load value will not apply until the next timer expiration.
//
// The expiry may be up to u32::MAX cycles away, so the timer must be restarted.
timer.tctrl().modify(|r| r.set_ten(false));
let now = self.now();
let timestamp = alarm.get();
if timestamp <= now {
self.trigger_alarm(cs);
} else {
// The alarm is not ready. Wait for u32::MAX cycles and check again or set the next alarm.
timer.ldval().write_value((timestamp - now) as u32);
timer.tctrl().modify(|r| r.set_ten(true));
}
}
});
}
}
embassy_time_driver::time_driver_impl!(static DRIVER: Driver = Driver {
alarm: Mutex::new(Cell::new(0)),
queue: Mutex::new(RefCell::new(Queue::new()))
});
pub(crate) fn init() {
DRIVER.init();
}
#[cfg(feature = "rt")]
#[interrupt]
fn PIT() {
DRIVER.on_interrupt();
}

View File

@ -57,7 +57,7 @@ embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", fe
embassy-embedded-hal = { version = "0.3.1", path = "../embassy-embedded-hal", default-features = false }
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" }
embassy-usb-synopsys-otg = { version = "0.2.0", path = "../embassy-usb-synopsys-otg" }
embassy-usb-synopsys-otg = { version = "0.3.0", path = "../embassy-usb-synopsys-otg" }
embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }

View File

@ -76,12 +76,14 @@ impl<T: Instance> SealedAdcChannel<T> for Vcore {
}
}
#[derive(Copy, Clone)]
pub enum DacChannel {
OUT1,
OUT2,
}
/// Number of samples used for averaging.
#[derive(Copy, Clone)]
pub enum Averaging {
Disabled,
Samples2,
@ -187,7 +189,7 @@ pub struct Adc4<'d, T: Instance> {
adc: crate::Peri<'d, T>,
}
#[derive(Debug)]
#[derive(Copy, Clone, Debug)]
pub enum Adc4Error {
InvalidSequence,
DMAError,

View File

@ -48,7 +48,7 @@ impl<T: Instance> SealedAdcChannel<T> for Temperature {
}
}
#[derive(Debug)]
#[derive(Copy, Clone, Debug)]
pub enum Prescaler {
NotDivided,
DividedBy2,
@ -138,6 +138,7 @@ impl<'a> defmt::Format for Prescaler {
/// Number of samples used for averaging.
/// TODO: Implement hardware averaging setting.
#[allow(unused)]
#[derive(Copy, Clone)]
pub enum Averaging {
Disabled,
Samples2,

View File

@ -17,6 +17,7 @@ pub const VDDA_CALIB_MV: u32 = 3300;
pub const ADC_MAX: u32 = (1 << 12) - 1;
pub const VREF_INT: u32 = 1230;
#[derive(Copy, Clone)]
pub enum AdcPowerMode {
AlwaysOn,
DelayOff,
@ -24,6 +25,7 @@ pub enum AdcPowerMode {
DelayIdleOff,
}
#[derive(Copy, Clone)]
pub enum Prescaler {
Div1,
Div2,

View File

@ -1,5 +1,7 @@
use cfg_if::cfg_if;
use pac::adc::vals::Dmacfg;
#[cfg(adc_v3)]
use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs};
use super::{
blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel,
@ -470,6 +472,23 @@ impl<'d, T: Instance> Adc<'d, T> {
T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
}
#[cfg(adc_v3)]
pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
}
#[cfg(adc_v3)]
pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) {
T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
}
#[cfg(adc_v3)]
pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) {
T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
}
fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
cfg_if! {
if #[cfg(any(adc_g0, adc_u0))] {

View File

@ -142,6 +142,7 @@ impl Prescaler {
}
/// Number of samples used for averaging.
#[derive(Copy, Clone)]
pub enum Averaging {
Disabled,
Samples2,

View File

@ -132,7 +132,10 @@ impl Into<Lpms> for StopMode {
fn into(self) -> Lpms {
match self {
StopMode::Stop1 => Lpms::STOP1,
#[cfg(not(stm32wba))]
StopMode::Stop2 => Lpms::STOP2,
#[cfg(stm32wba)]
StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2?
}
}
}

View File

@ -31,7 +31,7 @@ log = { version = "0.4.17", optional = true }
bitflags = "2.4.1"
cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
embassy-boot = { version = "0.4.0", path = "../embassy-boot" }
embassy-boot = { version = "0.5.0", path = "../embassy-boot" }
embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
embassy-time = { version = "0.4.0", path = "../embassy-time" }

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
## 0.5.0 - 2025-07-22
- Update `embassy-usb` to 0.5.0
## 0.4.0 - 2025-01-15
- Update `embassy-usb` to 0.4.0

View File

@ -1,6 +1,6 @@
[package]
name = "embassy-usb-logger"
version = "0.4.0"
version = "0.5.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "`log` implementation for USB serial using `embassy-usb`."

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
## 0.3.0 - 2025-07-22
- Bump `embassy-usb-driver` to v0.2.0
## 0.2.0 - 2024-12-06
- Fix corruption in CONTROL OUT transfers (and remove `quirk_setup_late_cnak`)

View File

@ -1,6 +1,6 @@
[package]
name = "embassy-usb-synopsys-otg"
version = "0.2.0"
version = "0.3.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "`embassy-usb-driver` implementation for Synopsys OTG USB controllers"

View File

@ -9,8 +9,8 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] }
embassy-nrf = { version = "0.5.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
embassy-boot = { version = "0.4.0", path = "../../../../embassy-boot", features = [] }
embassy-boot-nrf = { version = "0.5.0", path = "../../../../embassy-boot-nrf", features = [] }
embassy-boot = { version = "0.5.0", path = "../../../../embassy-boot", features = [] }
embassy-boot-nrf = { version = "0.6.0", path = "../../../../embassy-boot-nrf", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = { version = "1.0.1", optional = true }

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] }
embassy-rp = { version = "0.6.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] }
embassy-boot-rp = { version = "0.5.0", path = "../../../../embassy-boot-rp", features = [] }
embassy-boot-rp = { version = "0.6.0", path = "../../../../embassy-boot-rp", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = "1.0.1"

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32" }
embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32" }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = { version = "1.0.1", optional = true }

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] }
embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = { version = "1.0.1", optional = true }

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = { version = "1.0.1", optional = true }

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = { version = "1.0.1", optional = true }

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = { version = "1.0.1", optional = true }

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = { version = "1.0.1", optional = true }

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
embassy-usb = { version = "0.5.0", path = "../../../../embassy-usb" }
embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] }

View File

@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
defmt = { version = "1.0.1", optional = true }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55", "rt"] }
embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55", "rt", "defmt"] }
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }

View File

@ -0,0 +1,8 @@
[target.thumbv7em-none-eabihf]
runner = 'probe-rs run --chip MIMXRT1010'
[build]
target = "thumbv7em-none-eabihf" # Cortex-M7
[env]
DEFMT_LOG = "trace"

View File

@ -0,0 +1,29 @@
[package]
name = "embassy-imxrt1011-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.1"
defmt-rtt = "1.0.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-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["defmt", "mimxrt1011", "unstable-pac", "time-driver-pit"] }
embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", ] } # "defmt-timestamp-uptime" # RT1011 hard faults currently with this enabled.
embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
embedded-hal-async = "1.0.0"
imxrt-boot-gen = { version = "0.3.4", features = ["imxrt1010"] }
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
panic-semihosting = "0.6.0"
[build-dependencies]
imxrt-rt = { version = "0.1.7", features = ["device"] }
[profile.release]
debug = 2

View File

@ -0,0 +1,14 @@
use imxrt_rt::{Family, RuntimeBuilder};
fn main() {
// The IMXRT1010-EVK technically has 128M of flash, but we only ever use 8MB so that the examples
// will build fine on the Adafruit Metro M7 boards.
RuntimeBuilder::from_flexspi(Family::Imxrt1010, 8 * 1024 * 1024)
.build()
.unwrap();
println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
// Not link.x, as imxrt-rt needs to do some special things
println!("cargo:rustc-link-arg-bins=-Timxrt-link.x");
}

View File

@ -0,0 +1,48 @@
//! This example works on the following boards:
//! - IMXRT1010-EVK
//! - Adafruit Metro M7 (with microSD or with AirLift), requires an external button
//! - Makerdiary iMX RT1011 Nano Kit (TODO: currently untested, please change this)
//!
//! Although beware you will need to change the GPIO pins being used (scroll down).
#![no_std]
#![no_main]
use defmt::info;
use embassy_executor::Spawner;
use embassy_nxp::gpio::{Level, Output};
use embassy_time::Timer;
// Must include `embassy_imxrt1011_examples` to ensure the FCB gets linked.
use {defmt_rtt as _, embassy_imxrt1011_examples as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
let p = embassy_nxp::init(Default::default());
info!("Hello world!");
/* Pick the pins to use depending on your board. */
// IMXRT1010-EVK
//
// LED (D25)
let led = p.GPIO_11;
// Adafruit Metro M7 (both microSD and AirLift variants)
//
// The LED is connected to D13 on the board.
// let led = p.GPIO_03;
// Makerdiary iMX RT1011 Nano Kit
//
// LED0
// let led = p.GPIO_SD_04;
let mut led = Output::new(led, Level::Low);
loop {
Timer::after_millis(500).await;
info!("Toggle");
led.toggle();
}
}

View File

@ -0,0 +1,62 @@
//! This example works on the following boards:
//! - IMXRT1010-EVK
//! - Adafruit Metro M7 (with microSD or with AirLift), requires an external button
//! - Makerdiary iMX RT1011 Nano Kit (TODO: currently untested, please change this)
//!
//! Although beware you will need to change the GPIO pins being used (scroll down).
#![no_std]
#![no_main]
use defmt::info;
use embassy_executor::Spawner;
use embassy_nxp::gpio::{Input, Level, Output, Pull};
// Must include `embassy_imxrt1011_examples` to ensure the FCB gets linked.
use {defmt_rtt as _, embassy_imxrt1011_examples as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
let p = embassy_nxp::init(Default::default());
info!("Hello world!");
/* Pick the pins to use depending on your board. */
// IMXRT1010-EVK
//
// LED (D25) and user button (SW4)
let (led, button) = (p.GPIO_11, p.GPIO_SD_05);
// Adafruit Metro M7 (both microSD and AirLift variants)
//
// The LED is connected to D13 on the board.
//
// In particular the Metro M7 has no board user buttons, so you will need to connect a button.
// Any other GPIO pin can be used. GPIO_04 is used for example since it is on pin D12.
// let (led, button) = (p.GPIO_03, p.GPIO_04);
// Makerdiary iMX RT1011 Nano Kit
//
// LED0 and user button.
// let (led, button) = (p.GPIO_SD_04, p.GPIO_SD_03);
let mut button = Input::new(button, Pull::Up100K);
let mut led = Output::new(led, Level::Low);
led.set_high();
loop {
button.wait_for_falling_edge().await;
info!("Toggled");
led.toggle();
// The RT1010EVK has a 100 nF debouncing capacitor which results in false positive events
// when listening for a falling edge in a loop, wait for the rising edge and then wait for
// stabilization.
button.wait_for_rising_edge().await;
// Stabilization.
for _ in 0..100_000 {
cortex_m::asm::nop();
}
}
}

View File

@ -0,0 +1,75 @@
//! FlexSPI configuration block (FCB) for iMXRT1011 boards.
//!
//! This is a generic FCB that should work with most QSPI flash.
#![no_std]
use imxrt_boot_gen::flexspi;
use imxrt_boot_gen::flexspi::opcodes::sdr::*;
use imxrt_boot_gen::flexspi::{
ColumnAddressWidth, Command, DeviceModeConfiguration, FlashPadType, Instr, LookupTable, Pads,
ReadSampleClockSource, Sequence, SequenceBuilder, SerialClockFrequency, SerialFlashRegion,
WaitTimeConfigurationCommands,
};
use imxrt_boot_gen::serial_flash::nor;
/// While the IMXRT1010-EVK and Makerdiary iMX RT1011 Nano Kit have 128MBit of flash we limit to 64Mbit
/// to allow the Metro M7 boards to use the same FCB configuration.
const DENSITY_BITS: u32 = 64 * 1024 * 1024;
const DENSITY_BYTES: u32 = DENSITY_BITS / 8;
const SEQ_READ: Sequence = SequenceBuilder::new()
.instr(Instr::new(CMD, Pads::One, 0xEB))
.instr(Instr::new(RADDR, Pads::Four, 0x18))
.instr(Instr::new(DUMMY, Pads::Four, 0x06))
.instr(Instr::new(READ, Pads::Four, 0x04))
.build();
const SEQ_READ_STATUS: Sequence = SequenceBuilder::new()
.instr(Instr::new(CMD, Pads::One, 0x05))
.instr(Instr::new(READ, Pads::One, 0x01))
.build();
const SEQ_WRITE_ENABLE: Sequence = SequenceBuilder::new().instr(Instr::new(CMD, Pads::One, 0x06)).build();
const SEQ_ERASE_SECTOR: Sequence = SequenceBuilder::new()
.instr(Instr::new(CMD, Pads::One, 0x20))
.instr(Instr::new(RADDR, Pads::One, 0x18))
.build();
const SEQ_PAGE_PROGRAM: Sequence = SequenceBuilder::new()
.instr(Instr::new(CMD, Pads::One, 0x02))
.instr(Instr::new(RADDR, Pads::One, 0x18))
.instr(Instr::new(WRITE, Pads::One, 0x04))
.build();
const SEQ_CHIP_ERASE: Sequence = SequenceBuilder::new().instr(Instr::new(CMD, Pads::One, 0x60)).build();
const LUT: LookupTable = LookupTable::new()
.command(Command::Read, SEQ_READ)
.command(Command::ReadStatus, SEQ_READ_STATUS)
.command(Command::WriteEnable, SEQ_WRITE_ENABLE)
.command(Command::EraseSector, SEQ_ERASE_SECTOR)
.command(Command::PageProgram, SEQ_PAGE_PROGRAM)
.command(Command::ChipErase, SEQ_CHIP_ERASE);
const COMMON_CONFIGURATION_BLOCK: flexspi::ConfigurationBlock = flexspi::ConfigurationBlock::new(LUT)
.read_sample_clk_src(ReadSampleClockSource::LoopbackFromDQSPad)
.cs_hold_time(0x03)
.cs_setup_time(0x03)
.column_address_width(ColumnAddressWidth::OtherDevices)
.device_mode_configuration(DeviceModeConfiguration::Disabled)
.wait_time_cfg_commands(WaitTimeConfigurationCommands::disable())
.flash_size(SerialFlashRegion::A1, DENSITY_BYTES)
.serial_clk_freq(SerialClockFrequency::MHz120)
.serial_flash_pad_type(FlashPadType::Quad);
pub const SERIAL_NOR_CONFIGURATION_BLOCK: nor::ConfigurationBlock =
nor::ConfigurationBlock::new(COMMON_CONFIGURATION_BLOCK)
.page_size(256)
.sector_size(4096)
.ip_cmd_serial_clk_freq(nor::SerialClockFrequency::MHz30);
#[unsafe(no_mangle)]
#[cfg_attr(all(target_arch = "arm", target_os = "none"), link_section = ".fcb")]
pub static FLEXSPI_CONFIGURATION_BLOCK: nor::ConfigurationBlock = SERIAL_NOR_CONFIGURATION_BLOCK;

View File

@ -0,0 +1,8 @@
[target.thumbv7em-none-eabihf]
runner = 'probe-rs run --chip MIMXRT1060'
[build]
target = "thumbv7em-none-eabihf" # Cortex-M7
[env]
DEFMT_LOG = "trace"

View File

@ -0,0 +1,29 @@
[package]
name = "embassy-imxrt1062-evk-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.1"
defmt-rtt = "1.0.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-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["defmt", "mimxrt1062", "unstable-pac", "time-driver-pit"] }
embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", ] } # "defmt-timestamp-uptime"
embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
embedded-hal-async = "1.0.0"
imxrt-boot-gen = { version = "0.3.4", features = ["imxrt1060"] }
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
panic-semihosting = "0.6.0"
[build-dependencies]
imxrt-rt = { version = "0.1.7", features = ["device"] }
[profile.release]
debug = 2

View File

@ -0,0 +1,12 @@
use imxrt_rt::{Family, RuntimeBuilder};
fn main() {
RuntimeBuilder::from_flexspi(Family::Imxrt1060, 8 * 1024 * 1024)
.build()
.unwrap();
println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
// Not link.x, as imxrt-rt needs to do some special things
println!("cargo:rustc-link-arg-bins=-Timxrt-link.x");
}

View File

@ -0,0 +1,25 @@
#![no_std]
#![no_main]
use defmt::info;
use embassy_executor::Spawner;
use embassy_nxp::gpio::{Level, Output};
use embassy_time::Timer;
// Must include `embassy_imxrt1062_evk_examples` to ensure the FCB gets linked.
use {defmt_rtt as _, embassy_imxrt1062_evk_examples as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
let p = embassy_nxp::init(Default::default());
info!("Hello world!");
let led = p.GPIO_AD_B0_08;
let mut led = Output::new(led, Level::Low);
loop {
Timer::after_millis(500).await;
info!("Toggle");
led.toggle();
}
}

View File

@ -0,0 +1,36 @@
#![no_std]
#![no_main]
use defmt::info;
use embassy_executor::Spawner;
use embassy_nxp::gpio::{Input, Level, Output, Pull};
use {defmt_rtt as _, embassy_imxrt1062_evk_examples as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
let p = embassy_nxp::init(Default::default());
info!("Hello world!");
// User LED (D8)
let led = p.GPIO_AD_B0_08;
// User button (SW5)
let button = p.WAKEUP;
let mut button = Input::new(button, Pull::Up100K);
let mut led = Output::new(led, Level::Low);
led.set_high();
loop {
button.wait_for_falling_edge().await;
info!("Toggled");
led.toggle();
// Software debounce.
button.wait_for_rising_edge().await;
// Stabilization.
for _ in 0..100_000 {
cortex_m::asm::nop();
}
}
}

View File

@ -0,0 +1,60 @@
//! FlexSPI configuration block (FCB) for the iMXRT1060-EVK
//!
//! This uses IS25WP QuadSPI flash.
#![no_std]
use imxrt_boot_gen::flexspi::opcodes::sdr::*;
use imxrt_boot_gen::flexspi::{self, FlashPadType, ReadSampleClockSource, SerialClockFrequency, SerialFlashRegion, *};
use imxrt_boot_gen::serial_flash::*;
pub use nor::ConfigurationBlock;
const SEQ_READ: Sequence = SequenceBuilder::new()
.instr(Instr::new(CMD, Pads::One, 0xEB))
.instr(Instr::new(RADDR, Pads::Four, 0x18))
.instr(Instr::new(DUMMY, Pads::Four, 0x06))
.instr(Instr::new(READ, Pads::Four, 0x04))
.build();
const SEQ_READ_STATUS: Sequence = SequenceBuilder::new()
.instr(Instr::new(CMD, Pads::One, 0x05))
.instr(Instr::new(READ, Pads::One, 0x04))
.build();
const SEQ_WRITE_ENABLE: Sequence = SequenceBuilder::new().instr(Instr::new(CMD, Pads::One, 0x06)).build();
const SEQ_ERASE_SECTOR: Sequence = SequenceBuilder::new()
.instr(Instr::new(CMD, Pads::One, 0x20))
.instr(Instr::new(RADDR, Pads::One, 0x18))
.build();
const SEQ_PAGE_PROGRAM: Sequence = SequenceBuilder::new()
.instr(Instr::new(CMD, Pads::One, 0x02))
.instr(Instr::new(RADDR, Pads::One, 0x18))
.instr(Instr::new(WRITE, Pads::One, 0x04))
.build();
const SEQ_CHIP_ERASE: Sequence = SequenceBuilder::new().instr(Instr::new(CMD, Pads::One, 0x60)).build();
const LUT: LookupTable = LookupTable::new()
.command(Command::Read, SEQ_READ)
.command(Command::ReadStatus, SEQ_READ_STATUS)
.command(Command::WriteEnable, SEQ_WRITE_ENABLE)
.command(Command::EraseSector, SEQ_ERASE_SECTOR)
.command(Command::PageProgram, SEQ_PAGE_PROGRAM)
.command(Command::ChipErase, SEQ_CHIP_ERASE);
const COMMON_CONFIGURATION_BLOCK: flexspi::ConfigurationBlock = flexspi::ConfigurationBlock::new(LUT)
.version(Version::new(1, 4, 0))
.read_sample_clk_src(ReadSampleClockSource::LoopbackFromDQSPad)
.cs_hold_time(3)
.cs_setup_time(3)
.controller_misc_options(0x10)
.serial_flash_pad_type(FlashPadType::Quad)
.serial_clk_freq(SerialClockFrequency::MHz133)
.flash_size(SerialFlashRegion::A1, 8 * 1024 * 1024);
pub const SERIAL_NOR_CONFIGURATION_BLOCK: nor::ConfigurationBlock =
nor::ConfigurationBlock::new(COMMON_CONFIGURATION_BLOCK)
.page_size(256)
.sector_size(4096)
.ip_cmd_serial_clk_freq(nor::SerialClockFrequency::MHz30);
#[no_mangle]
#[cfg_attr(all(target_arch = "arm", target_os = "none"), link_section = ".fcb")]
pub static FLEXSPI_CONFIGURATION_BLOCK: nor::ConfigurationBlock = SERIAL_NOR_CONFIGURATION_BLOCK;

View File

@ -17,5 +17,7 @@ defmt-rtt = "1.0.0"
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
panic-semihosting = "0.6.0"
embedded-io-async = "0.6.1"
[profile.release]
debug = 2

View File

@ -15,7 +15,7 @@ embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defm
embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] }
embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" }
embassy-usb-logger = { version = "0.5.0", path = "../../embassy-usb-logger" }
cyw43 = { version = "0.4.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] }
cyw43-pio = { version = "0.5.1", path = "../../cyw43-pio", features = ["defmt"] }

View File

@ -15,7 +15,7 @@ embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defm
embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] }
embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" }
embassy-usb-logger = { version = "0.5.0", path = "../../embassy-usb-logger" }
cyw43 = { version = "0.4.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] }
cyw43-pio = { version = "0.5.1", path = "../../cyw43-pio", features = ["defmt"] }

View File

@ -13,6 +13,7 @@ teleprobe-meta = "1.1"
embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = [ "defmt" ] }
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt" ] }
embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [ "rt", "defmt", "unstable-pac", "time-driver-any" ] }
embassy-embedded-hal = { version = "0.3.1", path = "../../embassy-embedded-hal/"}
@ -24,6 +25,8 @@ cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-sin
cortex-m-rt = "0.7.0"
embedded-hal = { package = "embedded-hal", version = "1.0" }
embedded-hal-async = { version = "1.0" }
embedded-io = { version = "0.6.1", features = ["defmt-03"] }
embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
static_cell = "2"
portable-atomic = { version = "1.5", features = ["critical-section"] }

View File

@ -0,0 +1,115 @@
#![no_std]
#![no_main]
#[cfg(feature = "mspm0g3507")]
teleprobe_meta::target!(b"lp-mspm0g3507");
use defmt::{assert_eq, unwrap, *};
use embassy_executor::Spawner;
use embassy_mspm0::uart::{BufferedInterruptHandler, BufferedUart, Config};
use embassy_mspm0::{bind_interrupts, peripherals};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
UART1 => BufferedInterruptHandler<peripherals::UART1>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_mspm0::init(Default::default());
info!("Hello World!");
// TODO: Allow creating a looped-back UART (so pins are not needed).
// Do not select default UART since the virtual COM port is attached to UART0.
#[cfg(any(feature = "mspm0g3507"))]
let (mut tx, mut rx, mut uart) = (p.PA8, p.PA9, p.UART1);
{
use embedded_io_async::{Read, Write};
let mut config = Config::default();
config.loop_back_enable = true;
config.fifo_enable = false;
let tx_buf = &mut [0u8; 16];
let rx_buf = &mut [0u8; 16];
let mut uart = unwrap!(BufferedUart::new(
uart.reborrow(),
tx.reborrow(),
rx.reborrow(),
Irqs,
tx_buf,
rx_buf,
config
));
let mut buf = [0; 16];
for (j, b) in buf.iter_mut().enumerate() {
*b = j as u8;
}
unwrap!(uart.write_all(&buf).await);
unwrap!(uart.flush().await);
unwrap!(uart.read_exact(&mut buf).await);
for (j, b) in buf.iter().enumerate() {
assert_eq!(*b, j as u8);
}
// Buffer is unclogged, should be able to write again.
unwrap!(uart.write_all(&buf).await);
unwrap!(uart.flush().await);
unwrap!(uart.read_exact(&mut buf).await);
for (j, b) in buf.iter().enumerate() {
assert_eq!(*b, j as u8);
}
}
info!("Blocking buffered");
{
use embedded_io::{Read, Write};
let mut config = Config::default();
config.loop_back_enable = true;
config.fifo_enable = false;
let tx_buf = &mut [0u8; 16];
let rx_buf = &mut [0u8; 16];
let mut uart = unwrap!(BufferedUart::new(
uart.reborrow(),
tx.reborrow(),
rx.reborrow(),
Irqs,
tx_buf,
rx_buf,
config
));
let mut buf = [0; 16];
for (j, b) in buf.iter_mut().enumerate() {
*b = j as u8;
}
unwrap!(uart.write_all(&buf));
unwrap!(uart.blocking_flush());
unwrap!(uart.read_exact(&mut buf));
for (j, b) in buf.iter().enumerate() {
assert_eq!(*b, j as u8);
}
// Buffer is unclogged, should be able to write again.
unwrap!(uart.write_all(&buf));
unwrap!(uart.blocking_flush());
unwrap!(uart.read_exact(&mut buf));
for (j, b) in buf.iter().enumerate() {
assert_eq!(*b, j as u8, "at {}", j);
}
}
info!("Test OK");
cortex_m::asm::bkpt();
}