aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBogdan Petru Chircu Mare <[email protected]>2025-10-31 21:44:48 -0700
committerBogdan Petru Chircu Mare <[email protected]>2025-10-31 21:44:48 -0700
commit0443134bc47918d2f8f0ede1b292b372629f8894 (patch)
tree823f569464a6e001b4eb4246c9ad8083c8c20847 /examples
parent47e383545f4aac3bfaec0563429cc721540e665a (diff)
feat(mcxa276): initial HAL import
Diffstat (limited to 'examples')
-rw-r--r--examples/adc_interrupt.rs106
-rw-r--r--examples/adc_polling.rs95
-rw-r--r--examples/blink.rs93
-rw-r--r--examples/common/mod.rs45
-rw-r--r--examples/hello.rs126
-rw-r--r--examples/lpuart_buffered.rs88
-rw-r--r--examples/lpuart_polling.rs67
-rw-r--r--examples/ostimer_alarm.rs126
-rw-r--r--examples/ostimer_async.rs76
-rw-r--r--examples/ostimer_counter.rs142
-rw-r--r--examples/ostimer_race_test.rs411
-rw-r--r--examples/rtc_alarm.rs105
-rw-r--r--examples/uart_interrupt.rs86
13 files changed, 1566 insertions, 0 deletions
diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs
new file mode 100644
index 000000000..452eaae01
--- /dev/null
+++ b/examples/adc_interrupt.rs
@@ -0,0 +1,106 @@
1#![no_std]
2#![no_main]
3
4use embassy_mcxa276 as hal;
5use cortex_m;
6use embassy_executor::Spawner;
7
8use hal::adc::{TriggerPriorityPolicy, LpadcConfig};
9use hal::pac::adc1::cfg::{Refsel, Pwrsel};
10use hal::pac::adc1::tctrl::{Tcmd};
11use hal::pac::adc1::cmdl1::{Adch, Mode};
12use hal::pac::adc1::ctrl::{CalAvgs};
13
14use hal::uart;
15mod common;
16
17#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
18use defmt_rtt as _;
19#[cfg(feature = "defmt")]
20use panic_probe as _;
21#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
22use rtt_target as _;
23
24use hal::bind_interrupts;
25use hal::InterruptExt;
26
27bind_interrupts!(struct Irqs {
28 ADC1 => hal::adc::AdcHandler;
29});
30
31#[used]
32#[no_mangle]
33static KEEP_ADC: unsafe extern "C" fn() = ADC1;
34
35#[embassy_executor::main]
36async fn main(_spawner: Spawner) {
37 let p = hal::init(hal::config::Config::default());
38
39 unsafe {
40 common::init_uart2(hal::pac());
41 }
42
43 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
44 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src));
45
46 uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n");
47
48 unsafe {
49 common::init_adc(hal::pac());
50 }
51
52
53 let adc_config = LpadcConfig {
54 enable_in_doze_mode: true,
55 conversion_average_mode: CalAvgs::Average128,
56 enable_analog_preliminary: true,
57 power_up_delay: 0x80,
58 reference_voltage_source: Refsel::Option3,
59 power_level_mode: Pwrsel::Lowest,
60 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
61 enable_conv_pause: false,
62 conv_pause_delay: 0,
63 fifo_watermark: 0,
64 };
65 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config);
66
67 adc.do_offset_calibration();
68 adc.do_auto_calibration();
69
70 let mut conv_command_config = adc.get_default_conv_command_config();
71 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8;
72 conv_command_config.conversion_resolution_mode = Mode::Data16Bits;
73 adc.set_conv_command_config(1, &conv_command_config);
74
75 let mut conv_trigger_config = adc.get_default_conv_trigger_config();
76 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1;
77 conv_trigger_config.enable_hardware_trigger = false;
78 adc.set_conv_trigger_config(0, &conv_trigger_config);
79
80 uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n");
81
82 adc.enable_interrupt(0x1);
83
84 unsafe {
85 hal::interrupt::ADC1.enable();
86 }
87
88 unsafe {
89 cortex_m::interrupt::enable();
90 }
91
92 loop {
93 adc.do_software_trigger(1);
94 while !adc.is_interrupt_triggered() {
95 // Wait until the interrupt is triggered
96 }
97 uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n");
98 //TBD need to print the value
99 }
100}
101
102#[cfg(not(feature = "defmt"))]
103#[panic_handler]
104fn panic(_info: &core::panic::PanicInfo) -> ! {
105 loop {}
106} \ No newline at end of file
diff --git a/examples/adc_polling.rs b/examples/adc_polling.rs
new file mode 100644
index 000000000..7cb728e91
--- /dev/null
+++ b/examples/adc_polling.rs
@@ -0,0 +1,95 @@
1#![no_std]
2#![no_main]
3
4use embassy_mcxa276 as hal;
5
6use embassy_executor::Spawner;
7
8use hal::adc::{TriggerPriorityPolicy, LpadcConfig, ConvResult};
9use hal::pac::adc1::cfg::{Refsel, Pwrsel};
10use hal::pac::adc1::tctrl::{Tcmd};
11use hal::pac::adc1::cmdl1::{Adch, Mode};
12use hal::pac::adc1::ctrl::{CalAvgs};
13
14use hal::uart;
15
16mod common;
17
18#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
19use defmt_rtt as _;
20#[cfg(feature = "defmt")]
21use panic_probe as _;
22#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
23use rtt_target as _;
24
25use core::fmt::Write;
26use heapless::String;
27
28
29const G_LPADC_RESULT_SHIFT: u32 = 0;
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let p = hal::init(hal::config::Config::default());
34
35 unsafe {
36 common::init_uart2(hal::pac());
37 }
38
39 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
40 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src));
41
42 uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n");
43
44 unsafe {
45 common::init_adc(hal::pac());
46 }
47
48
49 let adc_config = LpadcConfig {
50 enable_in_doze_mode: true,
51 conversion_average_mode: CalAvgs::Average128,
52 enable_analog_preliminary: true,
53 power_up_delay: 0x80,
54 reference_voltage_source: Refsel::Option3,
55 power_level_mode: Pwrsel::Lowest,
56 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
57 enable_conv_pause: false,
58 conv_pause_delay: 0,
59 fifo_watermark: 0,
60 };
61 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config);
62
63 adc.do_offset_calibration();
64 adc.do_auto_calibration();
65
66 let mut conv_command_config = adc.get_default_conv_command_config();
67 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8;
68 conv_command_config.conversion_resolution_mode = Mode::Data16Bits;
69 adc.set_conv_command_config(1, &conv_command_config);
70
71 let mut conv_trigger_config = adc.get_default_conv_trigger_config();
72 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1;
73 conv_trigger_config.enable_hardware_trigger = false;
74 adc.set_conv_trigger_config(0, &conv_trigger_config);
75
76 uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n");
77
78 loop {
79 adc.do_software_trigger(1);
80 let mut result: Option<ConvResult> = None;
81 while result.is_none() {
82 result = hal::adc::get_conv_result();
83 }
84 let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT;
85 let mut buf: String<16> = String::new(); // adjust size as needed
86 write!(buf, "\r\nvalue: {}\r\n", value).unwrap();
87 uart.write_str_blocking(&buf);
88 }
89}
90
91#[cfg(not(feature = "defmt"))]
92#[panic_handler]
93fn panic(_info: &core::panic::PanicInfo) -> ! {
94 loop {}
95} \ No newline at end of file
diff --git a/examples/blink.rs b/examples/blink.rs
new file mode 100644
index 000000000..6289ac14e
--- /dev/null
+++ b/examples/blink.rs
@@ -0,0 +1,93 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa276 as hal;
6use embassy_time::{Duration, Timer};
7use hal::gpio::pins::PIO3_18;
8use hal::gpio::{Level, Output};
9
10mod common;
11
12use embassy_mcxa276::bind_interrupts;
13
14// Bind only OS_EVENT for timer interrupts
15bind_interrupts!(struct Irqs {
16 OS_EVENT => hal::ostimer::time_driver::OsEventHandler;
17});
18
19#[used]
20#[no_mangle]
21static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT;
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 let _p = hal::init(hal::config::Config::default());
26
27 // Board-style init: enable LED GPIO/PORT clocks used by blink
28 unsafe {
29 common::init_led(hal::pac());
30 }
31 // Initialize OSTIMER for async timing
32 unsafe {
33 common::init_ostimer0(hal::pac());
34 }
35
36 // Initialize embassy-time global driver backed by OSTIMER0
37 hal::ostimer::time_driver::init(
38 hal::config::Config::default().time_interrupt_priority,
39 1_000_000,
40 );
41
42 // Configure LED pin for GPIO mode
43 PIO3_18::set_mux_gpio();
44
45 let mut led = Output::new(PIO3_18::degrade(), Level::High);
46
47 // Complex blinking pattern: SOS in Morse code
48 // S: ... (3 short)
49 // O: --- (3 long)
50 // S: ... (3 short)
51 // With pauses between letters and words
52
53 loop {
54 // S: three short blinks
55 for _ in 0..3 {
56 led.set_low();
57 Timer::after(Duration::from_millis(150)).await;
58 led.set_high();
59 Timer::after(Duration::from_millis(150)).await;
60 }
61
62 // Pause between letters
63 Timer::after(Duration::from_millis(300)).await;
64
65 // O: three long blinks
66 for _ in 0..3 {
67 led.set_low();
68 Timer::after(Duration::from_millis(450)).await;
69 led.set_high();
70 Timer::after(Duration::from_millis(150)).await;
71 }
72
73 // Pause between letters
74 Timer::after(Duration::from_millis(300)).await;
75
76 // S: three short blinks
77 for _ in 0..3 {
78 led.set_low();
79 Timer::after(Duration::from_millis(150)).await;
80 led.set_high();
81 Timer::after(Duration::from_millis(150)).await;
82 }
83
84 // Long pause between words (SOS repeats)
85 Timer::after(Duration::from_millis(1000)).await;
86 }
87}
88
89#[cfg(not(feature = "defmt"))]
90#[panic_handler]
91fn panic(_info: &core::panic::PanicInfo) -> ! {
92 loop {}
93}
diff --git a/examples/common/mod.rs b/examples/common/mod.rs
new file mode 100644
index 000000000..7ada4c456
--- /dev/null
+++ b/examples/common/mod.rs
@@ -0,0 +1,45 @@
1//! Shared board-specific helpers for the FRDM-MCXA276 examples.
2//! These live with the examples so the HAL stays generic.
3
4use embassy_mcxa276 as hal;
5use hal::{clocks, pins, reset};
6
7/// Initialize clocks and pin muxing for UART2 debug console.
8/// Safe to call multiple times; writes are idempotent for our use.
9#[allow(dead_code)]
10pub unsafe fn init_uart2(p: &hal::pac::Peripherals) {
11 clocks::ensure_frolf_running(p);
12 clocks::enable_uart2_port2(p);
13 reset::release_reset_port2(p);
14 reset::release_reset_lpuart2(p);
15 pins::configure_uart2_pins_port2();
16 clocks::select_uart2_clock(p);
17}
18
19/// Initialize clocks for the LED GPIO/PORT used by the blink example.
20#[allow(dead_code)]
21pub unsafe fn init_led(p: &hal::pac::Peripherals) {
22 clocks::enable_led_port(p);
23 reset::release_reset_gpio3(p);
24 reset::release_reset_port3(p);
25}
26
27/// Initialize clocks for OSTIMER0 (1 MHz source).
28#[allow(dead_code)]
29pub unsafe fn init_ostimer0(p: &hal::pac::Peripherals) {
30 clocks::ensure_frolf_running(p);
31 clocks::enable_ostimer0(p);
32 reset::release_reset_ostimer0(p);
33 clocks::select_ostimer0_clock_1m(p);
34}
35
36/// Initialize clocks and pin muxing for ADC.
37#[allow(dead_code)]
38pub unsafe fn init_adc(p: &hal::pac::Peripherals) {
39 clocks::ensure_frolf_running(p);
40 clocks::enable_adc(p);
41 reset::release_reset_port1(p);
42 reset::release_reset_adc1(p);
43 pins::configure_adc_pins();
44 clocks::select_adc_clock(p);
45}
diff --git a/examples/hello.rs b/examples/hello.rs
new file mode 100644
index 000000000..591bf2460
--- /dev/null
+++ b/examples/hello.rs
@@ -0,0 +1,126 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa276 as hal;
6use hal::uart;
7
8mod common;
9
10#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
11use defmt_rtt as _;
12#[cfg(feature = "defmt")]
13use panic_probe as _;
14#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
15use rtt_target as _;
16
17/// Simple helper to write a byte as hex to UART
18fn write_hex_byte(uart: &hal::uart::Uart<hal::uart::Lpuart2>, byte: u8) {
19 const HEX_DIGITS: &[u8] = b"0123456789ABCDEF";
20 uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]);
21 uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]);
22}
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let p = hal::init(hal::config::Config::default());
27
28 #[cfg(feature = "defmt")]
29 defmt::info!("boot");
30
31 // Board-level init for UART2 clocks and pins.
32 unsafe {
33 common::init_uart2(hal::pac());
34 }
35
36 // Get UART source frequency from clock configuration
37 // Using hardcoded frequency for now - dynamic detection may have issues
38 let src = 12_000_000; // FRO_LF_DIV at 12MHz with DIV=0
39 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src));
40
41 // Print welcome message before any async delays to guarantee early console output
42 uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n");
43 uart.write_str_blocking("Available commands:\r\n");
44 uart.write_str_blocking(" help - Show this help\r\n");
45 uart.write_str_blocking(" echo <text> - Echo back the text\r\n");
46 uart.write_str_blocking(" hex <byte> - Display byte in hex (0-255)\r\n");
47 uart.write_str_blocking("Type a command: ");
48
49 let mut buffer = [0u8; 64];
50 let mut buf_idx = 0;
51
52 loop {
53 // Read a byte from UART
54 let byte = uart.read_byte_blocking();
55
56 // Echo the character back
57 if byte == b'\r' || byte == b'\n' {
58 // Enter pressed - process command
59 uart.write_str_blocking("\r\n");
60
61 if buf_idx > 0 {
62 let command = &buffer[0..buf_idx];
63
64 if command == b"help" {
65 uart.write_str_blocking("Available commands:\r\n");
66 uart.write_str_blocking(" help - Show this help\r\n");
67 uart.write_str_blocking(" echo <text> - Echo back the text\r\n");
68 uart.write_str_blocking(" hex <byte> - Display byte in hex (0-255)\r\n");
69 } else if command.starts_with(b"echo ") && command.len() > 5 {
70 uart.write_str_blocking("Echo: ");
71 uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or(""));
72 uart.write_str_blocking("\r\n");
73 } else if command.starts_with(b"hex ") && command.len() > 4 {
74 // Parse the byte value
75 let num_str = &command[4..];
76 if let Ok(num) = parse_u8(num_str) {
77 uart.write_str_blocking("Hex: 0x");
78 write_hex_byte(&uart, num);
79 uart.write_str_blocking("\r\n");
80 } else {
81 uart.write_str_blocking("Invalid number for hex command\r\n");
82 }
83 } else if command.len() > 0 {
84 uart.write_str_blocking("Unknown command: ");
85 uart.write_str_blocking(core::str::from_utf8(command).unwrap_or(""));
86 uart.write_str_blocking("\r\n");
87 }
88 }
89
90 // Reset buffer and prompt
91 buf_idx = 0;
92 uart.write_str_blocking("Type a command: ");
93 } else if byte == 8 || byte == 127 {
94 // Backspace
95 if buf_idx > 0 {
96 buf_idx -= 1;
97 uart.write_str_blocking("\x08 \x08"); // Erase character
98 }
99 } else if buf_idx < buffer.len() - 1 {
100 // Regular character
101 buffer[buf_idx] = byte;
102 buf_idx += 1;
103 uart.write_byte(byte);
104 }
105 }
106}
107
108/// Simple parser for u8 from ASCII bytes
109fn parse_u8(bytes: &[u8]) -> Result<u8, ()> {
110 let mut result = 0u8;
111 for &b in bytes {
112 if b >= b'0' && b <= b'9' {
113 result = result.checked_mul(10).ok_or(())?;
114 result = result.checked_add(b - b'0').ok_or(())?;
115 } else {
116 return Err(());
117 }
118 }
119 Ok(result)
120}
121
122#[cfg(not(feature = "defmt"))]
123#[panic_handler]
124fn panic(_info: &core::panic::PanicInfo) -> ! {
125 loop {}
126}
diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs
new file mode 100644
index 000000000..88f256096
--- /dev/null
+++ b/examples/lpuart_buffered.rs
@@ -0,0 +1,88 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa276 as hal;
6use embassy_mcxa276::interrupt::typelevel::Handler;
7use embassy_mcxa276::lpuart;
8use embassy_mcxa276::lpuart::buffered::BufferedLpuart;
9
10use embedded_io_async::{Read, Write};
11
12use embassy_mcxa276::bind_interrupts;
13
14mod common;
15
16// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver
17bind_interrupts!(struct Irqs {
18 LPUART2 => lpuart::buffered::BufferedInterruptHandler::<lpuart::lib::peripherals::LPUART2>;
19});
20
21// Wrapper function for the interrupt handler
22unsafe extern "C" fn lpuart2_handler() {
23 lpuart::buffered::BufferedInterruptHandler::<lpuart::lib::peripherals::LPUART2>::on_interrupt();
24}
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let _p = hal::init(hal::config::Config::default());
29 let p2 = lpuart::lib::init();
30
31 unsafe {
32 hal::interrupt::install_irq_handler(mcxa276_pac::Interrupt::LPUART2, lpuart2_handler);
33 }
34
35 // Configure NVIC for LPUART2
36 hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3);
37
38 unsafe {
39 common::init_uart2(hal::pac());
40 common::init_ostimer0(hal::pac());
41 }
42
43 // UART configuration (enable both TX and RX)
44 let config = lpuart::Config {
45 baudrate_bps: 115_200,
46 enable_tx: true,
47 enable_rx: true,
48 rx_fifo_watermark: 0,
49 tx_fifo_watermark: 0,
50 ..Default::default()
51 };
52
53 let mut tx_buf = [0u8; 256];
54 let mut rx_buf = [0u8; 256];
55
56 // Create a buffered LPUART2 instance with both TX and RX
57 let mut uart = BufferedLpuart::new(
58 p2.LPUART2,
59 p2.PIO2_2, // TX pin
60 p2.PIO2_3, // RX pin
61 Irqs,
62 &mut tx_buf,
63 &mut rx_buf,
64 config,
65 )
66 .unwrap();
67
68 // Split into TX and RX parts
69 let (tx, rx) = uart.split_ref();
70
71 tx.write(b"Hello buffered LPUART.\r\n").await.unwrap();
72 tx.write(b"Type characters to echo them back.\r\n")
73 .await
74 .unwrap();
75
76 // Echo loop
77 let mut buf = [0u8; 4];
78 loop {
79 rx.read_exact(&mut buf[..]).await.unwrap();
80 tx.write_all(&buf[..]).await.unwrap();
81 }
82}
83
84#[cfg(not(feature = "defmt"))]
85#[panic_handler]
86fn panic(_info: &core::panic::PanicInfo) -> ! {
87 loop {}
88}
diff --git a/examples/lpuart_polling.rs b/examples/lpuart_polling.rs
new file mode 100644
index 000000000..c83c959e8
--- /dev/null
+++ b/examples/lpuart_polling.rs
@@ -0,0 +1,67 @@
1#![no_std]
2#![no_main]
3
4use crate::hal::lpuart::{lib, Config, Lpuart};
5use embassy_executor::Spawner;
6use embassy_mcxa276 as hal;
7
8#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
9use defmt_rtt as _;
10#[cfg(feature = "defmt")]
11use panic_probe as _;
12#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
13use rtt_target as _;
14
15mod common;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let _p = hal::init(hal::config::Config::default());
20 let p2 = lib::init();
21
22 #[cfg(feature = "defmt")]
23 defmt::info!("boot");
24
25 // Board-level init for UART2 clocks and pins.
26 unsafe {
27 common::init_uart2(hal::pac());
28 }
29
30 // Create UART configuration
31 let config = Config {
32 baudrate_bps: 115_200,
33 enable_tx: true,
34 enable_rx: true,
35 ..Default::default()
36 };
37
38 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
39 let lpuart = Lpuart::new_blocking(
40 p2.LPUART2, // Peripheral
41 p2.PIO2_2, // TX pin
42 p2.PIO2_3, // RX pin
43 config,
44 )
45 .unwrap();
46
47 // Split into separate TX and RX parts
48 let (mut tx, mut rx) = lpuart.split();
49
50 // Write hello messages
51 tx.blocking_write(b"Hello world.\r\n").unwrap();
52 tx.blocking_write(b"Echoing. Type characters...\r\n")
53 .unwrap();
54
55 // Echo loop
56 loop {
57 let mut buf = [0u8; 1];
58 rx.blocking_read(&mut buf).unwrap();
59 tx.blocking_write(&buf).unwrap();
60 }
61}
62
63#[cfg(not(feature = "defmt"))]
64#[panic_handler]
65fn panic(_info: &core::panic::PanicInfo) -> ! {
66 loop {}
67}
diff --git a/examples/ostimer_alarm.rs b/examples/ostimer_alarm.rs
new file mode 100644
index 000000000..823e37c15
--- /dev/null
+++ b/examples/ostimer_alarm.rs
@@ -0,0 +1,126 @@
1#![no_std]
2#![no_main]
3
4use core::sync::atomic::{AtomicBool, Ordering};
5use cortex_m;
6use embassy_executor::Spawner;
7use embassy_mcxa276 as hal;
8use hal::uart;
9
10mod common;
11
12#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
13use defmt_rtt as _;
14#[cfg(feature = "defmt")]
15use panic_probe as _;
16#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
17use rtt_target as _;
18
19use embassy_mcxa276::bind_interrupts;
20
21// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed.
22bind_interrupts!(struct Irqs {
23 OS_EVENT => hal::ostimer::time_driver::OsEventHandler;
24});
25
26#[used]
27#[no_mangle]
28static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT;
29
30// Global flag for alarm callback
31static ALARM_FLAG: AtomicBool = AtomicBool::new(false);
32
33// Alarm callback function
34fn alarm_callback() {
35 ALARM_FLAG.store(true, Ordering::Release);
36}
37
38#[embassy_executor::main]
39async fn main(_spawner: Spawner) {
40 let p = hal::init(hal::config::Config::default());
41
42 // Enable/clock OSTIMER0 and UART2 before touching their registers
43 unsafe {
44 common::init_ostimer0(hal::pac());
45 }
46 unsafe {
47 common::init_uart2(hal::pac());
48 }
49 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
50 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src));
51 uart.write_str_blocking("OSTIMER Alarm Example\n");
52
53 // Initialize embassy-time global driver backed by OSTIMER0
54 hal::ostimer::time_driver::init(
55 hal::config::Config::default().time_interrupt_priority,
56 1_000_000,
57 );
58
59 // Create OSTIMER instance
60 let config = hal::ostimer::Config {
61 init_match_max: true,
62 clock_frequency_hz: 1_000_000, // 1MHz
63 };
64 let ostimer = hal::ostimer::Ostimer::<hal::ostimer::Ostimer0>::new(p.OSTIMER0, config, hal::pac());
65
66 // Create alarm with callback
67 let alarm = hal::ostimer::Alarm::new()
68 .with_callback(alarm_callback)
69 .with_flag(&ALARM_FLAG);
70
71 uart.write_str_blocking("Scheduling alarm for 2 seconds...\n");
72
73 // Schedule alarm to expire in 2 seconds (2,000,000 microseconds)
74 let scheduled = ostimer.schedule_alarm_delay(&alarm, 2_000_000);
75 if scheduled {
76 uart.write_str_blocking("Alarm scheduled successfully\n");
77 } else {
78 uart.write_str_blocking("Failed to schedule alarm (would exceed timer capacity)\n");
79 return;
80 }
81
82 // Wait for alarm to expire
83 loop {
84 // Check if alarm has expired
85 if ALARM_FLAG.load(Ordering::Acquire) {
86 uart.write_str_blocking("Alarm expired! Callback executed.\n");
87 break;
88 }
89
90 // Busy wait - don't use Timer::after_millis as it interferes with alarm MATCH
91 for _ in 0..100000 {
92 cortex_m::asm::nop();
93 }
94 }
95
96 // Demonstrate canceling an alarm
97 uart.write_str_blocking("Scheduling another alarm for 3 seconds...\n");
98 ALARM_FLAG.store(false, Ordering::Release); // Reset flag
99
100 let scheduled = ostimer.schedule_alarm_delay(&alarm, 3_000_000);
101 if scheduled {
102 uart.write_str_blocking("Alarm scheduled. Waiting 1 second then canceling...\n");
103
104 // Wait 1 second
105 embassy_time::Timer::after_millis(1000).await;
106
107 // Cancel the alarm
108 ostimer.cancel_alarm(&alarm);
109 uart.write_str_blocking("Alarm canceled\n");
110
111 // Check immediately if alarm flag is set
112 if !ALARM_FLAG.load(Ordering::Acquire) {
113 uart.write_str_blocking("Alarm was successfully canceled\n");
114 } else {
115 uart.write_str_blocking("Alarm fired despite cancellation\n");
116 }
117 }
118
119 uart.write_str_blocking("Example complete\n");
120}
121
122#[cfg(not(feature = "defmt"))]
123#[panic_handler]
124fn panic(_info: &core::panic::PanicInfo) -> ! {
125 loop {}
126}
diff --git a/examples/ostimer_async.rs b/examples/ostimer_async.rs
new file mode 100644
index 000000000..181ce58ef
--- /dev/null
+++ b/examples/ostimer_async.rs
@@ -0,0 +1,76 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa276 as hal;
6use hal::uart;
7
8mod common;
9
10#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
11use defmt_rtt as _;
12#[cfg(feature = "defmt")]
13use panic_probe as _;
14#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
15use rtt_target as _;
16
17use embassy_time::{Duration, Timer};
18
19use embassy_mcxa276::bind_interrupts;
20
21// Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed.
22bind_interrupts!(struct Irqs {
23 OS_EVENT => hal::ostimer::time_driver::OsEventHandler;
24});
25
26#[used]
27#[no_mangle]
28static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT;
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let _p = hal::init(hal::config::Config::default());
33
34 // Enable/clock OSTIMER0 and UART2 before touching their registers
35 unsafe {
36 common::init_ostimer0(hal::pac());
37 }
38 unsafe {
39 common::init_uart2(hal::pac());
40 }
41 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
42 let uart = uart::Uart::<uart::Lpuart2>::new(_p.LPUART2, uart::Config::new(src));
43 uart.write_str_blocking("boot\n");
44
45 // Avoid mass NVIC writes here; DefaultHandler now safely returns.
46
47 // Initialize embassy-time global driver backed by OSTIMER0 (re-enables OS_EVENT with priority)
48 // The bind_interrupts! macro handles handler binding automatically
49
50 // Initialize OSTIMER with default 1MHz frequency
51 // Adjust this value to match your actual OSTIMER clock frequency
52 hal::ostimer::time_driver::init(
53 hal::config::Config::default().time_interrupt_priority,
54 1_000_000,
55 );
56
57 // Removed force-pend; rely on real hardware match to trigger OS_EVENT.
58
59 // Log using defmt if enabled
60 #[cfg(feature = "defmt")]
61 defmt::info!("OSTIMER async example starting...");
62
63 loop {
64 #[cfg(feature = "defmt")]
65 defmt::info!("tick");
66 #[cfg(not(feature = "defmt"))]
67 uart.write_str_blocking("tick\n");
68 Timer::after(Duration::from_millis(1000)).await;
69 }
70}
71
72#[cfg(not(feature = "defmt"))]
73#[panic_handler]
74fn panic(_info: &core::panic::PanicInfo) -> ! {
75 loop {}
76}
diff --git a/examples/ostimer_counter.rs b/examples/ostimer_counter.rs
new file mode 100644
index 000000000..3af0f03f2
--- /dev/null
+++ b/examples/ostimer_counter.rs
@@ -0,0 +1,142 @@
1//! # OSTIMER Counter Reading and Reset Example
2//!
3//! This example demonstrates the new timer counter reading and reset functionality
4//! of the OSTIMER driver.
5
6#![no_std]
7#![no_main]
8
9use embassy_executor::Spawner;
10use embassy_time::{Duration, Timer};
11
12#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
13use defmt_rtt as _;
14#[cfg(feature = "defmt")]
15use panic_probe as _;
16#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
17use rtt_target as _;
18
19use embassy_mcxa276 as hal;
20use hal::bind_interrupts;
21
22mod common;
23
24bind_interrupts!(struct Irqs {
25 OS_EVENT => hal::ostimer::time_driver::OsEventHandler;
26});
27
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30 let p = hal::init(Default::default());
31
32 // Enable/clock OSTIMER0 and UART2 before touching their registers
33 unsafe {
34 common::init_ostimer0(hal::pac());
35 }
36 unsafe {
37 common::init_uart2(hal::pac());
38 }
39 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
40 let mut uart = hal::uart::Uart::<hal::uart::Lpuart2>::new(p.LPUART2, hal::uart::Config::new(src));
41
42 uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n");
43
44 // Initialize the OSTIMER time driver
45 hal::ostimer::time_driver::init(
46 hal::interrupt::Priority::from(3),
47 1_000_000, // 1MHz clock
48 );
49
50 // Create OSTIMER instance
51 let ostimer = hal::ostimer::Ostimer::<hal::ostimer::Ostimer0>::new(
52 p.OSTIMER0,
53 hal::ostimer::Config {
54 init_match_max: true,
55 clock_frequency_hz: 1_000_000,
56 },
57 hal::pac(),
58 );
59
60 // Read initial counter value
61 let initial_counter = ostimer.now();
62 uart.write_str_blocking("Initial counter value: ");
63 write_u64(&mut uart, initial_counter);
64 uart.write_str_blocking("\n");
65
66 // Wait a bit to let counter increment
67 Timer::after(Duration::from_millis(100)).await;
68
69 // Read counter again
70 let counter_after_wait = ostimer.now();
71 uart.write_str_blocking("Counter after 100ms wait: ");
72 write_u64(&mut uart, counter_after_wait);
73 uart.write_str_blocking("\n");
74 uart.write_str_blocking("Difference: ");
75 write_u64(&mut uart, counter_after_wait - initial_counter);
76 uart.write_str_blocking(" ticks\n");
77
78 // Reset the timer
79 uart.write_str_blocking("Resetting timer...\n");
80 ostimer.reset(hal::pac());
81
82 // Read counter after reset
83 let counter_after_reset = ostimer.now();
84 uart.write_str_blocking("Counter after reset: ");
85 write_u64(&mut uart, counter_after_reset);
86 uart.write_str_blocking("\n");
87
88 // Wait again to verify timer is working
89 Timer::after(Duration::from_millis(50)).await;
90
91 let final_counter = ostimer.now();
92 uart.write_str_blocking("Counter after another 50ms: ");
93 write_u64(&mut uart, final_counter);
94 uart.write_str_blocking("\n");
95 uart.write_str_blocking("Difference after reset: ");
96 write_u64(&mut uart, final_counter - counter_after_reset);
97 uart.write_str_blocking(" ticks\n");
98
99 uart.write_str_blocking("Example complete\n");
100}
101
102// Helper function to write a u64 value as decimal string
103fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) {
104 if value == 0 {
105 uart.write_str_blocking("0");
106 return;
107 }
108
109 let mut buffer = [0u8; 20]; // Enough for max u64
110 let mut i = 0;
111 let mut v = value;
112
113 while v > 0 {
114 buffer[i] = b'0' + (v % 10) as u8;
115 v /= 10;
116 i += 1;
117 }
118
119 // Write digits in reverse order
120 while i > 0 {
121 i -= 1;
122 match buffer[i] {
123 b'0' => uart.write_str_blocking("0"),
124 b'1' => uart.write_str_blocking("1"),
125 b'2' => uart.write_str_blocking("2"),
126 b'3' => uart.write_str_blocking("3"),
127 b'4' => uart.write_str_blocking("4"),
128 b'5' => uart.write_str_blocking("5"),
129 b'6' => uart.write_str_blocking("6"),
130 b'7' => uart.write_str_blocking("7"),
131 b'8' => uart.write_str_blocking("8"),
132 b'9' => uart.write_str_blocking("9"),
133 _ => uart.write_str_blocking("?"),
134 }
135 }
136}
137
138#[cfg(not(feature = "defmt"))]
139#[panic_handler]
140fn panic(_info: &core::panic::PanicInfo) -> ! {
141 loop {}
142}
diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs
new file mode 100644
index 000000000..4470b65fd
--- /dev/null
+++ b/examples/ostimer_race_test.rs
@@ -0,0 +1,411 @@
1//! # OSTIMER Race Condition Test
2//!
3//! This example tests for race conditions in the OSTIMER driver by:
4//! - Scheduling alarms sequentially (hardware limitation: only one at a time)
5//! - Reading the counter during interrupt-heavy periods
6//! - Testing concurrent timer operations
7//! - Stress testing interrupt handling
8
9#![no_std]
10#![no_main]
11
12use embassy_executor::Spawner;
13use embassy_time::{Duration, Timer};
14
15#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
16use defmt_rtt as _;
17#[cfg(feature = "defmt")]
18use panic_probe as _;
19#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
20use rtt_target as _;
21
22use core::sync::atomic::{AtomicU32, Ordering};
23use embassy_mcxa276 as hal;
24use hal::bind_interrupts;
25
26mod common;
27
28bind_interrupts!(struct Irqs {
29 OS_EVENT => hal::ostimer::time_driver::OsEventHandler;
30});
31
32#[used]
33#[no_mangle]
34static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT;
35
36// Global counters for race condition detection
37static ALARM_CALLBACK_COUNT: AtomicU32 = AtomicU32::new(0);
38static INTERRUPT_COUNT: AtomicU32 = AtomicU32::new(0);
39static RACE_DETECTED: AtomicU32 = AtomicU32::new(0);
40
41// Alarm callback function
42fn alarm_callback() {
43 let _count = ALARM_CALLBACK_COUNT.fetch_add(1, Ordering::SeqCst);
44 INTERRUPT_COUNT.fetch_add(1, Ordering::SeqCst);
45
46 // Simulate some work in the callback to increase chance of races
47 for _ in 0..10 {
48 cortex_m::asm::nop();
49 }
50}
51
52fn report_default_handler(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>) {
53 let snapshot = hal::interrupt::default_handler_snapshot();
54 if snapshot.count == 0 {
55 return;
56 }
57
58 uart.write_str_blocking("WARNING: DefaultHandler executed ");
59 write_u32(uart, snapshot.count);
60 uart.write_str_blocking(" time(s). Vector=");
61 write_u32(uart, snapshot.vector as u32);
62 uart.write_str_blocking(" CFSR=0x");
63 write_hex32(uart, snapshot.cfsr);
64 uart.write_str_blocking(" HFSR=0x");
65 write_hex32(uart, snapshot.hfsr);
66 uart.write_str_blocking(" PC=0x");
67 write_hex32(uart, snapshot.stacked_pc);
68 uart.write_str_blocking(" LR=0x");
69 write_hex32(uart, snapshot.stacked_lr);
70 uart.write_str_blocking(" SP=0x");
71 write_hex32(uart, snapshot.stacked_sp);
72 uart.write_str_blocking("\n");
73
74 hal::interrupt::clear_default_handler_snapshot();
75}
76
77#[embassy_executor::main]
78async fn main(_spawner: Spawner) {
79 let p = hal::init(Default::default());
80
81 // Enable/clock OSTIMER0 and UART2 before touching their registers
82 unsafe {
83 common::init_ostimer0(hal::pac());
84 }
85 unsafe {
86 common::init_uart2(hal::pac());
87 }
88 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
89 let mut uart = hal::uart::Uart::<hal::uart::Lpuart2>::new(p.LPUART2, hal::uart::Config::new(src));
90
91 uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n");
92
93 // The bind_interrupts! macro handles handler binding automatically
94
95 // Initialize the OSTIMER time driver FIRST
96 hal::ostimer::time_driver::init(
97 hal::interrupt::Priority::from(3),
98 1_000_000, // 1MHz clock
99 );
100
101 uart.write_str_blocking("Time driver initialized\n");
102
103 // Create OSTIMER instance
104 let ostimer = hal::ostimer::Ostimer::<hal::ostimer::Ostimer0>::new(
105 p.OSTIMER0,
106 hal::ostimer::Config {
107 init_match_max: true,
108 clock_frequency_hz: 1_000_000,
109 },
110 hal::pac(),
111 );
112
113 uart.write_str_blocking("OSTIMER instance created\n");
114
115 // Test 1: Sequential alarm scheduling (OSTIMER only supports one alarm at a time)
116 uart.write_str_blocking("Test 1: Sequential alarm scheduling...\n");
117 test_rapid_alarms(&ostimer, &mut uart).await;
118 report_default_handler(&mut uart);
119
120 // Test 2: Counter reading during interrupts
121 uart.write_str_blocking("Test 2: Counter reading during interrupts...\n");
122 test_counter_reading_during_interrupts(&ostimer, &mut uart).await;
123 report_default_handler(&mut uart);
124
125 // Test 3: Concurrent timer operations
126 uart.write_str_blocking("Test 3: Concurrent timer operations...\n");
127 test_concurrent_operations(&ostimer, &mut uart).await;
128 report_default_handler(&mut uart);
129
130 // Test 4: Timer reset during operation
131 uart.write_str_blocking("Test 4: Timer reset during operation...\n");
132 test_reset_during_operation(&ostimer, &mut uart, hal::pac()).await;
133 report_default_handler(&mut uart);
134
135 // Report results
136 uart.write_str_blocking("Race condition test complete\n");
137 uart.write_str_blocking("Callback count: ");
138 write_u32(&mut uart, ALARM_CALLBACK_COUNT.load(Ordering::SeqCst));
139 uart.write_str_blocking("\nInterrupt count: ");
140 write_u32(&mut uart, INTERRUPT_COUNT.load(Ordering::SeqCst));
141 uart.write_str_blocking("\nRaces detected: ");
142 write_u32(&mut uart, RACE_DETECTED.load(Ordering::SeqCst));
143 uart.write_str_blocking("\n");
144}
145
146// Test rapid alarm scheduling to stress interrupt handling
147async fn test_rapid_alarms(
148 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
149 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>,
150) {
151 let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst);
152
153 // Schedule 10 alarms sequentially (OSTIMER only supports one alarm at a time)
154 for _i in 0..10 {
155 let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback);
156 let delay_us = 1000; // 1ms delay for each alarm
157 if ostimer.schedule_alarm_delay(&alarm, delay_us) {
158 // Wait for this alarm to complete before scheduling the next
159 Timer::after(Duration::from_micros(delay_us + 100)).await;
160 report_default_handler(uart);
161 } else {
162 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
163 uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm (match not ready)\n");
164 }
165 }
166
167 // All alarms should have completed by now
168 let final_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst);
169 let expected_count = initial_count + 10;
170
171 if final_count != expected_count {
172 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
173 uart.write_str_blocking("ERROR: Expected ");
174 write_u32(uart, expected_count);
175 uart.write_str_blocking(" callbacks, got ");
176 write_u32(uart, final_count);
177 uart.write_str_blocking("\n");
178 } else {
179 uart.write_str_blocking("PASS: All rapid alarms executed\n");
180 }
181}
182
183// Test reading counter while interrupts are firing
184async fn test_counter_reading_during_interrupts(
185 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
186 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>,
187) {
188 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
189
190 // Schedule an alarm that will fire soon
191 let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback);
192 if !ostimer.schedule_alarm_delay(&alarm, 500) {
193 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
194 uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before counter stress\n");
195 }
196
197 // While alarm is pending, read the counter many times rapidly
198 // This tests if counter reading is atomic and doesn't get corrupted by interrupts
199 let mut last_counter = ostimer.now();
200 let mut consistent_reads = 0;
201 let mut total_reads = 0;
202
203 for _ in 0..1000 {
204 let current_counter = ostimer.now();
205 total_reads += 1;
206
207 // Check if counter is monotonically increasing (basic sanity check)
208 if current_counter >= last_counter {
209 consistent_reads += 1;
210 }
211 last_counter = current_counter;
212
213 // Small delay between reads
214 for _ in 0..10 {
215 cortex_m::asm::nop();
216 }
217
218 report_default_handler(uart);
219 }
220
221 // Wait for alarm to complete
222 Timer::after(Duration::from_millis(1)).await;
223
224 let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
225
226 if consistent_reads == total_reads {
227 uart.write_str_blocking("PASS: Counter reading consistent during interrupts\n");
228 } else {
229 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
230 uart.write_str_blocking("ERROR: Counter reading inconsistent: ");
231 write_u32(uart, consistent_reads);
232 uart.write_str_blocking("/");
233 write_u32(uart, total_reads);
234 uart.write_str_blocking(" consistent\n");
235 }
236
237 if final_interrupt_count > initial_interrupt_count {
238 uart.write_str_blocking("PASS: Interrupt fired during counter reading test\n");
239 } else {
240 uart.write_str_blocking("WARNING: No interrupt fired during counter reading test\n");
241 }
242}
243
244// Test concurrent timer operations (embassy-time + alarms)
245async fn test_concurrent_operations(
246 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
247 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>,
248) {
249 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
250
251 // Start an embassy-time timer
252 let timer_future = Timer::after(Duration::from_millis(2));
253
254 // Schedule an alarm that should fire before the timer
255 let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback);
256 if !ostimer.schedule_alarm_delay(&alarm, 1000) {
257 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
258 uart.write_str_blocking(
259 "ERROR: Failed to program OSTIMER alarm before concurrent operations\n",
260 );
261 }
262
263 // Wait for both to complete
264 timer_future.await;
265
266 let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
267
268 if final_interrupt_count > initial_interrupt_count {
269 uart.write_str_blocking("PASS: Concurrent operations completed\n");
270 } else {
271 uart.write_str_blocking("WARNING: No interrupts during concurrent operations\n");
272 }
273}
274
275// Test timer reset during active operations
276async fn test_reset_during_operation(
277 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
278 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>,
279 peripherals: &hal::pac::Peripherals,
280) {
281 let initial_counter = ostimer.now();
282
283 // Schedule an alarm
284 let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback);
285 if !ostimer.schedule_alarm_delay(&alarm, 2000) {
286 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
287 uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before reset test\n");
288 }
289
290 // Wait a bit then reset the timer
291 Timer::after(Duration::from_millis(1)).await;
292 ostimer.reset(peripherals);
293
294 // Check counter after reset
295 let counter_after_reset = ostimer.now();
296
297 // Wait to see if the alarm still fires (it shouldn't after reset)
298 Timer::after(Duration::from_millis(2)).await;
299
300 let final_counter = ostimer.now();
301
302 if counter_after_reset < initial_counter {
303 uart.write_str_blocking("PASS: Timer reset successful\n");
304 } else {
305 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
306 uart.write_str_blocking("ERROR: Timer reset may have failed\n");
307 }
308
309 uart.write_str_blocking("Counter progression after reset: ");
310 write_u64(uart, initial_counter);
311 uart.write_str_blocking(" -> ");
312 write_u64(uart, counter_after_reset);
313 uart.write_str_blocking(" -> ");
314 write_u64(uart, final_counter);
315 uart.write_str_blocking("\n");
316}
317
318// Helper function to write a u32 value as decimal string
319fn write_u32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) {
320 if value == 0 {
321 uart.write_str_blocking("0");
322 return;
323 }
324
325 let mut buffer = [0u8; 10]; // Enough for max u32
326 let mut i = 0;
327 let mut v = value;
328
329 while v > 0 {
330 buffer[i] = b'0' + (v % 10) as u8;
331 v /= 10;
332 i += 1;
333 }
334
335 // Write digits in reverse order
336 while i > 0 {
337 i -= 1;
338 match buffer[i] {
339 b'0' => uart.write_str_blocking("0"),
340 b'1' => uart.write_str_blocking("1"),
341 b'2' => uart.write_str_blocking("2"),
342 b'3' => uart.write_str_blocking("3"),
343 b'4' => uart.write_str_blocking("4"),
344 b'5' => uart.write_str_blocking("5"),
345 b'6' => uart.write_str_blocking("6"),
346 b'7' => uart.write_str_blocking("7"),
347 b'8' => uart.write_str_blocking("8"),
348 b'9' => uart.write_str_blocking("9"),
349 _ => uart.write_str_blocking("?"),
350 }
351 }
352}
353
354fn write_hex32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) {
355 let mut buf = [b'0'; 8];
356 let mut tmp = value;
357 for i in (0..8).rev() {
358 let digit = (tmp & 0xF) as u8;
359 buf[i] = match digit {
360 0..=9 => b'0' + digit,
361 10..=15 => b'A' + (digit - 10),
362 _ => b'?',
363 };
364 tmp >>= 4;
365 }
366 for b in &buf {
367 uart.write_byte(*b);
368 }
369}
370
371// Helper function to write a u64 value as decimal string
372fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) {
373 if value == 0 {
374 uart.write_str_blocking("0");
375 return;
376 }
377
378 let mut buffer = [0u8; 20]; // Enough for max u64
379 let mut i = 0;
380 let mut v = value;
381
382 while v > 0 {
383 buffer[i] = b'0' + (v % 10) as u8;
384 v /= 10;
385 i += 1;
386 }
387
388 // Write digits in reverse order
389 while i > 0 {
390 i -= 1;
391 match buffer[i] {
392 b'0' => uart.write_str_blocking("0"),
393 b'1' => uart.write_str_blocking("1"),
394 b'2' => uart.write_str_blocking("2"),
395 b'3' => uart.write_str_blocking("3"),
396 b'4' => uart.write_str_blocking("4"),
397 b'5' => uart.write_str_blocking("5"),
398 b'6' => uart.write_str_blocking("6"),
399 b'7' => uart.write_str_blocking("7"),
400 b'8' => uart.write_str_blocking("8"),
401 b'9' => uart.write_str_blocking("9"),
402 _ => uart.write_str_blocking("?"),
403 }
404 }
405}
406
407#[cfg(not(feature = "defmt"))]
408#[panic_handler]
409fn panic(_info: &core::panic::PanicInfo) -> ! {
410 loop {}
411}
diff --git a/examples/rtc_alarm.rs b/examples/rtc_alarm.rs
new file mode 100644
index 000000000..8f4ff1623
--- /dev/null
+++ b/examples/rtc_alarm.rs
@@ -0,0 +1,105 @@
1#![no_std]
2#![no_main]
3
4
5use embassy_mcxa276 as hal;
6use cortex_m;
7use embassy_executor::Spawner;
8use hal::rtc::{RtcDateTime, RtcInterruptEnable};
9use hal::uart;
10use hal::InterruptExt;
11
12mod common;
13
14type MyRtc = hal::rtc::Rtc<hal::rtc::Rtc0>;
15
16#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
17use defmt_rtt as _;
18#[cfg(feature = "defmt")]
19use panic_probe as _;
20#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
21use rtt_target as _;
22
23use embassy_mcxa276::bind_interrupts;
24bind_interrupts!(struct Irqs {
25 RTC => hal::rtc::RtcHandler;
26});
27
28#[used]
29#[no_mangle]
30static KEEP_RTC: unsafe extern "C" fn() = RTC;
31
32#[embassy_executor::main]
33async fn main(_spawner: Spawner) {
34
35 let p = hal::init(hal::config::Config::default());
36
37 unsafe {
38 common::init_uart2(hal::pac());
39 }
40
41 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
42 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src));
43
44 uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n");
45
46 unsafe { hal::clocks::init_fro16k(hal::pac()) };
47
48 let rtc_config = hal::rtc::get_default_config();
49
50 let rtc = MyRtc::new(p.RTC0, rtc_config);
51
52 let now = RtcDateTime {
53 year: 2025,
54 month: 10,
55 day: 15,
56 hour: 14,
57 minute: 30,
58 second: 0,
59 };
60
61
62 rtc.stop();
63
64 uart.write_str_blocking("Time set to: 2025-10-15 14:30:00\r\n");
65 rtc.set_datetime(now);
66
67 let mut alarm = now;
68 alarm.second += 10;
69
70 rtc.set_alarm(alarm);
71 uart.write_str_blocking("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)\r\n");
72
73 rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE);
74
75 unsafe {
76 hal::interrupt::RTC.enable();
77 }
78
79 unsafe {
80 cortex_m::interrupt::enable();
81 }
82
83 rtc.start();
84
85 uart.write_str_blocking("RTC started, waiting for alarm...\r\n");
86
87 loop {
88 if rtc.is_alarm_triggered() {
89 uart.write_str_blocking("\r\n*** ALARM TRIGGERED! ***\r\n");
90 break;
91 }
92 }
93
94 uart.write_str_blocking("Example complete - Test PASSED!\r\n");
95
96 loop {
97
98 }
99}
100
101#[cfg(not(feature = "defmt"))]
102#[panic_handler]
103fn panic(_info: &core::panic::PanicInfo) -> ! {
104 loop {}
105}
diff --git a/examples/uart_interrupt.rs b/examples/uart_interrupt.rs
new file mode 100644
index 000000000..b309ce973
--- /dev/null
+++ b/examples/uart_interrupt.rs
@@ -0,0 +1,86 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa276 as hal;
6use hal::interrupt::typelevel::Handler;
7use hal::uart;
8
9mod common;
10
11#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
12use defmt_rtt as _;
13#[cfg(feature = "defmt")]
14use panic_probe as _;
15#[cfg(all(feature = "defmt", feature = "defmt-rtt"))]
16use rtt_target as _;
17
18use embassy_mcxa276::bind_interrupts;
19
20// Bind LPUART2 interrupt to our handler
21bind_interrupts!(struct Irqs {
22 LPUART2 => hal::uart::UartInterruptHandler;
23});
24
25#[used]
26#[no_mangle]
27static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2;
28
29// Wrapper function for the interrupt handler
30unsafe extern "C" fn lpuart2_handler() {
31 hal::uart::UartInterruptHandler::on_interrupt();
32}
33
34#[embassy_executor::main]
35async fn main(_spawner: Spawner) {
36 let _p = hal::init(hal::config::Config::default());
37
38 // Enable/clock UART2 before touching its registers
39 unsafe {
40 common::init_uart2(hal::pac());
41 }
42 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
43 let uart = uart::Uart::<uart::Lpuart2>::new(_p.LPUART2, uart::Config::new(src));
44
45 // Configure LPUART2 interrupt for UART operation BEFORE any UART usage
46 hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3));
47
48 // Manually install the interrupt handler
49 unsafe {
50 hal::interrupt::LPUART2.install_handler(lpuart2_handler);
51 }
52
53 // Print welcome message
54 uart.write_str_blocking("UART interrupt echo demo starting...\r\n");
55 uart.write_str_blocking("Type characters to echo them back.\r\n");
56
57 // Log using defmt if enabled
58 #[cfg(feature = "defmt")]
59 defmt::info!("UART interrupt echo demo starting...");
60
61 loop {
62 // Check if we have received any data
63 if uart.rx_data_available() {
64 if let Some(byte) = uart.try_read_byte() {
65 // Echo it back
66 uart.write_byte(byte);
67 uart.write_str_blocking(" (received)\r\n");
68 }
69 } else {
70 // No data available, wait a bit before checking again
71 cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz
72 }
73 }
74}
75
76#[cfg(feature = "defmt")]
77#[export_name = "_defmt_timestamp"]
78fn defmt_timestamp(_fmt: defmt::Formatter<'_>) {
79 // Return empty timestamp for now
80}
81
82#[cfg(not(feature = "defmt"))]
83#[panic_handler]
84fn panic(_info: &core::panic::PanicInfo) -> ! {
85 loop {}
86}