aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-11-14 18:43:27 +0100
committerJames Munns <[email protected]>2025-11-14 18:43:27 +0100
commit8cdccae3c6c4a805cf5003b1a859734c105d76e8 (patch)
tree7c605a58aa7e124bbed658dfc5f6822a25a83e98
parente799d6c8956ed3ea5ced65d58c3065a22927ad10 (diff)
Continue working on examples
-rw-r--r--Cargo.toml3
-rw-r--r--examples/adc_interrupt.rs29
-rw-r--r--examples/adc_polling.rs30
-rw-r--r--examples/blink.rs4
-rw-r--r--examples/hello.rs33
-rw-r--r--examples/lpuart_buffered.rs9
-rw-r--r--examples/lpuart_polling.rs11
-rw-r--r--examples/ostimer_alarm.rs32
-rw-r--r--examples/ostimer_async.rs29
-rw-r--r--examples/ostimer_counter.rs26
-rw-r--r--examples/ostimer_race_test.rs71
-rw-r--r--examples/rtc_alarm.rs28
-rw-r--r--examples/uart_interrupt.rs69
-rw-r--r--src/lib.rs2
-rw-r--r--src/lpuart/mod.rs20
-rw-r--r--src/ostimer.rs10
-rw-r--r--src/rtc.rs32
-rw-r--r--src/uart.rs316
18 files changed, 248 insertions, 506 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 19d1c7174..259becfe8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -58,9 +58,6 @@ name = "hello"
58name = "blink" 58name = "blink"
59 59
60[[example]] 60[[example]]
61name = "uart_interrupt"
62
63[[example]]
64name = "ostimer_alarm" 61name = "ostimer_alarm"
65 62
66[[example]] 63[[example]]
diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs
index 3be85ac75..536152539 100644
--- a/examples/adc_interrupt.rs
+++ b/examples/adc_interrupt.rs
@@ -4,13 +4,13 @@
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4}; 5use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4};
6use embassy_mcxa276::clocks::PoweredClock; 6use embassy_mcxa276::clocks::PoweredClock;
7use embassy_mcxa276::lpuart::{Config, Lpuart};
7use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; 8use hal::adc::{LpadcConfig, TriggerPriorityPolicy};
8use hal::uart;
9use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; 9use mcxa_pac::adc1::cfg::{Pwrsel, Refsel};
10use mcxa_pac::adc1::cmdl1::{Adch, Mode}; 10use mcxa_pac::adc1::cmdl1::{Adch, Mode};
11use mcxa_pac::adc1::ctrl::CalAvgs; 11use mcxa_pac::adc1::ctrl::CalAvgs;
12use mcxa_pac::adc1::tctrl::Tcmd; 12use mcxa_pac::adc1::tctrl::Tcmd;
13use {cortex_m, embassy_mcxa276 as hal}; 13use {embassy_mcxa276 as hal};
14mod common; 14mod common;
15 15
16use hal::{bind_interrupts, InterruptExt}; 16use hal::{bind_interrupts, InterruptExt};
@@ -28,14 +28,25 @@ static KEEP_ADC: unsafe extern "C" fn() = ADC1;
28async fn main(_spawner: Spawner) { 28async fn main(_spawner: Spawner) {
29 let p = hal::init(hal::config::Config::default()); 29 let p = hal::init(hal::config::Config::default());
30 30
31 // Create UART configuration
32 let config = Config {
33 baudrate_bps: 115_200,
34 enable_tx: true,
35 enable_rx: true,
36 ..Default::default()
37 };
38
39 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
31 unsafe { 40 unsafe {
32 common::init_uart2(hal::pac()); 41 common::init_uart2(hal::pac());
33 } 42 }
34 43 let mut uart = Lpuart::new_blocking(
35 // let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 44 p.LPUART2, // Peripheral
36 // let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 45 p.PIO2_2, // TX pin
37 46 p.PIO2_3, // RX pin
38 // uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); 47 config,
48 )
49 .unwrap();
39 50
40 unsafe { 51 unsafe {
41 common::init_adc(hal::pac()); 52 common::init_adc(hal::pac());
@@ -71,7 +82,7 @@ async fn main(_spawner: Spawner) {
71 conv_trigger_config.enable_hardware_trigger = false; 82 conv_trigger_config.enable_hardware_trigger = false;
72 adc.set_conv_trigger_config(0, &conv_trigger_config); 83 adc.set_conv_trigger_config(0, &conv_trigger_config);
73 84
74 // uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); 85 uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n");
75 86
76 adc.enable_interrupt(0x1); 87 adc.enable_interrupt(0x1);
77 88
@@ -88,7 +99,7 @@ async fn main(_spawner: Spawner) {
88 while !adc.is_interrupt_triggered() { 99 while !adc.is_interrupt_triggered() {
89 // Wait until the interrupt is triggered 100 // Wait until the interrupt is triggered
90 } 101 }
91 // uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); 102 uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n");
92 //TBD need to print the value 103 //TBD need to print the value
93 } 104 }
94} 105}
diff --git a/examples/adc_polling.rs b/examples/adc_polling.rs
index 4b5f9422d..2fe4153db 100644
--- a/examples/adc_polling.rs
+++ b/examples/adc_polling.rs
@@ -2,9 +2,11 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4};
6use embassy_mcxa276::clocks::PoweredClock;
7use embassy_mcxa276::lpuart::{Config, Lpuart};
5use embassy_mcxa276 as hal; 8use embassy_mcxa276 as hal;
6use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; 9use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy};
7use hal::uart;
8use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; 10use mcxa_pac::adc1::cfg::{Pwrsel, Refsel};
9use mcxa_pac::adc1::cmdl1::{Adch, Mode}; 11use mcxa_pac::adc1::cmdl1::{Adch, Mode};
10use mcxa_pac::adc1::ctrl::CalAvgs; 12use mcxa_pac::adc1::ctrl::CalAvgs;
@@ -27,10 +29,27 @@ async fn main(_spawner: Spawner) {
27 common::init_uart2(hal::pac()); 29 common::init_uart2(hal::pac());
28 } 30 }
29 31
30 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 32 // Create UART configuration
31 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 33 let config = Config {
34 baudrate_bps: 115_200,
35 enable_tx: true,
36 enable_rx: true,
37 ..Default::default()
38 };
39
40 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
41 unsafe {
42 common::init_uart2(hal::pac());
43 }
44 let mut uart = Lpuart::new_blocking(
45 p.LPUART2, // Peripheral
46 p.PIO2_2, // TX pin
47 p.PIO2_3, // RX pin
48 config,
49 )
50 .unwrap();
32 51
33 uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); 52 uart.blocking_write(b"\r\n=== ADC polling Example ===\r\n").unwrap();
34 53
35 unsafe { 54 unsafe {
36 common::init_adc(hal::pac()); 55 common::init_adc(hal::pac());
@@ -47,6 +66,9 @@ async fn main(_spawner: Spawner) {
47 enable_conv_pause: false, 66 enable_conv_pause: false,
48 conv_pause_delay: 0, 67 conv_pause_delay: 0,
49 fifo_watermark: 0, 68 fifo_watermark: 0,
69 power: PoweredClock::NormalEnabledDeepSleepDisabled,
70 source: AdcClockSel::FroLfDiv,
71 div: Div4::no_div(),
50 }; 72 };
51 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); 73 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config);
52 74
diff --git a/examples/blink.rs b/examples/blink.rs
index 564353d5c..0f489abb9 100644
--- a/examples/blink.rs
+++ b/examples/blink.rs
@@ -28,10 +28,6 @@ async fn main(_spawner: Spawner) {
28 unsafe { 28 unsafe {
29 common::init_led(hal::pac()); 29 common::init_led(hal::pac());
30 } 30 }
31 // Initialize OSTIMER for async timing
32 unsafe {
33 common::init_ostimer0(hal::pac());
34 }
35 31
36 // Initialize embassy-time global driver backed by OSTIMER0 32 // Initialize embassy-time global driver backed by OSTIMER0
37 hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); 33 hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000);
diff --git a/examples/hello.rs b/examples/hello.rs
index e39adaced..dbb53fdcf 100644
--- a/examples/hello.rs
+++ b/examples/hello.rs
@@ -2,15 +2,14 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa276 as hal; 5use embassy_mcxa276::{self as hal, lpuart::{Blocking, Config, Lpuart}};
6use hal::uart;
7 6
8mod common; 7mod common;
9 8
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
11 10
12/// Simple helper to write a byte as hex to UART 11/// Simple helper to write a byte as hex to UART
13fn write_hex_byte(uart: &hal::uart::Uart<hal::uart::Lpuart2>, byte: u8) { 12fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) {
14 const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; 13 const HEX_DIGITS: &[u8] = b"0123456789ABCDEF";
15 uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); 14 uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]);
16 uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); 15 uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]);
@@ -22,15 +21,25 @@ async fn main(_spawner: Spawner) {
22 21
23 defmt::info!("boot"); 22 defmt::info!("boot");
24 23
25 // Board-level init for UART2 clocks and pins. 24 // Create UART configuration
25 let config = Config {
26 baudrate_bps: 115_200,
27 enable_tx: true,
28 enable_rx: true,
29 ..Default::default()
30 };
31
32 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
26 unsafe { 33 unsafe {
27 common::init_uart2(hal::pac()); 34 common::init_uart2(hal::pac());
28 } 35 }
29 36 let mut uart = Lpuart::new_blocking(
30 // Get UART source frequency from clock configuration 37 p.LPUART2, // Peripheral
31 // Using hardcoded frequency for now - dynamic detection may have issues 38 p.PIO2_2, // TX pin
32 let src = 12_000_000; // FRO_LF_DIV at 12MHz with DIV=0 39 p.PIO2_3, // RX pin
33 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 40 config,
41 )
42 .unwrap();
34 43
35 // Print welcome message before any async delays to guarantee early console output 44 // Print welcome message before any async delays to guarantee early console output
36 uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); 45 uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n");
@@ -69,12 +78,12 @@ async fn main(_spawner: Spawner) {
69 let num_str = &command[4..]; 78 let num_str = &command[4..];
70 if let Ok(num) = parse_u8(num_str) { 79 if let Ok(num) = parse_u8(num_str) {
71 uart.write_str_blocking("Hex: 0x"); 80 uart.write_str_blocking("Hex: 0x");
72 write_hex_byte(&uart, num); 81 write_hex_byte(&mut uart, num);
73 uart.write_str_blocking("\r\n"); 82 uart.write_str_blocking("\r\n");
74 } else { 83 } else {
75 uart.write_str_blocking("Invalid number for hex command\r\n"); 84 uart.write_str_blocking("Invalid number for hex command\r\n");
76 } 85 }
77 } else if command.len() > 0 { 86 } else if !command.is_empty() {
78 uart.write_str_blocking("Unknown command: "); 87 uart.write_str_blocking("Unknown command: ");
79 uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); 88 uart.write_str_blocking(core::str::from_utf8(command).unwrap_or(""));
80 uart.write_str_blocking("\r\n"); 89 uart.write_str_blocking("\r\n");
@@ -103,7 +112,7 @@ async fn main(_spawner: Spawner) {
103fn parse_u8(bytes: &[u8]) -> Result<u8, ()> { 112fn parse_u8(bytes: &[u8]) -> Result<u8, ()> {
104 let mut result = 0u8; 113 let mut result = 0u8;
105 for &b in bytes { 114 for &b in bytes {
106 if b >= b'0' && b <= b'9' { 115 if b.is_ascii_digit() {
107 result = result.checked_mul(10).ok_or(())?; 116 result = result.checked_mul(10).ok_or(())?;
108 result = result.checked_add(b - b'0').ok_or(())?; 117 result = result.checked_add(b - b'0').ok_or(())?;
109 } else { 118 } else {
diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs
index 6ae690c56..9e297ca67 100644
--- a/examples/lpuart_buffered.rs
+++ b/examples/lpuart_buffered.rs
@@ -22,7 +22,7 @@ unsafe extern "C" fn lpuart2_handler() {
22 22
23#[embassy_executor::main] 23#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
25 let _p = hal::init(hal::config::Config::default()); 25 let p = hal::init(hal::config::Config::default());
26 26
27 unsafe { 27 unsafe {
28 hal::interrupt::install_irq_handler(mcxa_pac::Interrupt::LPUART2, lpuart2_handler); 28 hal::interrupt::install_irq_handler(mcxa_pac::Interrupt::LPUART2, lpuart2_handler);
@@ -33,7 +33,6 @@ async fn main(_spawner: Spawner) {
33 33
34 unsafe { 34 unsafe {
35 common::init_uart2(hal::pac()); 35 common::init_uart2(hal::pac());
36 common::init_ostimer0(hal::pac());
37 } 36 }
38 37
39 // UART configuration (enable both TX and RX) 38 // UART configuration (enable both TX and RX)
@@ -51,9 +50,9 @@ async fn main(_spawner: Spawner) {
51 50
52 // Create a buffered LPUART2 instance with both TX and RX 51 // Create a buffered LPUART2 instance with both TX and RX
53 let mut uart = BufferedLpuart::new( 52 let mut uart = BufferedLpuart::new(
54 p2.LPUART2, 53 p.LPUART2,
55 p2.PIO2_2, // TX pin 54 p.PIO2_2, // TX pin
56 p2.PIO2_3, // RX pin 55 p.PIO2_3, // RX pin
57 Irqs, 56 Irqs,
58 &mut tx_buf, 57 &mut tx_buf,
59 &mut rx_buf, 58 &mut rx_buf,
diff --git a/examples/lpuart_polling.rs b/examples/lpuart_polling.rs
index 067c7eb53..c9630dca5 100644
--- a/examples/lpuart_polling.rs
+++ b/examples/lpuart_polling.rs
@@ -4,14 +4,13 @@
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; 5use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _};
6 6
7use crate::hal::lpuart::{lib, Config, Lpuart}; 7use crate::hal::lpuart::{Config, Lpuart};
8 8
9mod common; 9mod common;
10 10
11#[embassy_executor::main] 11#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
13 let _p = hal::init(hal::config::Config::default()); 13 let p = hal::init(hal::config::Config::default());
14 let p2 = lib::init();
15 14
16 defmt::info!("boot"); 15 defmt::info!("boot");
17 16
@@ -30,9 +29,9 @@ async fn main(_spawner: Spawner) {
30 29
31 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX 30 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
32 let lpuart = Lpuart::new_blocking( 31 let lpuart = Lpuart::new_blocking(
33 p2.LPUART2, // Peripheral 32 p.LPUART2, // Peripheral
34 p2.PIO2_2, // TX pin 33 p.PIO2_2, // TX pin
35 p2.PIO2_3, // RX pin 34 p.PIO2_3, // RX pin
36 config, 35 config,
37 ) 36 )
38 .unwrap(); 37 .unwrap();
diff --git a/examples/ostimer_alarm.rs b/examples/ostimer_alarm.rs
index 4f29a2c7c..f3a84d312 100644
--- a/examples/ostimer_alarm.rs
+++ b/examples/ostimer_alarm.rs
@@ -4,12 +4,15 @@
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, Ordering};
5 5
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use hal::uart; 7use embassy_mcxa276 as hal;
8use {cortex_m, embassy_mcxa276 as hal};
9 8
10mod common; 9mod common;
11 10
12use embassy_mcxa276::{bind_interrupts, clocks::{periph_helpers::OstimerClockSel, PoweredClock}}; 11use embassy_mcxa276::{
12 bind_interrupts,
13 clocks::{periph_helpers::OstimerClockSel, PoweredClock},
14 lpuart::{Config, Lpuart},
15};
13use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
14 17
15// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. 18// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed.
@@ -33,15 +36,26 @@ fn alarm_callback() {
33async fn main(_spawner: Spawner) { 36async fn main(_spawner: Spawner) {
34 let p = hal::init(hal::config::Config::default()); 37 let p = hal::init(hal::config::Config::default());
35 38
36 // Enable/clock OSTIMER0 and UART2 before touching their registers 39 // Create UART configuration
37 unsafe { 40 let config = Config {
38 common::init_ostimer0(hal::pac()); 41 baudrate_bps: 115_200,
39 } 42 enable_tx: true,
43 enable_rx: true,
44 ..Default::default()
45 };
46
47 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
40 unsafe { 48 unsafe {
41 common::init_uart2(hal::pac()); 49 common::init_uart2(hal::pac());
42 } 50 }
43 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 51 let mut uart = Lpuart::new_blocking(
44 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 52 p.LPUART2, // Peripheral
53 p.PIO2_2, // TX pin
54 p.PIO2_3, // RX pin
55 config,
56 )
57 .unwrap();
58
45 uart.write_str_blocking("OSTIMER Alarm Example\n"); 59 uart.write_str_blocking("OSTIMER Alarm Example\n");
46 60
47 // Initialize embassy-time global driver backed by OSTIMER0 61 // Initialize embassy-time global driver backed by OSTIMER0
diff --git a/examples/ostimer_async.rs b/examples/ostimer_async.rs
index 27e14e022..2642a633d 100644
--- a/examples/ostimer_async.rs
+++ b/examples/ostimer_async.rs
@@ -2,8 +2,7 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa276 as hal; 5use embassy_mcxa276::{self as hal, lpuart::{Config, Lpuart}};
6use hal::uart;
7 6
8mod common; 7mod common;
9 8
@@ -22,18 +21,28 @@ static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT;
22 21
23#[embassy_executor::main] 22#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
25 let _p = hal::init(hal::config::Config::default()); 24 let p = hal::init(hal::config::Config::default());
26 25
27 // Enable/clock OSTIMER0 and UART2 before touching their registers 26 // Create UART configuration
28 unsafe { 27 let config = Config {
29 common::init_ostimer0(hal::pac()); 28 baudrate_bps: 115_200,
30 } 29 enable_tx: true,
30 enable_rx: true,
31 ..Default::default()
32 };
33
34 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
31 unsafe { 35 unsafe {
32 common::init_uart2(hal::pac()); 36 common::init_uart2(hal::pac());
33 } 37 }
34 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 38 let mut uart = Lpuart::new_blocking(
35 let uart = uart::Uart::<uart::Lpuart2>::new(_p.LPUART2, uart::Config::new(src)); 39 p.LPUART2, // Peripheral
36 uart.write_str_blocking("boot\n"); 40 p.PIO2_2, // TX pin
41 p.PIO2_3, // RX pin
42 config,
43 )
44 .unwrap();
45 uart.blocking_write(b"boot\n").unwrap();
37 46
38 // Avoid mass NVIC writes here; DefaultHandler now safely returns. 47 // Avoid mass NVIC writes here; DefaultHandler now safely returns.
39 48
diff --git a/examples/ostimer_counter.rs b/examples/ostimer_counter.rs
index 069e879d8..590c5a14b 100644
--- a/examples/ostimer_counter.rs
+++ b/examples/ostimer_counter.rs
@@ -7,7 +7,10 @@
7#![no_main] 7#![no_main]
8 8
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_mcxa276::clocks::{periph_helpers::OstimerClockSel, PoweredClock}; 10use embassy_mcxa276::{
11 clocks::{periph_helpers::OstimerClockSel, PoweredClock},
12 lpuart::{Blocking, Config, Lpuart},
13};
11use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
12use hal::bind_interrupts; 15use hal::bind_interrupts;
13use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; 16use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _};
@@ -22,12 +25,25 @@ bind_interrupts!(struct Irqs {
22async fn main(_spawner: Spawner) { 25async fn main(_spawner: Spawner) {
23 let p = hal::init(Default::default()); 26 let p = hal::init(Default::default());
24 27
25 // Enable/clock OSTIMER0 and UART2 before touching their registers 28 // Create UART configuration
29 let config = Config {
30 baudrate_bps: 115_200,
31 enable_tx: true,
32 enable_rx: true,
33 ..Default::default()
34 };
35
36 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
26 unsafe { 37 unsafe {
27 common::init_uart2(hal::pac()); 38 common::init_uart2(hal::pac());
28 } 39 }
29 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 40 let mut uart = Lpuart::new_blocking(
30 let mut uart = hal::uart::Uart::<hal::uart::Lpuart2>::new(p.LPUART2, hal::uart::Config::new(src)); 41 p.LPUART2, // Peripheral
42 p.PIO2_2, // TX pin
43 p.PIO2_3, // RX pin
44 config,
45 )
46 .unwrap();
31 47
32 uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); 48 uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n");
33 49
@@ -90,7 +106,7 @@ async fn main(_spawner: Spawner) {
90} 106}
91 107
92// Helper function to write a u64 value as decimal string 108// Helper function to write a u64 value as decimal string
93fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) { 109fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) {
94 if value == 0 { 110 if value == 0 {
95 uart.write_str_blocking("0"); 111 uart.write_str_blocking("0");
96 return; 112 return;
diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs
index 6e3d4ac21..131d10f64 100644
--- a/examples/ostimer_race_test.rs
+++ b/examples/ostimer_race_test.rs
@@ -12,7 +12,10 @@
12use core::sync::atomic::{AtomicU32, Ordering}; 12use core::sync::atomic::{AtomicU32, Ordering};
13 13
14use embassy_executor::Spawner; 14use embassy_executor::Spawner;
15use embassy_mcxa276::clocks::{periph_helpers::OstimerClockSel, PoweredClock}; 15use embassy_mcxa276::{
16 clocks::{periph_helpers::OstimerClockSel, PoweredClock},
17 lpuart::{Blocking, Config, Lpuart},
18};
16use embassy_time::{Duration, Timer}; 19use embassy_time::{Duration, Timer};
17use hal::bind_interrupts; 20use hal::bind_interrupts;
18use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; 21use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _};
@@ -43,7 +46,7 @@ fn alarm_callback() {
43 } 46 }
44} 47}
45 48
46fn report_default_handler(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>) { 49fn report_default_handler(uart: &mut Lpuart<'_, Blocking>) {
47 let snapshot = hal::interrupt::default_handler_snapshot(); 50 let snapshot = hal::interrupt::default_handler_snapshot();
48 if snapshot.count == 0 { 51 if snapshot.count == 0 {
49 return; 52 return;
@@ -72,15 +75,25 @@ fn report_default_handler(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>) {
72async fn main(_spawner: Spawner) { 75async fn main(_spawner: Spawner) {
73 let p = hal::init(Default::default()); 76 let p = hal::init(Default::default());
74 77
75 // Enable/clock OSTIMER0 and UART2 before touching their registers 78 // Create UART configuration
76 unsafe { 79 let config = Config {
77 common::init_ostimer0(hal::pac()); 80 baudrate_bps: 115_200,
78 } 81 enable_tx: true,
82 enable_rx: true,
83 ..Default::default()
84 };
85
86 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
79 unsafe { 87 unsafe {
80 common::init_uart2(hal::pac()); 88 common::init_uart2(hal::pac());
81 } 89 }
82 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 90 let mut uart = Lpuart::new_blocking(
83 let mut uart = hal::uart::Uart::<hal::uart::Lpuart2>::new(p.LPUART2, hal::uart::Config::new(src)); 91 p.LPUART2, // Peripheral
92 p.PIO2_2, // TX pin
93 p.PIO2_3, // RX pin
94 config,
95 )
96 .unwrap();
84 97
85 uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); 98 uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n");
86 99
@@ -140,7 +153,7 @@ async fn main(_spawner: Spawner) {
140// Test rapid alarm scheduling to stress interrupt handling 153// Test rapid alarm scheduling to stress interrupt handling
141async fn test_rapid_alarms( 154async fn test_rapid_alarms(
142 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, 155 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
143 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, 156 uart: &mut Lpuart<'_, Blocking>,
144) { 157) {
145 let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); 158 let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst);
146 159
@@ -177,7 +190,7 @@ async fn test_rapid_alarms(
177// Test reading counter while interrupts are firing 190// Test reading counter while interrupts are firing
178async fn test_counter_reading_during_interrupts( 191async fn test_counter_reading_during_interrupts(
179 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, 192 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
180 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, 193 uart: &mut Lpuart<'_, Blocking>,
181) { 194) {
182 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); 195 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
183 196
@@ -238,7 +251,7 @@ async fn test_counter_reading_during_interrupts(
238// Test concurrent timer operations (embassy-time + alarms) 251// Test concurrent timer operations (embassy-time + alarms)
239async fn test_concurrent_operations( 252async fn test_concurrent_operations(
240 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, 253 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
241 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, 254 uart: &mut Lpuart<'_, Blocking>,
242) { 255) {
243 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); 256 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
244 257
@@ -267,7 +280,7 @@ async fn test_concurrent_operations(
267// Test timer reset during active operations 280// Test timer reset during active operations
268async fn test_reset_during_operation( 281async fn test_reset_during_operation(
269 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, 282 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
270 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, 283 uart: &mut Lpuart<'_, Blocking>,
271 peripherals: &mcxa_pac::Peripherals, 284 peripherals: &mcxa_pac::Peripherals,
272) { 285) {
273 let initial_counter = ostimer.now(); 286 let initial_counter = ostimer.now();
@@ -308,7 +321,7 @@ async fn test_reset_during_operation(
308} 321}
309 322
310// Helper function to write a u32 value as decimal string 323// Helper function to write a u32 value as decimal string
311fn write_u32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) { 324fn write_u32(uart: &mut Lpuart<'_, Blocking>, value: u32) {
312 if value == 0 { 325 if value == 0 {
313 uart.write_str_blocking("0"); 326 uart.write_str_blocking("0");
314 return; 327 return;
@@ -343,7 +356,7 @@ fn write_u32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) {
343 } 356 }
344} 357}
345 358
346fn write_hex32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) { 359fn write_hex32(uart: &mut Lpuart<'_, Blocking>, value: u32) {
347 let mut buf = [b'0'; 8]; 360 let mut buf = [b'0'; 8];
348 let mut tmp = value; 361 let mut tmp = value;
349 for i in (0..8).rev() { 362 for i in (0..8).rev() {
@@ -355,15 +368,13 @@ fn write_hex32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) {
355 }; 368 };
356 tmp >>= 4; 369 tmp >>= 4;
357 } 370 }
358 for b in &buf { 371 uart.blocking_write(&buf).unwrap();
359 uart.write_byte(*b);
360 }
361} 372}
362 373
363// Helper function to write a u64 value as decimal string 374// Helper function to write a u64 value as decimal string
364fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) { 375fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) {
365 if value == 0 { 376 if value == 0 {
366 uart.write_str_blocking("0"); 377 uart.blocking_write(b"0").unwrap();
367 return; 378 return;
368 } 379 }
369 380
@@ -381,17 +392,17 @@ fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) {
381 while i > 0 { 392 while i > 0 {
382 i -= 1; 393 i -= 1;
383 match buffer[i] { 394 match buffer[i] {
384 b'0' => uart.write_str_blocking("0"), 395 b'0' => uart.blocking_write(b"0").unwrap(),
385 b'1' => uart.write_str_blocking("1"), 396 b'1' => uart.blocking_write(b"1").unwrap(),
386 b'2' => uart.write_str_blocking("2"), 397 b'2' => uart.blocking_write(b"2").unwrap(),
387 b'3' => uart.write_str_blocking("3"), 398 b'3' => uart.blocking_write(b"3").unwrap(),
388 b'4' => uart.write_str_blocking("4"), 399 b'4' => uart.blocking_write(b"4").unwrap(),
389 b'5' => uart.write_str_blocking("5"), 400 b'5' => uart.blocking_write(b"5").unwrap(),
390 b'6' => uart.write_str_blocking("6"), 401 b'6' => uart.blocking_write(b"6").unwrap(),
391 b'7' => uart.write_str_blocking("7"), 402 b'7' => uart.blocking_write(b"7").unwrap(),
392 b'8' => uart.write_str_blocking("8"), 403 b'8' => uart.blocking_write(b"8").unwrap(),
393 b'9' => uart.write_str_blocking("9"), 404 b'9' => uart.blocking_write(b"9").unwrap(),
394 _ => uart.write_str_blocking("?"), 405 _ => uart.blocking_write(b"?").unwrap(),
395 } 406 }
396 } 407 }
397} 408}
diff --git a/examples/rtc_alarm.rs b/examples/rtc_alarm.rs
index c27fd4c55..1cda37054 100644
--- a/examples/rtc_alarm.rs
+++ b/examples/rtc_alarm.rs
@@ -2,13 +2,14 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa276::lpuart::{Config, Lpuart};
5use hal::rtc::{RtcDateTime, RtcInterruptEnable}; 6use hal::rtc::{RtcDateTime, RtcInterruptEnable};
6use hal::{uart, InterruptExt}; 7use hal::InterruptExt;
7use {cortex_m, embassy_mcxa276 as hal}; 8use {embassy_mcxa276 as hal};
8 9
9mod common; 10mod common;
10 11
11type MyRtc = hal::rtc::Rtc<hal::rtc::Rtc0>; 12type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>;
12 13
13use embassy_mcxa276::bind_interrupts; 14use embassy_mcxa276::bind_interrupts;
14use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
@@ -25,17 +26,28 @@ static KEEP_RTC: unsafe extern "C" fn() = RTC;
25async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
26 let p = hal::init(hal::config::Config::default()); 27 let p = hal::init(hal::config::Config::default());
27 28
29 // Create UART configuration
30 let config = Config {
31 baudrate_bps: 115_200,
32 enable_tx: true,
33 enable_rx: true,
34 ..Default::default()
35 };
36
37 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
28 unsafe { 38 unsafe {
29 common::init_uart2(hal::pac()); 39 common::init_uart2(hal::pac());
30 } 40 }
31 41 let mut uart = Lpuart::new_blocking(
32 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 42 p.LPUART2, // Peripheral
33 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 43 p.PIO2_2, // TX pin
44 p.PIO2_3, // RX pin
45 config,
46 )
47 .unwrap();
34 48
35 uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n"); 49 uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n");
36 50
37 unsafe { hal::clocks::init_fro16k(hal::pac()) };
38
39 let rtc_config = hal::rtc::get_default_config(); 51 let rtc_config = hal::rtc::get_default_config();
40 52
41 let rtc = MyRtc::new(p.RTC0, rtc_config); 53 let rtc = MyRtc::new(p.RTC0, rtc_config);
diff --git a/examples/uart_interrupt.rs b/examples/uart_interrupt.rs
deleted file mode 100644
index 190a4d850..000000000
--- a/examples/uart_interrupt.rs
+++ /dev/null
@@ -1,69 +0,0 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5// use embassy_mcxa276 as hal;
6// use hal::interrupt::typelevel::Handler;
7// use hal::uart;
8
9// mod common;
10
11// use embassy_mcxa276::bind_interrupts;
12// use {defmt_rtt as _, panic_probe as _};
13
14// // Bind LPUART2 interrupt to our handler
15// bind_interrupts!(struct Irqs {
16// LPUART2 => hal::uart::UartInterruptHandler;
17// });
18
19// #[used]
20// #[no_mangle]
21// static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2;
22
23// // Wrapper function for the interrupt handler
24// unsafe extern "C" fn lpuart2_handler() {
25// hal::uart::UartInterruptHandler::on_interrupt();
26// }
27
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30// let _p = hal::init(hal::config::Config::default());
31
32// // Enable/clock UART2 before touching its registers
33// unsafe {
34// common::init_uart2(hal::pac());
35// }
36// let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
37// let uart = uart::Uart::<uart::Lpuart2>::new(_p.LPUART2, uart::Config::new(src));
38
39// // Configure LPUART2 interrupt for UART operation BEFORE any UART usage
40// hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3));
41
42// // Manually install the interrupt handler and enable RX IRQs in the peripheral
43// unsafe {
44// hal::interrupt::LPUART2.install_handler(lpuart2_handler);
45// // Enable RX interrupts so the handler actually fires on incoming bytes
46// uart.enable_rx_interrupts();
47// }
48
49// // Print welcome message
50// uart.write_str_blocking("UART interrupt echo demo starting...\r\n");
51// uart.write_str_blocking("Type characters to echo them back.\r\n");
52
53// // Log using defmt if enabled
54// defmt::info!("UART interrupt echo demo starting...");
55
56// loop {
57// // Check if we have received any data
58// if uart.rx_data_available() {
59// if let Some(byte) = uart.try_read_byte() {
60// // Echo it back
61// uart.write_byte(byte);
62// uart.write_str_blocking(" (received)\r\n");
63// }
64// } else {
65// // No data available, wait a bit before checking again
66// cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz
67// }
68// }
69}
diff --git a/src/lib.rs b/src/lib.rs
index 4120c1e84..ec2cb31e7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,7 +13,6 @@ pub mod interrupt;
13pub mod lpuart; 13pub mod lpuart;
14pub mod ostimer; 14pub mod ostimer;
15pub mod rtc; 15pub mod rtc;
16pub mod uart;
17 16
18embassy_hal_internal::peripherals!(PORT1, PORT2, PORT3, LPUART2, OSTIMER0, GPIO, PIO2_2, PIO2_3, GPIO3, RTC0, ADC1,); 17embassy_hal_internal::peripherals!(PORT1, PORT2, PORT3, LPUART2, OSTIMER0, GPIO, PIO2_2, PIO2_3, GPIO3, RTC0, ADC1,);
19 18
@@ -45,7 +44,6 @@ pub use mcxa_pac as pac;
45pub(crate) use mcxa_pac as pac; 44pub(crate) use mcxa_pac as pac;
46pub use ostimer::Ostimer0 as Ostimer0Token; 45pub use ostimer::Ostimer0 as Ostimer0Token;
47pub use rtc::Rtc0 as Rtc0Token; 46pub use rtc::Rtc0 as Rtc0Token;
48pub use uart::Lpuart2 as Uart2Token;
49 47
50/// Initialize HAL with configuration (mirrors embassy-imxrt style). Minimal: just take peripherals. 48/// Initialize HAL with configuration (mirrors embassy-imxrt style). Minimal: just take peripherals.
51/// Also applies configurable NVIC priority for the OSTIMER OS_EVENT interrupt (no enabling). 49/// Also applies configurable NVIC priority for the OSTIMER OS_EVENT interrupt (no enabling).
diff --git a/src/lpuart/mod.rs b/src/lpuart/mod.rs
index 9e8b25ff6..b3d7c4885 100644
--- a/src/lpuart/mod.rs
+++ b/src/lpuart/mod.rs
@@ -772,6 +772,10 @@ impl<'a> LpuartTx<'a, Blocking> {
772 Ok(()) 772 Ok(())
773 } 773 }
774 774
775 pub fn write_str_blocking(&mut self, buf: &str) {
776 let _ = self.blocking_write(buf.as_bytes());
777 }
778
775 /// Write data to LPUART TX without blocking. 779 /// Write data to LPUART TX without blocking.
776 pub fn write(&mut self, buf: &[u8]) -> Result<()> { 780 pub fn write(&mut self, buf: &[u8]) -> Result<()> {
777 for x in buf { 781 for x in buf {
@@ -901,6 +905,22 @@ impl<'a> Lpuart<'a, Blocking> {
901 self.tx.blocking_write(buf) 905 self.tx.blocking_write(buf)
902 } 906 }
903 907
908 pub fn write_byte(&mut self, byte: u8) {
909 _ = self.tx.write_byte(byte);
910 }
911
912 pub fn read_byte_blocking(&mut self) -> u8 {
913 loop {
914 if let Ok(b) = self.rx.read_byte() {
915 return b;
916 }
917 }
918 }
919
920 pub fn write_str_blocking(&mut self, buf: &str) {
921 self.tx.write_str_blocking(buf);
922 }
923
904 /// Write data to LPUART TX without blocking 924 /// Write data to LPUART TX without blocking
905 pub fn write(&mut self, buf: &[u8]) -> Result<()> { 925 pub fn write(&mut self, buf: &[u8]) -> Result<()> {
906 self.tx.write(buf) 926 self.tx.write(buf)
diff --git a/src/ostimer.rs b/src/ostimer.rs
index efa534194..ebdf7d45d 100644
--- a/src/ostimer.rs
+++ b/src/ostimer.rs
@@ -534,7 +534,7 @@ pub mod time_driver {
534 bin_to_gray, now_ticks_read, Regs, ALARM_ACTIVE, ALARM_CALLBACK, ALARM_FLAG, ALARM_TARGET_TIME, 534 bin_to_gray, now_ticks_read, Regs, ALARM_ACTIVE, ALARM_CALLBACK, ALARM_FLAG, ALARM_TARGET_TIME,
535 EVTIMER_HI_MASK, EVTIMER_HI_SHIFT, LOW_32_BIT_MASK, 535 EVTIMER_HI_MASK, EVTIMER_HI_SHIFT, LOW_32_BIT_MASK,
536 }; 536 };
537 use crate::pac; 537 use crate::{clocks::{enable_and_reset, periph_helpers::{OsTimerConfig, OstimerClockSel}, PoweredClock}, pac, peripherals::OSTIMER0};
538 pub struct Driver; 538 pub struct Driver;
539 static TIMER_WAKER: AtomicWaker = AtomicWaker::new(); 539 static TIMER_WAKER: AtomicWaker = AtomicWaker::new();
540 540
@@ -621,6 +621,14 @@ pub mod time_driver {
621 /// Note: The frequency parameter is currently accepted for API compatibility. 621 /// Note: The frequency parameter is currently accepted for API compatibility.
622 /// The embassy_time_driver macro handles driver registration automatically. 622 /// The embassy_time_driver macro handles driver registration automatically.
623 pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) { 623 pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) {
624 let _clock_freq = unsafe {
625 enable_and_reset::<OSTIMER0>(&OsTimerConfig {
626 power: PoweredClock::AlwaysEnabled,
627 source: OstimerClockSel::Clk1M,
628 })
629 .expect("Enabling OsTimer clock should not fail")
630 };
631
624 // Mask/clear at peripheral and set default MATCH 632 // Mask/clear at peripheral and set default MATCH
625 let r: &Regs = unsafe { &*pac::Ostimer0::ptr() }; 633 let r: &Regs = unsafe { &*pac::Ostimer0::ptr() };
626 super::prime_match_registers(r); 634 super::prime_match_registers(r);
diff --git a/src/rtc.rs b/src/rtc.rs
index facb9cf8c..f526e82ac 100644
--- a/src/rtc.rs
+++ b/src/rtc.rs
@@ -1,6 +1,9 @@
1//! RTC DateTime driver. 1//! RTC DateTime driver.
2use core::sync::atomic::{AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering};
3 3
4use embassy_hal_internal::{Peri, PeripheralType};
5
6use crate::clocks::with_clocks;
4use crate::pac; 7use crate::pac;
5use crate::pac::rtc0::cr::Um; 8use crate::pac::rtc0::cr::Um;
6 9
@@ -9,7 +12,7 @@ type Regs = pac::rtc0::RegisterBlock;
9static ALARM_TRIGGERED: AtomicBool = AtomicBool::new(false); 12static ALARM_TRIGGERED: AtomicBool = AtomicBool::new(false);
10 13
11// Token-based instance pattern like embassy-imxrt 14// Token-based instance pattern like embassy-imxrt
12pub trait Instance { 15pub trait Instance: PeripheralType {
13 fn ptr() -> *const Regs; 16 fn ptr() -> *const Regs;
14} 17}
15 18
@@ -22,14 +25,6 @@ impl Instance for crate::peripherals::RTC0 {
22 } 25 }
23} 26}
24 27
25// Also implement Instance for the Peri wrapper type
26impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::RTC0> {
27 #[inline(always)]
28 fn ptr() -> *const Regs {
29 pac::Rtc0::ptr()
30 }
31}
32
33const DAYS_IN_A_YEAR: u32 = 365; 28const DAYS_IN_A_YEAR: u32 = 365;
34const SECONDS_IN_A_DAY: u32 = 86400; 29const SECONDS_IN_A_DAY: u32 = 86400;
35const SECONDS_IN_A_HOUR: u32 = 3600; 30const SECONDS_IN_A_HOUR: u32 = 3600;
@@ -157,15 +152,26 @@ pub fn get_default_config() -> RtcConfig {
157 } 152 }
158} 153}
159/// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy) 154/// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy)
160pub struct Rtc<I: Instance> { 155pub struct Rtc<'a, I: Instance> {
161 _inst: core::marker::PhantomData<I>, 156 _inst: core::marker::PhantomData<&'a mut I>,
162} 157}
163 158
164impl<I: Instance> Rtc<I> { 159impl<'a, I: Instance> Rtc<'a, I> {
165 /// initialize RTC 160 /// initialize RTC
166 pub fn new(_inst: impl Instance, config: RtcConfig) -> Self { 161 pub fn new(_inst: Peri<'a, I>, config: RtcConfig) -> Self {
167 let rtc = unsafe { &*I::ptr() }; 162 let rtc = unsafe { &*I::ptr() };
168 163
164 // The RTC is NOT gated by the MRCC, but we DO need to make sure the 16k clock
165 // on the vsys domain is active
166 let clocks = with_clocks(|c| {
167 c.clk_16k_vsys.clone()
168 });
169 match clocks {
170 None => panic!("Clocks have not been initialized"),
171 Some(None) => panic!("Clocks initialized, but clk_16k_vsys not active"),
172 Some(Some(_)) => {}
173 }
174
169 /* RTC reset */ 175 /* RTC reset */
170 rtc.cr().modify(|_, w| w.swr().set_bit()); 176 rtc.cr().modify(|_, w| w.swr().set_bit());
171 rtc.cr().modify(|_, w| w.swr().clear_bit()); 177 rtc.cr().modify(|_, w| w.swr().clear_bit());
diff --git a/src/uart.rs b/src/uart.rs
deleted file mode 100644
index 3705959d3..000000000
--- a/src/uart.rs
+++ /dev/null
@@ -1,316 +0,0 @@
1//! Minimal polling UART2 bring-up replicating MCUXpresso hello_world ordering.
2//! WARNING: This is a narrow implementation only for debug console (115200 8N1).
3
4// TODO(AJM): As of 2025-11-13, we need to do a pass to ensure safety docs
5// are complete prior to release.
6#![allow(clippy::missing_safety_doc)]
7
8use core::cell::RefCell;
9
10use cortex_m::interrupt::Mutex;
11use embassy_sync::signal::Signal;
12
13use crate::pac;
14
15// svd2rust defines the shared LPUART RegisterBlock under lpuart0; all instances reuse it.
16type Regs = pac::lpuart0::RegisterBlock;
17
18// Token-based instance pattern like embassy-imxrt
19pub trait Instance {
20 fn ptr() -> *const Regs;
21}
22
23/// Token for LPUART2 provided by embassy-hal-internal peripherals macro.
24pub type Lpuart2 = crate::peripherals::LPUART2;
25impl Instance for crate::peripherals::LPUART2 {
26 #[inline(always)]
27 fn ptr() -> *const Regs {
28 pac::Lpuart2::ptr()
29 }
30}
31
32// Also implement Instance for the Peri wrapper type
33impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::LPUART2> {
34 #[inline(always)]
35 fn ptr() -> *const Regs {
36 pac::Lpuart2::ptr()
37 }
38}
39
40/// UART configuration (explicit src_hz; no hardcoded frequencies)
41#[derive(Copy, Clone)]
42pub struct Config {
43 pub src_hz: u32,
44 pub baud: u32,
45 pub parity: Parity,
46 pub stop_bits: StopBits,
47}
48
49#[derive(Copy, Clone)]
50pub enum Parity {
51 None,
52 Even,
53 Odd,
54}
55#[derive(Copy, Clone)]
56pub enum StopBits {
57 One,
58 Two,
59}
60
61impl Config {
62 pub fn new(src_hz: u32) -> Self {
63 Self {
64 src_hz,
65 baud: 115_200,
66 parity: Parity::None,
67 stop_bits: StopBits::One,
68 }
69 }
70}
71
72/// Compute a valid (OSR, SBR) tuple for given source clock and baud.
73/// Uses a functional fold approach to find the best OSR/SBR combination
74/// with minimal baud rate error.
75fn compute_osr_sbr(src_hz: u32, baud: u32) -> (u8, u16) {
76 let (best_osr, best_sbr, _best_err) = (8u32..=32).fold(
77 (16u8, 4u16, u32::MAX), // (best_osr, best_sbr, best_err)
78 |(best_osr, best_sbr, best_err), osr| {
79 let denom = baud.saturating_mul(osr);
80 if denom == 0 {
81 return (best_osr, best_sbr, best_err);
82 }
83
84 let sbr = (src_hz + denom / 2) / denom; // round
85 if sbr == 0 || sbr > 0x1FFF {
86 return (best_osr, best_sbr, best_err);
87 }
88
89 let actual = src_hz / (osr * sbr);
90 let err = actual.abs_diff(baud);
91
92 // Update best if this is better, or same error but higher OSR
93 if err < best_err || (err == best_err && osr as u8 > best_osr) {
94 (osr as u8, sbr as u16, err)
95 } else {
96 (best_osr, best_sbr, best_err)
97 }
98 },
99 );
100 (best_osr, best_sbr)
101}
102
103/// Minimal UART handle for a specific instance I (store the zero-sized token like embassy)
104pub struct Uart<I: Instance> {
105 _inst: core::marker::PhantomData<I>,
106}
107
108impl<I: Instance> Uart<I> {
109 /// Create and initialize LPUART (reset + config). Clocks and pins must be prepared by the caller.
110 pub fn new(_inst: impl Instance, cfg: Config) -> Self {
111 let l = unsafe { &*I::ptr() };
112 // 1) software reset pulse
113 l.global().write(|w| w.rst().reset());
114 cortex_m::asm::delay(3); // Short delay for reset to take effect
115 l.global().write(|w| w.rst().no_effect());
116 cortex_m::asm::delay(10); // Allow peripheral to stabilize after reset
117 // 2) BAUD
118 let (osr, sbr) = compute_osr_sbr(cfg.src_hz, cfg.baud);
119 l.baud().modify(|_, w| {
120 let w = match cfg.stop_bits {
121 StopBits::One => w.sbns().one(),
122 StopBits::Two => w.sbns().two(),
123 };
124 // OSR field encodes (osr-1); use raw bits to avoid a long match on all variants
125 let raw_osr = osr.saturating_sub(1);
126 unsafe { w.osr().bits(raw_osr).sbr().bits(sbr) }
127 });
128 // 3) CTRL baseline and parity
129 l.ctrl().write(|w| {
130 let w = w.ilt().from_stop().idlecfg().idle_2();
131 let w = match cfg.parity {
132 Parity::None => w.pe().disabled(),
133 Parity::Even => w.pe().enabled().pt().even(),
134 Parity::Odd => w.pe().enabled().pt().odd(),
135 };
136 w.re().enabled().te().enabled().rie().disabled()
137 });
138 // 4) FIFOs and WATER: keep it simple for polling; disable FIFOs and set RX watermark to 0
139 l.fifo().modify(|_, w| {
140 w.txfe()
141 .disabled()
142 .rxfe()
143 .disabled()
144 .txflush()
145 .txfifo_rst()
146 .rxflush()
147 .rxfifo_rst()
148 });
149 l.water()
150 .modify(|_, w| unsafe { w.txwater().bits(0).rxwater().bits(0) });
151 Self {
152 _inst: core::marker::PhantomData,
153 }
154 }
155
156 /// Enable RX interrupts. The caller must ensure an appropriate IRQ handler is installed.
157 pub unsafe fn enable_rx_interrupts(&self) {
158 let l = &*I::ptr();
159 l.ctrl().modify(|_, w| w.rie().enabled());
160 }
161
162 #[inline(never)]
163 pub fn write_byte(&self, b: u8) {
164 let l = unsafe { &*I::ptr() };
165 // Timeout after ~10ms at 12MHz (assuming 115200 baud, should be plenty)
166 const DATA_OFFSET: usize = 0x1C; // DATA register offset inside LPUART block
167 let data_ptr = unsafe { (I::ptr() as *mut u8).add(DATA_OFFSET) };
168 for _ in 0..120000 {
169 if l.water().read().txcount().bits() == 0 {
170 unsafe { core::ptr::write_volatile(data_ptr, b) };
171 return;
172 }
173 }
174 // If timeout, skip the write to avoid hanging
175 }
176
177 #[inline(never)]
178 pub fn write_str_blocking(&self, s: &str) {
179 for &b in s.as_bytes() {
180 if b == b'\n' {
181 self.write_byte(b'\r');
182 }
183 self.write_byte(b);
184 }
185 }
186 pub fn read_byte_blocking(&self) -> u8 {
187 let l = unsafe { &*I::ptr() };
188 while !l.stat().read().rdrf().is_rxdata() {}
189 (l.data().read().bits() & 0xFF) as u8
190 }
191}
192
193// Simple ring buffer for UART RX data
194const RX_BUFFER_SIZE: usize = 256;
195pub struct RingBuffer {
196 buffer: [u8; RX_BUFFER_SIZE],
197 read_idx: usize,
198 write_idx: usize,
199 count: usize,
200}
201
202impl Default for RingBuffer {
203 fn default() -> Self {
204 Self::new()
205 }
206}
207
208impl RingBuffer {
209 pub const fn new() -> Self {
210 Self {
211 buffer: [0; RX_BUFFER_SIZE],
212 read_idx: 0,
213 write_idx: 0,
214 count: 0,
215 }
216 }
217
218 pub fn push(&mut self, data: u8) -> bool {
219 if self.count >= RX_BUFFER_SIZE {
220 return false; // Buffer full
221 }
222 self.buffer[self.write_idx] = data;
223 self.write_idx = (self.write_idx + 1) % RX_BUFFER_SIZE;
224 self.count += 1;
225 true
226 }
227
228 pub fn pop(&mut self) -> Option<u8> {
229 if self.count == 0 {
230 return None;
231 }
232 let data = self.buffer[self.read_idx];
233 self.read_idx = (self.read_idx + 1) % RX_BUFFER_SIZE;
234 self.count -= 1;
235 Some(data)
236 }
237
238 pub fn is_empty(&self) -> bool {
239 self.count == 0
240 }
241
242 pub fn len(&self) -> usize {
243 self.count
244 }
245}
246
247// Global RX buffer shared between interrupt handler and UART instance
248static RX_BUFFER: Mutex<RefCell<RingBuffer>> = Mutex::new(RefCell::new(RingBuffer::new()));
249static RX_SIGNAL: Signal<embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex, ()> = Signal::new();
250
251// Debug counter for interrupt handler calls
252static mut INTERRUPT_COUNT: u32 = 0;
253
254impl<I: Instance> Uart<I> {
255 /// Read a byte asynchronously using interrupts
256 pub async fn read_byte_async(&self) -> u8 {
257 loop {
258 // Check if we have data in the buffer
259 let byte = cortex_m::interrupt::free(|cs| {
260 let mut buffer = RX_BUFFER.borrow(cs).borrow_mut();
261 buffer.pop()
262 });
263
264 if let Some(byte) = byte {
265 return byte;
266 }
267
268 // Wait for the interrupt signal
269 RX_SIGNAL.wait().await;
270 }
271 }
272
273 /// Check if there's data available in the RX buffer
274 pub fn rx_data_available(&self) -> bool {
275 cortex_m::interrupt::free(|cs| {
276 let buffer = RX_BUFFER.borrow(cs).borrow();
277 !buffer.is_empty()
278 })
279 }
280
281 /// Try to read a byte from RX buffer (non-blocking)
282 pub fn try_read_byte(&self) -> Option<u8> {
283 cortex_m::interrupt::free(|cs| {
284 let mut buffer = RX_BUFFER.borrow(cs).borrow_mut();
285 buffer.pop()
286 })
287 }
288}
289
290/// Type-level handler for LPUART2 interrupts, compatible with bind_interrupts!.
291pub struct UartInterruptHandler;
292
293impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::LPUART2> for UartInterruptHandler {
294 unsafe fn on_interrupt() {
295 INTERRUPT_COUNT += 1;
296
297 let lpuart = &*pac::Lpuart2::ptr();
298
299 // Check if we have RX data
300 if lpuart.stat().read().rdrf().is_rxdata() {
301 // Read the data byte
302 let data = (lpuart.data().read().bits() & 0xFF) as u8;
303
304 // Store in ring buffer
305 cortex_m::interrupt::free(|cs| {
306 let mut buffer = RX_BUFFER.borrow(cs).borrow_mut();
307 if buffer.push(data) {
308 // Data added successfully, signal waiting tasks
309 RX_SIGNAL.signal(());
310 }
311 });
312 }
313 // Always clear any error flags that might cause spurious interrupts
314 let _ = lpuart.stat().read();
315 }
316}