diff options
| author | James Munns <[email protected]> | 2025-11-14 18:43:27 +0100 |
|---|---|---|
| committer | James Munns <[email protected]> | 2025-11-14 18:43:27 +0100 |
| commit | 8cdccae3c6c4a805cf5003b1a859734c105d76e8 (patch) | |
| tree | 7c605a58aa7e124bbed658dfc5f6822a25a83e98 | |
| parent | e799d6c8956ed3ea5ced65d58c3065a22927ad10 (diff) | |
Continue working on examples
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | examples/adc_interrupt.rs | 29 | ||||
| -rw-r--r-- | examples/adc_polling.rs | 30 | ||||
| -rw-r--r-- | examples/blink.rs | 4 | ||||
| -rw-r--r-- | examples/hello.rs | 33 | ||||
| -rw-r--r-- | examples/lpuart_buffered.rs | 9 | ||||
| -rw-r--r-- | examples/lpuart_polling.rs | 11 | ||||
| -rw-r--r-- | examples/ostimer_alarm.rs | 32 | ||||
| -rw-r--r-- | examples/ostimer_async.rs | 29 | ||||
| -rw-r--r-- | examples/ostimer_counter.rs | 26 | ||||
| -rw-r--r-- | examples/ostimer_race_test.rs | 71 | ||||
| -rw-r--r-- | examples/rtc_alarm.rs | 28 | ||||
| -rw-r--r-- | examples/uart_interrupt.rs | 69 | ||||
| -rw-r--r-- | src/lib.rs | 2 | ||||
| -rw-r--r-- | src/lpuart/mod.rs | 20 | ||||
| -rw-r--r-- | src/ostimer.rs | 10 | ||||
| -rw-r--r-- | src/rtc.rs | 32 | ||||
| -rw-r--r-- | src/uart.rs | 316 |
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" | |||
| 58 | name = "blink" | 58 | name = "blink" |
| 59 | 59 | ||
| 60 | [[example]] | 60 | [[example]] |
| 61 | name = "uart_interrupt" | ||
| 62 | |||
| 63 | [[example]] | ||
| 64 | name = "ostimer_alarm" | 61 | name = "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 @@ | |||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4}; | 5 | use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4}; |
| 6 | use embassy_mcxa276::clocks::PoweredClock; | 6 | use embassy_mcxa276::clocks::PoweredClock; |
| 7 | use embassy_mcxa276::lpuart::{Config, Lpuart}; | ||
| 7 | use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; | 8 | use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; |
| 8 | use hal::uart; | ||
| 9 | use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; | 9 | use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; |
| 10 | use mcxa_pac::adc1::cmdl1::{Adch, Mode}; | 10 | use mcxa_pac::adc1::cmdl1::{Adch, Mode}; |
| 11 | use mcxa_pac::adc1::ctrl::CalAvgs; | 11 | use mcxa_pac::adc1::ctrl::CalAvgs; |
| 12 | use mcxa_pac::adc1::tctrl::Tcmd; | 12 | use mcxa_pac::adc1::tctrl::Tcmd; |
| 13 | use {cortex_m, embassy_mcxa276 as hal}; | 13 | use {embassy_mcxa276 as hal}; |
| 14 | mod common; | 14 | mod common; |
| 15 | 15 | ||
| 16 | use hal::{bind_interrupts, InterruptExt}; | 16 | use hal::{bind_interrupts, InterruptExt}; |
| @@ -28,14 +28,25 @@ static KEEP_ADC: unsafe extern "C" fn() = ADC1; | |||
| 28 | async fn main(_spawner: Spawner) { | 28 | async 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 | ||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4}; | ||
| 6 | use embassy_mcxa276::clocks::PoweredClock; | ||
| 7 | use embassy_mcxa276::lpuart::{Config, Lpuart}; | ||
| 5 | use embassy_mcxa276 as hal; | 8 | use embassy_mcxa276 as hal; |
| 6 | use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; | 9 | use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; |
| 7 | use hal::uart; | ||
| 8 | use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; | 10 | use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; |
| 9 | use mcxa_pac::adc1::cmdl1::{Adch, Mode}; | 11 | use mcxa_pac::adc1::cmdl1::{Adch, Mode}; |
| 10 | use mcxa_pac::adc1::ctrl::CalAvgs; | 12 | use 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 | ||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_mcxa276 as hal; | 5 | use embassy_mcxa276::{self as hal, lpuart::{Blocking, Config, Lpuart}}; |
| 6 | use hal::uart; | ||
| 7 | 6 | ||
| 8 | mod common; | 7 | mod common; |
| 9 | 8 | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {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 |
| 13 | fn write_hex_byte(uart: &hal::uart::Uart<hal::uart::Lpuart2>, byte: u8) { | 12 | fn 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) { | |||
| 103 | fn parse_u8(bytes: &[u8]) -> Result<u8, ()> { | 112 | fn 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] |
| 24 | async fn main(_spawner: Spawner) { | 24 | async 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 @@ | |||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; | 5 | use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; |
| 6 | 6 | ||
| 7 | use crate::hal::lpuart::{lib, Config, Lpuart}; | 7 | use crate::hal::lpuart::{Config, Lpuart}; |
| 8 | 8 | ||
| 9 | mod common; | 9 | mod common; |
| 10 | 10 | ||
| 11 | #[embassy_executor::main] | 11 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) { | 12 | async 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 @@ | |||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | 4 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 5 | 5 | ||
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use hal::uart; | 7 | use embassy_mcxa276 as hal; |
| 8 | use {cortex_m, embassy_mcxa276 as hal}; | ||
| 9 | 8 | ||
| 10 | mod common; | 9 | mod common; |
| 11 | 10 | ||
| 12 | use embassy_mcxa276::{bind_interrupts, clocks::{periph_helpers::OstimerClockSel, PoweredClock}}; | 11 | use embassy_mcxa276::{ |
| 12 | bind_interrupts, | ||
| 13 | clocks::{periph_helpers::OstimerClockSel, PoweredClock}, | ||
| 14 | lpuart::{Config, Lpuart}, | ||
| 15 | }; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {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() { | |||
| 33 | async fn main(_spawner: Spawner) { | 36 | async 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 | ||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_mcxa276 as hal; | 5 | use embassy_mcxa276::{self as hal, lpuart::{Config, Lpuart}}; |
| 6 | use hal::uart; | ||
| 7 | 6 | ||
| 8 | mod common; | 7 | mod 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] |
| 24 | async fn main(_spawner: Spawner) { | 23 | async 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 | ||
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_mcxa276::clocks::{periph_helpers::OstimerClockSel, PoweredClock}; | 10 | use embassy_mcxa276::{ |
| 11 | clocks::{periph_helpers::OstimerClockSel, PoweredClock}, | ||
| 12 | lpuart::{Blocking, Config, Lpuart}, | ||
| 13 | }; | ||
| 11 | use embassy_time::{Duration, Timer}; | 14 | use embassy_time::{Duration, Timer}; |
| 12 | use hal::bind_interrupts; | 15 | use hal::bind_interrupts; |
| 13 | use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; | 16 | use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; |
| @@ -22,12 +25,25 @@ bind_interrupts!(struct Irqs { | |||
| 22 | async fn main(_spawner: Spawner) { | 25 | async 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 |
| 93 | fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) { | 109 | fn 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 @@ | |||
| 12 | use core::sync::atomic::{AtomicU32, Ordering}; | 12 | use core::sync::atomic::{AtomicU32, Ordering}; |
| 13 | 13 | ||
| 14 | use embassy_executor::Spawner; | 14 | use embassy_executor::Spawner; |
| 15 | use embassy_mcxa276::clocks::{periph_helpers::OstimerClockSel, PoweredClock}; | 15 | use embassy_mcxa276::{ |
| 16 | clocks::{periph_helpers::OstimerClockSel, PoweredClock}, | ||
| 17 | lpuart::{Blocking, Config, Lpuart}, | ||
| 18 | }; | ||
| 16 | use embassy_time::{Duration, Timer}; | 19 | use embassy_time::{Duration, Timer}; |
| 17 | use hal::bind_interrupts; | 20 | use hal::bind_interrupts; |
| 18 | use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; | 21 | use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; |
| @@ -43,7 +46,7 @@ fn alarm_callback() { | |||
| 43 | } | 46 | } |
| 44 | } | 47 | } |
| 45 | 48 | ||
| 46 | fn report_default_handler(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>) { | 49 | fn 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>) { | |||
| 72 | async fn main(_spawner: Spawner) { | 75 | async 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 |
| 141 | async fn test_rapid_alarms( | 154 | async 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 |
| 178 | async fn test_counter_reading_during_interrupts( | 191 | async 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) |
| 239 | async fn test_concurrent_operations( | 252 | async 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 |
| 268 | async fn test_reset_during_operation( | 281 | async 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 |
| 311 | fn write_u32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) { | 324 | fn 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 | ||
| 346 | fn write_hex32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) { | 359 | fn 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 |
| 364 | fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) { | 375 | fn 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 | ||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_mcxa276::lpuart::{Config, Lpuart}; | ||
| 5 | use hal::rtc::{RtcDateTime, RtcInterruptEnable}; | 6 | use hal::rtc::{RtcDateTime, RtcInterruptEnable}; |
| 6 | use hal::{uart, InterruptExt}; | 7 | use hal::InterruptExt; |
| 7 | use {cortex_m, embassy_mcxa276 as hal}; | 8 | use {embassy_mcxa276 as hal}; |
| 8 | 9 | ||
| 9 | mod common; | 10 | mod common; |
| 10 | 11 | ||
| 11 | type MyRtc = hal::rtc::Rtc<hal::rtc::Rtc0>; | 12 | type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>; |
| 12 | 13 | ||
| 13 | use embassy_mcxa276::bind_interrupts; | 14 | use embassy_mcxa276::bind_interrupts; |
| 14 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -25,17 +26,28 @@ static KEEP_RTC: unsafe extern "C" fn() = RTC; | |||
| 25 | async fn main(_spawner: Spawner) { | 26 | async 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 | |||
| 4 | use 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] | ||
| 29 | async 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; | |||
| 13 | pub mod lpuart; | 13 | pub mod lpuart; |
| 14 | pub mod ostimer; | 14 | pub mod ostimer; |
| 15 | pub mod rtc; | 15 | pub mod rtc; |
| 16 | pub mod uart; | ||
| 17 | 16 | ||
| 18 | embassy_hal_internal::peripherals!(PORT1, PORT2, PORT3, LPUART2, OSTIMER0, GPIO, PIO2_2, PIO2_3, GPIO3, RTC0, ADC1,); | 17 | embassy_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; | |||
| 45 | pub(crate) use mcxa_pac as pac; | 44 | pub(crate) use mcxa_pac as pac; |
| 46 | pub use ostimer::Ostimer0 as Ostimer0Token; | 45 | pub use ostimer::Ostimer0 as Ostimer0Token; |
| 47 | pub use rtc::Rtc0 as Rtc0Token; | 46 | pub use rtc::Rtc0 as Rtc0Token; |
| 48 | pub 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. |
| 2 | use core::sync::atomic::{AtomicBool, Ordering}; | 2 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 3 | 3 | ||
| 4 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 5 | |||
| 6 | use crate::clocks::with_clocks; | ||
| 4 | use crate::pac; | 7 | use crate::pac; |
| 5 | use crate::pac::rtc0::cr::Um; | 8 | use crate::pac::rtc0::cr::Um; |
| 6 | 9 | ||
| @@ -9,7 +12,7 @@ type Regs = pac::rtc0::RegisterBlock; | |||
| 9 | static ALARM_TRIGGERED: AtomicBool = AtomicBool::new(false); | 12 | static ALARM_TRIGGERED: AtomicBool = AtomicBool::new(false); |
| 10 | 13 | ||
| 11 | // Token-based instance pattern like embassy-imxrt | 14 | // Token-based instance pattern like embassy-imxrt |
| 12 | pub trait Instance { | 15 | pub 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 | ||
| 26 | impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::RTC0> { | ||
| 27 | #[inline(always)] | ||
| 28 | fn ptr() -> *const Regs { | ||
| 29 | pac::Rtc0::ptr() | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | const DAYS_IN_A_YEAR: u32 = 365; | 28 | const DAYS_IN_A_YEAR: u32 = 365; |
| 34 | const SECONDS_IN_A_DAY: u32 = 86400; | 29 | const SECONDS_IN_A_DAY: u32 = 86400; |
| 35 | const SECONDS_IN_A_HOUR: u32 = 3600; | 30 | const 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) |
| 160 | pub struct Rtc<I: Instance> { | 155 | pub struct Rtc<'a, I: Instance> { |
| 161 | _inst: core::marker::PhantomData<I>, | 156 | _inst: core::marker::PhantomData<&'a mut I>, |
| 162 | } | 157 | } |
| 163 | 158 | ||
| 164 | impl<I: Instance> Rtc<I> { | 159 | impl<'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 | |||
| 8 | use core::cell::RefCell; | ||
| 9 | |||
| 10 | use cortex_m::interrupt::Mutex; | ||
| 11 | use embassy_sync::signal::Signal; | ||
| 12 | |||
| 13 | use crate::pac; | ||
| 14 | |||
| 15 | // svd2rust defines the shared LPUART RegisterBlock under lpuart0; all instances reuse it. | ||
| 16 | type Regs = pac::lpuart0::RegisterBlock; | ||
| 17 | |||
| 18 | // Token-based instance pattern like embassy-imxrt | ||
| 19 | pub trait Instance { | ||
| 20 | fn ptr() -> *const Regs; | ||
| 21 | } | ||
| 22 | |||
| 23 | /// Token for LPUART2 provided by embassy-hal-internal peripherals macro. | ||
| 24 | pub type Lpuart2 = crate::peripherals::LPUART2; | ||
| 25 | impl 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 | ||
| 33 | impl 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)] | ||
| 42 | pub 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)] | ||
| 50 | pub enum Parity { | ||
| 51 | None, | ||
| 52 | Even, | ||
| 53 | Odd, | ||
| 54 | } | ||
| 55 | #[derive(Copy, Clone)] | ||
| 56 | pub enum StopBits { | ||
| 57 | One, | ||
| 58 | Two, | ||
| 59 | } | ||
| 60 | |||
| 61 | impl 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. | ||
| 75 | fn 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) | ||
| 104 | pub struct Uart<I: Instance> { | ||
| 105 | _inst: core::marker::PhantomData<I>, | ||
| 106 | } | ||
| 107 | |||
| 108 | impl<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 | ||
| 194 | const RX_BUFFER_SIZE: usize = 256; | ||
| 195 | pub struct RingBuffer { | ||
| 196 | buffer: [u8; RX_BUFFER_SIZE], | ||
| 197 | read_idx: usize, | ||
| 198 | write_idx: usize, | ||
| 199 | count: usize, | ||
| 200 | } | ||
| 201 | |||
| 202 | impl Default for RingBuffer { | ||
| 203 | fn default() -> Self { | ||
| 204 | Self::new() | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | impl 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 | ||
| 248 | static RX_BUFFER: Mutex<RefCell<RingBuffer>> = Mutex::new(RefCell::new(RingBuffer::new())); | ||
| 249 | static RX_SIGNAL: Signal<embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex, ()> = Signal::new(); | ||
| 250 | |||
| 251 | // Debug counter for interrupt handler calls | ||
| 252 | static mut INTERRUPT_COUNT: u32 = 0; | ||
| 253 | |||
| 254 | impl<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!. | ||
| 291 | pub struct UartInterruptHandler; | ||
| 292 | |||
| 293 | impl 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 | } | ||
