mspm0: blocking uart driver

This commit is contained in:
i509VCB 2025-03-22 17:52:13 -05:00
parent 954d1554d4
commit 91cde689cc
No known key found for this signature in database
GPG Key ID: 3E860D038915EF88
16 changed files with 1355 additions and 10 deletions

View File

@ -39,6 +39,7 @@ embedded-hal = { version = "1.0" }
embedded-hal-async = { version = "1.0" }
defmt = { version = "0.3", optional = true }
fixed = "1.29"
log = { version = "0.4.14", optional = true }
cortex-m-rt = ">=0.6.15,<0.8"
cortex-m = "0.7.6"

View File

@ -381,7 +381,7 @@ fn generate_peripheral_instances() -> TokenStream {
// Will be filled in when uart implementation is finished
let _ = peri;
let tokens = match peripheral.kind {
// "uart" => Some(quote! { impl_uart_instance!(#peri); }),
"uart" => Some(quote! { impl_uart_instance!(#peri); }),
_ => None,
};
@ -412,10 +412,10 @@ fn generate_pin_trait_impls() -> TokenStream {
let _ = pf;
let tokens = match key {
// ("uart", "TX") => Some(quote! { impl_uart_tx_pin!(#peri, #pin_name, #pf); }),
// ("uart", "RX") => Some(quote! { impl_uart_rx_pin!(#peri, #pin_name, #pf); }),
// ("uart", "CTS") => Some(quote! { impl_uart_cts_pin!(#peri, #pin_name, #pf); }),
// ("uart", "RTS") => Some(quote! { impl_uart_rts_pin!(#peri, #pin_name, #pf); }),
("uart", "TX") => Some(quote! { impl_uart_tx_pin!(#peri, #pin_name, #pf); }),
("uart", "RX") => Some(quote! { impl_uart_rx_pin!(#peri, #pin_name, #pf); }),
("uart", "CTS") => Some(quote! { impl_uart_cts_pin!(#peri, #pin_name, #pf); }),
("uart", "RTS") => Some(quote! { impl_uart_rts_pin!(#peri, #pin_name, #pf); }),
_ => None,
};

View File

@ -836,6 +836,31 @@ impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> {
}
}
#[derive(Copy, Clone)]
pub struct PfType {
pull: Pull,
input: bool,
invert: bool,
}
impl PfType {
pub const fn input(pull: Pull, invert: bool) -> Self {
Self {
pull,
input: true,
invert,
}
}
pub const fn output(pull: Pull, invert: bool) -> Self {
Self {
pull,
input: false,
invert,
}
}
}
/// The pin function to disconnect peripherals from the pin.
///
/// This is also the pin function used to connect to analog peripherals, such as an ADC.
@ -907,6 +932,40 @@ pub(crate) trait SealedPin {
(self.pin_port() % 32) as usize
}
#[inline]
fn set_as_analog(&self) {
let pincm = pac::IOMUX.pincm(self._pin_cm() as usize);
pincm.modify(|w| {
w.set_pf(DISCONNECT_PF);
w.set_pipu(false);
w.set_pipd(false);
});
}
fn update_pf(&self, ty: PfType) {
let pincm = pac::IOMUX.pincm(self._pin_cm() as usize);
let pf = pincm.read().pf();
set_pf(self._pin_cm() as usize, pf, ty);
}
fn set_as_pf(&self, pf: u8, ty: PfType) {
set_pf(self._pin_cm() as usize, pf, ty)
}
/// 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 internal weak pull-up and pull-down resistors.
#[inline]
fn set_as_disconnected(&self) {
self.set_as_analog();
}
#[inline]
fn block(&self) -> gpio::Gpio {
match self.pin_port() / 32 {
@ -920,6 +979,18 @@ pub(crate) trait SealedPin {
}
}
#[inline(never)]
fn set_pf(pincm: usize, pf: u8, ty: PfType) {
pac::IOMUX.pincm(pincm).modify(|w| {
w.set_pf(pf);
w.set_pc(true);
w.set_pipu(ty.pull == Pull::Up);
w.set_pipd(ty.pull == Pull::Down);
w.set_inena(ty.input);
w.set_inv(ty.invert);
});
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct InputFuture<'d> {
pin: Peri<'d, AnyPin>,

View File

@ -5,8 +5,12 @@
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;
// This must be declared early as well for
mod macros;
pub mod gpio;
pub mod timer;
pub mod uart;
/// Operating modes for peripherals.
pub mod mode {

View File

@ -0,0 +1,9 @@
#![macro_use]
macro_rules! new_pin {
($name: ident, $pf_type: expr) => {{
let pin = $name;
pin.set_as_pf(pin.pf_num(), $pf_type);
Some(pin.into())
}};
}

1085
embassy-mspm0/src/uart.rs Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,35 @@
//! Example of using blocking uart
//!
//! This uses the virtual COM port provided on the LP-MSPM0C1104 board.
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_mspm0::uart::{Config, Uart};
use {defmt_rtt as _, panic_halt as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
info!("Hello world!");
let p = embassy_mspm0::init(Default::default());
let instance = p.UART0;
let tx = p.PA27;
let rx = p.PA26;
let config = Config::default();
let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
info!("wrote Hello, starting echo");
let mut buf = [0u8; 1];
loop {
unwrap!(uart.blocking_read(&mut buf));
unwrap!(uart.blocking_write(&buf));
}
}

View File

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

View File

@ -0,0 +1,35 @@
//! Example of using blocking uart
//!
//! This uses the virtual COM port provided on the LP-MSPM0G3507 board.
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_mspm0::uart::{Config, Uart};
use {defmt_rtt as _, panic_halt as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
info!("Hello world!");
let p = embassy_mspm0::init(Default::default());
let instance = p.UART0;
let tx = p.PA10;
let rx = p.PA11;
let config = Config::default();
let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
info!("wrote Hello, starting echo");
let mut buf = [0u8; 1];
loop {
unwrap!(uart.blocking_read(&mut buf));
unwrap!(uart.blocking_write(&buf));
}
}

View File

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

View File

@ -0,0 +1,35 @@
//! Example of using blocking uart
//!
//! This uses the virtual COM port provided on the LP-MSPM0G3519 board.
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_mspm0::uart::{Config, Uart};
use {defmt_rtt as _, panic_halt as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
info!("Hello world!");
let p = embassy_mspm0::init(Default::default());
let instance = p.UART0;
let tx = p.PA10;
let rx = p.PA11;
let config = Config::default();
let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
info!("wrote Hello, starting echo");
let mut buf = [0u8; 1];
loop {
unwrap!(uart.blocking_read(&mut buf));
unwrap!(uart.blocking_write(&buf));
}
}

View File

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

View File

@ -0,0 +1,35 @@
//! Example of using blocking uart
//!
//! This uses the virtual COM port provided on the LP-MSPM0L1306 board.
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_mspm0::uart::{Config, Uart};
use {defmt_rtt as _, panic_halt as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
info!("Hello world!");
let p = embassy_mspm0::init(Default::default());
let instance = p.UART0;
let tx = p.PA8;
let rx = p.PA9;
let config = Config::default();
let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
info!("wrote Hello, starting echo");
let mut buf = [0u8; 1];
loop {
unwrap!(uart.blocking_read(&mut buf));
unwrap!(uart.blocking_write(&buf));
}
}

View File

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

View File

@ -0,0 +1,35 @@
//! Example of using blocking uart
//!
//! This uses the virtual COM port provided on the LP-MSPM0L2228 board.
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_mspm0::uart::{Config, Uart};
use {defmt_rtt as _, panic_halt as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
info!("Hello world!");
let p = embassy_mspm0::init(Default::default());
let instance = p.UART0;
let tx = p.PA10;
let rx = p.PA11;
let config = Config::default();
let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config));
unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n"));
info!("wrote Hello, starting echo");
let mut buf = [0u8; 1];
loop {
unwrap!(uart.blocking_read(&mut buf));
unwrap!(uart.blocking_write(&buf));
}
}