aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml18
-rw-r--r--examples/Cargo.lock1
-rw-r--r--examples/Cargo.toml4
-rw-r--r--examples/src/bin/blinky.rs13
-rw-r--r--examples/src/bin/ostimer_alarm.rs122
-rw-r--r--examples/src/bin/ostimer_async.rs64
-rw-r--r--examples/src/bin/ostimer_counter.rs139
-rw-r--r--examples/src/bin/ostimer_race_test.rs405
-rw-r--r--src/clocks/mod.rs6
-rw-r--r--src/config.rs2
-rw-r--r--src/lib.rs11
-rw-r--r--src/ostimer.rs88
13 files changed, 98 insertions, 776 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0fb5bfb12..46322c4de 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -328,6 +328,7 @@ source = "git+https://github.com/OpenDevicePartnership/mcxa-pac?rev=3ab4c868f75a
328dependencies = [ 328dependencies = [
329 "cortex-m", 329 "cortex-m",
330 "cortex-m-rt", 330 "cortex-m-rt",
331 "critical-section",
331 "vcell", 332 "vcell",
332] 333]
333 334
diff --git a/Cargo.toml b/Cargo.toml
index 60f836ac3..0ed6995c6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,14 +9,12 @@ categories = ["embedded", "hardware-support", "no-std"]
9 9
10[dependencies] 10[dependencies]
11cortex-m = { version = "0.7", features = ["critical-section-single-core"] } 11cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
12cortex-m-rt = { version = "0.7", features = ["device"] } 12cortex-m-rt = { version = "0.7" }
13critical-section = "1.2.0" 13critical-section = "1.2.0"
14defmt = { version = "1.0", optional = true } 14defmt = { version = "1.0", optional = true }
15embassy-embedded-hal = "0.5.0" 15embassy-embedded-hal = "0.5.0"
16embassy-hal-internal = { version = "0.3.0", features = ["cortex-m", "prio-bits-3"] } 16embassy-hal-internal = { version = "0.3.0", features = ["cortex-m", "prio-bits-3"] }
17embassy-sync = "0.7.2" 17embassy-sync = "0.7.2"
18embassy-time = "0.5.0"
19embassy-time-driver = "0.2.1"
20embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 18embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
21embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 19embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
22embedded-hal-async = { version = "1.0" } 20embedded-hal-async = { version = "1.0" }
@@ -24,10 +22,14 @@ embedded-hal-nb = { version = "1.0" }
24embedded-io = "0.6" 22embedded-io = "0.6"
25embedded-io-async = { version = "0.6.1" } 23embedded-io-async = { version = "0.6.1" }
26heapless = "0.8" 24heapless = "0.8"
27mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt"], rev = "3ab4c868f75a9240bb8fdce24982d34f2273aabf", version = "0.1.0" } 25mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], rev = "3ab4c868f75a9240bb8fdce24982d34f2273aabf", version = "0.1.0" }
28nb = "1.1.0" 26nb = "1.1.0"
29paste = "1.0.15" 27paste = "1.0.15"
30 28
29# `time` dependencies
30embassy-time = { version = "0.5.0", optional = true }
31embassy-time-driver = { version = "0.2.1", optional = true }
32
31[features] 33[features]
32default = [] 34default = []
33 35
@@ -35,6 +37,12 @@ default = []
35# Use with one logger feature: defmt-rtt (preferred) or defmt-uart (fallback) 37# Use with one logger feature: defmt-rtt (preferred) or defmt-uart (fallback)
36defmt = ["dep:defmt"] 38defmt = ["dep:defmt"]
37 39
38rt = [] 40rt = ["cortex-m-rt/device"]
39 41
40unstable-pac = [] 42unstable-pac = []
43
44# Embassy time
45time = [
46 "dep:embassy-time",
47 "dep:embassy-time-driver",
48]
diff --git a/examples/Cargo.lock b/examples/Cargo.lock
index b2ac9a051..14f472cbf 100644
--- a/examples/Cargo.lock
+++ b/examples/Cargo.lock
@@ -446,6 +446,7 @@ source = "git+https://github.com/OpenDevicePartnership/mcxa-pac?rev=3ab4c868f75a
446dependencies = [ 446dependencies = [
447 "cortex-m", 447 "cortex-m",
448 "cortex-m-rt", 448 "cortex-m-rt",
449 "critical-section",
449 "vcell", 450 "vcell",
450] 451]
451 452
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index d03d3d95c..d1c6a2071 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -6,13 +6,13 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8cortex-m = { version = "0.7", features = ["critical-section-single-core"] } 8cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
9cortex-m-rt = { version = "0.7", features = ["device"] } 9cortex-m-rt = { version = "0.7" }
10critical-section = "1.2.0" 10critical-section = "1.2.0"
11defmt = "1.0" 11defmt = "1.0"
12defmt-rtt = "1.0" 12defmt-rtt = "1.0"
13embassy-embedded-hal = "0.5.0" 13embassy-embedded-hal = "0.5.0"
14embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } 14embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false }
15embassy-mcxa = { path = "../", features = ["defmt", "rt", "unstable-pac"] } 15embassy-mcxa = { path = "../", features = ["defmt", "rt", "unstable-pac", "time"] }
16embassy-sync = "0.7.2" 16embassy-sync = "0.7.2"
17embassy-time = "0.5.0" 17embassy-time = "0.5.0"
18embassy-time-driver = "0.2.1" 18embassy-time-driver = "0.2.1"
diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs
index 28d83a12e..ab1e59bdb 100644
--- a/examples/src/bin/blinky.rs
+++ b/examples/src/bin/blinky.rs
@@ -2,29 +2,16 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa::bind_interrupts;
6use embassy_time::Timer; 5use embassy_time::Timer;
7use hal::gpio::{Level, Output}; 6use hal::gpio::{Level, Output};
8use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
9 8
10// Bind only OS_EVENT for timer interrupts
11bind_interrupts!(struct Irqs {
12 OS_EVENT => hal::ostimer::time_driver::OsEventHandler;
13});
14
15#[used]
16#[no_mangle]
17static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT;
18
19#[embassy_executor::main] 9#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 10async fn main(_spawner: Spawner) {
21 let p = hal::init(hal::config::Config::default()); 11 let p = hal::init(hal::config::Config::default());
22 12
23 defmt::info!("Blink example"); 13 defmt::info!("Blink example");
24 14
25 // Initialize embassy-time global driver backed by OSTIMER0
26 hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000);
27
28 let mut red = Output::new(p.P3_18, Level::High); 15 let mut red = Output::new(p.P3_18, Level::High);
29 let mut green = Output::new(p.P3_19, Level::High); 16 let mut green = Output::new(p.P3_19, Level::High);
30 let mut blue = Output::new(p.P3_21, Level::High); 17 let mut blue = Output::new(p.P3_21, Level::High);
diff --git a/examples/src/bin/ostimer_alarm.rs b/examples/src/bin/ostimer_alarm.rs
deleted file mode 100644
index 6d38741b7..000000000
--- a/examples/src/bin/ostimer_alarm.rs
+++ /dev/null
@@ -1,122 +0,0 @@
1#![no_std]
2#![no_main]
3
4use core::sync::atomic::{AtomicBool, Ordering};
5
6use embassy_executor::Spawner;
7use embassy_mcxa::bind_interrupts;
8use embassy_mcxa::clocks::periph_helpers::OstimerClockSel;
9use embassy_mcxa::clocks::PoweredClock;
10use embassy_mcxa::lpuart::{Config, Lpuart};
11use embassy_mcxa_examples::init_uart2_pins;
12use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
13
14// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed.
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// Global flag for alarm callback
24static ALARM_FLAG: AtomicBool = AtomicBool::new(false);
25
26// Alarm callback function
27fn alarm_callback() {
28 ALARM_FLAG.store(true, Ordering::Release);
29}
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let p = hal::init(hal::config::Config::default());
34
35 // Create UART configuration
36 let config = Config {
37 baudrate_bps: 115_200,
38 enable_tx: true,
39 enable_rx: true,
40 ..Default::default()
41 };
42
43 // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX
44 unsafe {
45 init_uart2_pins(hal::pac());
46 }
47 let mut uart = Lpuart::new_blocking(
48 p.LPUART2, // Peripheral
49 p.P2_2, // TX pin
50 p.P2_3, // RX pin
51 config,
52 )
53 .unwrap();
54
55 uart.write_str_blocking("OSTIMER Alarm Example\n");
56
57 // Initialize embassy-time global driver backed by OSTIMER0
58 hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000);
59
60 // Create OSTIMER instance
61 let config = hal::ostimer::Config {
62 init_match_max: true,
63 power: PoweredClock::NormalEnabledDeepSleepDisabled,
64 source: OstimerClockSel::Clk1M,
65 };
66 let ostimer = hal::ostimer::Ostimer::<hal::ostimer::Ostimer0>::new(p.OSTIMER0, config);
67
68 // Create alarm with callback
69 let alarm = hal::ostimer::Alarm::new()
70 .with_callback(alarm_callback)
71 .with_flag(&ALARM_FLAG);
72
73 uart.write_str_blocking("Scheduling alarm for 2 seconds...\n");
74
75 // Schedule alarm to expire in 2 seconds (2,000,000 microseconds)
76 let scheduled = ostimer.schedule_alarm_delay(&alarm, 2_000_000);
77 if scheduled {
78 uart.write_str_blocking("Alarm scheduled successfully\n");
79 } else {
80 uart.write_str_blocking("Failed to schedule alarm (would exceed timer capacity)\n");
81 return;
82 }
83
84 // Wait for alarm to expire
85 loop {
86 // Check if alarm has expired
87 if ALARM_FLAG.load(Ordering::Acquire) {
88 uart.write_str_blocking("Alarm expired! Callback executed.\n");
89 break;
90 }
91
92 // Busy wait - don't use Timer::after_millis as it interferes with alarm MATCH
93 for _ in 0..100000 {
94 cortex_m::asm::nop();
95 }
96 }
97
98 // Demonstrate canceling an alarm
99 uart.write_str_blocking("Scheduling another alarm for 3 seconds...\n");
100 ALARM_FLAG.store(false, Ordering::Release); // Reset flag
101
102 let scheduled = ostimer.schedule_alarm_delay(&alarm, 3_000_000);
103 if scheduled {
104 uart.write_str_blocking("Alarm scheduled. Waiting 1 second then canceling...\n");
105
106 // Wait 1 second
107 embassy_time::Timer::after_millis(1000).await;
108
109 // Cancel the alarm
110 ostimer.cancel_alarm(&alarm);
111 uart.write_str_blocking("Alarm canceled\n");
112
113 // Check immediately if alarm flag is set
114 if !ALARM_FLAG.load(Ordering::Acquire) {
115 uart.write_str_blocking("Alarm was successfully canceled\n");
116 } else {
117 uart.write_str_blocking("Alarm fired despite cancellation\n");
118 }
119 }
120
121 uart.write_str_blocking("Example complete\n");
122}
diff --git a/examples/src/bin/ostimer_async.rs b/examples/src/bin/ostimer_async.rs
deleted file mode 100644
index f043184e7..000000000
--- a/examples/src/bin/ostimer_async.rs
+++ /dev/null
@@ -1,64 +0,0 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::bind_interrupts;
6use embassy_mcxa_examples::init_uart2_pins;
7use embassy_time::{Duration, Timer};
8use hal::lpuart::{Config, Lpuart};
9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
10
11// Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed.
12bind_interrupts!(struct Irqs {
13 OS_EVENT => hal::ostimer::time_driver::OsEventHandler;
14});
15
16#[used]
17#[no_mangle]
18static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT;
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let p = hal::init(hal::config::Config::default());
23
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 P2_2 as TX and P2_3 as RX
33 unsafe {
34 init_uart2_pins(hal::pac());
35 }
36 let mut uart = Lpuart::new_blocking(
37 p.LPUART2, // Peripheral
38 p.P2_2, // TX pin
39 p.P2_3, // RX pin
40 config,
41 )
42 .unwrap();
43 uart.blocking_write(b"boot\n").unwrap();
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(hal::config::Config::default().time_interrupt_priority, 1_000_000);
53
54 // Removed force-pend; rely on real hardware match to trigger OS_EVENT.
55
56 // Log using defmt if enabled
57 defmt::info!("OSTIMER async example starting...");
58
59 loop {
60 defmt::info!("tick");
61 uart.write_str_blocking("tick\n");
62 Timer::after(Duration::from_millis(1000)).await;
63 }
64}
diff --git a/examples/src/bin/ostimer_counter.rs b/examples/src/bin/ostimer_counter.rs
deleted file mode 100644
index f36915ff2..000000000
--- a/examples/src/bin/ostimer_counter.rs
+++ /dev/null
@@ -1,139 +0,0 @@
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_mcxa::clocks::periph_helpers::OstimerClockSel;
11use embassy_mcxa::clocks::PoweredClock;
12use embassy_mcxa::lpuart::{Blocking, Config, Lpuart};
13use embassy_time::{Duration, Timer};
14use hal::bind_interrupts;
15use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 OS_EVENT => hal::ostimer::time_driver::OsEventHandler;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let p = hal::init(Default::default());
24
25 // Create UART configuration
26 let config = Config {
27 baudrate_bps: 115_200,
28 enable_tx: true,
29 enable_rx: true,
30 ..Default::default()
31 };
32
33 // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX
34 unsafe {
35 embassy_mcxa_examples::init_uart2_pins(hal::pac());
36 }
37 let mut uart = Lpuart::new_blocking(
38 p.LPUART2, // Peripheral
39 p.P2_2, // TX pin
40 p.P2_3, // RX pin
41 config,
42 )
43 .unwrap();
44
45 uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n");
46
47 // Initialize the OSTIMER time driver
48 hal::ostimer::time_driver::init(
49 hal::interrupt::Priority::from(3),
50 1_000_000, // 1MHz clock
51 );
52
53 // Create OSTIMER instance
54 let ostimer = hal::ostimer::Ostimer::<hal::ostimer::Ostimer0>::new(
55 p.OSTIMER0,
56 hal::ostimer::Config {
57 init_match_max: true,
58 power: PoweredClock::NormalEnabledDeepSleepDisabled,
59 source: OstimerClockSel::Clk1M,
60 },
61 );
62
63 // Read initial counter value
64 let initial_counter = ostimer.now();
65 uart.write_str_blocking("Initial counter value: ");
66 write_u64(&mut uart, initial_counter);
67 uart.write_str_blocking("\n");
68
69 // Wait a bit to let counter increment
70 Timer::after(Duration::from_millis(100)).await;
71
72 // Read counter again
73 let counter_after_wait = ostimer.now();
74 uart.write_str_blocking("Counter after 100ms wait: ");
75 write_u64(&mut uart, counter_after_wait);
76 uart.write_str_blocking("\n");
77 uart.write_str_blocking("Difference: ");
78 write_u64(&mut uart, counter_after_wait - initial_counter);
79 uart.write_str_blocking(" ticks\n");
80
81 // Reset the timer
82 uart.write_str_blocking("Resetting timer...\n");
83 ostimer.reset(hal::pac());
84
85 // Read counter after reset
86 let counter_after_reset = ostimer.now();
87 uart.write_str_blocking("Counter after reset: ");
88 write_u64(&mut uart, counter_after_reset);
89 uart.write_str_blocking("\n");
90
91 // Wait again to verify timer is working
92 Timer::after(Duration::from_millis(50)).await;
93
94 let final_counter = ostimer.now();
95 uart.write_str_blocking("Counter after another 50ms: ");
96 write_u64(&mut uart, final_counter);
97 uart.write_str_blocking("\n");
98 uart.write_str_blocking("Difference after reset: ");
99 write_u64(&mut uart, final_counter - counter_after_reset);
100 uart.write_str_blocking(" ticks\n");
101
102 uart.write_str_blocking("Example complete\n");
103}
104
105// Helper function to write a u64 value as decimal string
106fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) {
107 if value == 0 {
108 uart.write_str_blocking("0");
109 return;
110 }
111
112 let mut buffer = [0u8; 20]; // Enough for max u64
113 let mut i = 0;
114 let mut v = value;
115
116 while v > 0 {
117 buffer[i] = b'0' + (v % 10) as u8;
118 v /= 10;
119 i += 1;
120 }
121
122 // Write digits in reverse order
123 while i > 0 {
124 i -= 1;
125 match buffer[i] {
126 b'0' => uart.write_str_blocking("0"),
127 b'1' => uart.write_str_blocking("1"),
128 b'2' => uart.write_str_blocking("2"),
129 b'3' => uart.write_str_blocking("3"),
130 b'4' => uart.write_str_blocking("4"),
131 b'5' => uart.write_str_blocking("5"),
132 b'6' => uart.write_str_blocking("6"),
133 b'7' => uart.write_str_blocking("7"),
134 b'8' => uart.write_str_blocking("8"),
135 b'9' => uart.write_str_blocking("9"),
136 _ => uart.write_str_blocking("?"),
137 }
138 }
139}
diff --git a/examples/src/bin/ostimer_race_test.rs b/examples/src/bin/ostimer_race_test.rs
deleted file mode 100644
index 0106b92a7..000000000
--- a/examples/src/bin/ostimer_race_test.rs
+++ /dev/null
@@ -1,405 +0,0 @@
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 core::sync::atomic::{AtomicU32, Ordering};
13
14use embassy_executor::Spawner;
15use embassy_mcxa::clocks::periph_helpers::OstimerClockSel;
16use embassy_mcxa::clocks::PoweredClock;
17use embassy_mcxa::lpuart::{Blocking, Config, Lpuart};
18use embassy_time::{Duration, Timer};
19use hal::bind_interrupts;
20use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
21
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 counters for race condition detection
31static ALARM_CALLBACK_COUNT: AtomicU32 = AtomicU32::new(0);
32static INTERRUPT_COUNT: AtomicU32 = AtomicU32::new(0);
33static RACE_DETECTED: AtomicU32 = AtomicU32::new(0);
34
35// Alarm callback function
36fn alarm_callback() {
37 let _count = ALARM_CALLBACK_COUNT.fetch_add(1, Ordering::SeqCst);
38 INTERRUPT_COUNT.fetch_add(1, Ordering::SeqCst);
39
40 // Simulate some work in the callback to increase chance of races
41 for _ in 0..10 {
42 cortex_m::asm::nop();
43 }
44}
45
46fn report_default_handler(uart: &mut Lpuart<'_, Blocking>) {
47 let snapshot = hal::interrupt::default_handler_snapshot();
48 if snapshot.count == 0 {
49 return;
50 }
51
52 uart.write_str_blocking("WARNING: DefaultHandler executed ");
53 write_u32(uart, snapshot.count);
54 uart.write_str_blocking(" time(s). Vector=");
55 write_u32(uart, snapshot.vector as u32);
56 uart.write_str_blocking(" CFSR=0x");
57 write_hex32(uart, snapshot.cfsr);
58 uart.write_str_blocking(" HFSR=0x");
59 write_hex32(uart, snapshot.hfsr);
60 uart.write_str_blocking(" PC=0x");
61 write_hex32(uart, snapshot.stacked_pc);
62 uart.write_str_blocking(" LR=0x");
63 write_hex32(uart, snapshot.stacked_lr);
64 uart.write_str_blocking(" SP=0x");
65 write_hex32(uart, snapshot.stacked_sp);
66 uart.write_str_blocking("\n");
67
68 hal::interrupt::clear_default_handler_snapshot();
69}
70
71#[embassy_executor::main]
72async fn main(_spawner: Spawner) {
73 let p = hal::init(Default::default());
74
75 // Create UART configuration
76 let config = Config {
77 baudrate_bps: 115_200,
78 enable_tx: true,
79 enable_rx: true,
80 ..Default::default()
81 };
82
83 // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX
84 unsafe {
85 embassy_mcxa_examples::init_uart2_pins(hal::pac());
86 }
87 let mut uart = Lpuart::new_blocking(
88 p.LPUART2, // Peripheral
89 p.P2_2, // TX pin
90 p.P2_3, // RX pin
91 config,
92 )
93 .unwrap();
94
95 uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n");
96
97 // The bind_interrupts! macro handles handler binding automatically
98
99 // Initialize the OSTIMER time driver FIRST
100 hal::ostimer::time_driver::init(
101 hal::interrupt::Priority::from(3),
102 1_000_000, // 1MHz clock
103 );
104
105 uart.write_str_blocking("Time driver initialized\n");
106
107 // Create OSTIMER instance
108 let ostimer = hal::ostimer::Ostimer::<hal::ostimer::Ostimer0>::new(
109 p.OSTIMER0,
110 hal::ostimer::Config {
111 init_match_max: true,
112 power: PoweredClock::NormalEnabledDeepSleepDisabled,
113 source: OstimerClockSel::Clk1M,
114 },
115 );
116
117 uart.write_str_blocking("OSTIMER instance created\n");
118
119 // Test 1: Sequential alarm scheduling (OSTIMER only supports one alarm at a time)
120 uart.write_str_blocking("Test 1: Sequential alarm scheduling...\n");
121 test_rapid_alarms(&ostimer, &mut uart).await;
122 report_default_handler(&mut uart);
123
124 // Test 2: Counter reading during interrupts
125 uart.write_str_blocking("Test 2: Counter reading during interrupts...\n");
126 test_counter_reading_during_interrupts(&ostimer, &mut uart).await;
127 report_default_handler(&mut uart);
128
129 // Test 3: Concurrent timer operations
130 uart.write_str_blocking("Test 3: Concurrent timer operations...\n");
131 test_concurrent_operations(&ostimer, &mut uart).await;
132 report_default_handler(&mut uart);
133
134 // Test 4: Timer reset during operation
135 uart.write_str_blocking("Test 4: Timer reset during operation...\n");
136 test_reset_during_operation(&ostimer, &mut uart, hal::pac()).await;
137 report_default_handler(&mut uart);
138
139 // Report results
140 uart.write_str_blocking("Race condition test complete\n");
141 uart.write_str_blocking("Callback count: ");
142 write_u32(&mut uart, ALARM_CALLBACK_COUNT.load(Ordering::SeqCst));
143 uart.write_str_blocking("\nInterrupt count: ");
144 write_u32(&mut uart, INTERRUPT_COUNT.load(Ordering::SeqCst));
145 uart.write_str_blocking("\nRaces detected: ");
146 write_u32(&mut uart, RACE_DETECTED.load(Ordering::SeqCst));
147 uart.write_str_blocking("\n");
148}
149
150// Test rapid alarm scheduling to stress interrupt handling
151async fn test_rapid_alarms(
152 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
153 uart: &mut Lpuart<'_, Blocking>,
154) {
155 let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst);
156
157 // Schedule 10 alarms sequentially (OSTIMER only supports one alarm at a time)
158 for _i in 0..10 {
159 let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback);
160 let delay_us = 1000; // 1ms delay for each alarm
161 if ostimer.schedule_alarm_delay(&alarm, delay_us) {
162 // Wait for this alarm to complete before scheduling the next
163 Timer::after(Duration::from_micros(delay_us + 100)).await;
164 report_default_handler(uart);
165 } else {
166 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
167 uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm (match not ready)\n");
168 }
169 }
170
171 // All alarms should have completed by now
172 let final_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst);
173 let expected_count = initial_count + 10;
174
175 if final_count != expected_count {
176 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
177 uart.write_str_blocking("ERROR: Expected ");
178 write_u32(uart, expected_count);
179 uart.write_str_blocking(" callbacks, got ");
180 write_u32(uart, final_count);
181 uart.write_str_blocking("\n");
182 } else {
183 uart.write_str_blocking("PASS: All rapid alarms executed\n");
184 }
185}
186
187// Test reading counter while interrupts are firing
188async fn test_counter_reading_during_interrupts(
189 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
190 uart: &mut Lpuart<'_, Blocking>,
191) {
192 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
193
194 // Schedule an alarm that will fire soon
195 let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback);
196 if !ostimer.schedule_alarm_delay(&alarm, 500) {
197 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
198 uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before counter stress\n");
199 }
200
201 // While alarm is pending, read the counter many times rapidly
202 // This tests if counter reading is atomic and doesn't get corrupted by interrupts
203 let mut last_counter = ostimer.now();
204 let mut consistent_reads = 0;
205 let mut total_reads = 0;
206
207 for _ in 0..1000 {
208 let current_counter = ostimer.now();
209 total_reads += 1;
210
211 // Check if counter is monotonically increasing (basic sanity check)
212 if current_counter >= last_counter {
213 consistent_reads += 1;
214 }
215 last_counter = current_counter;
216
217 // Small delay between reads
218 for _ in 0..10 {
219 cortex_m::asm::nop();
220 }
221
222 report_default_handler(uart);
223 }
224
225 // Wait for alarm to complete
226 Timer::after(Duration::from_millis(1)).await;
227
228 let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
229
230 if consistent_reads == total_reads {
231 uart.write_str_blocking("PASS: Counter reading consistent during interrupts\n");
232 } else {
233 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
234 uart.write_str_blocking("ERROR: Counter reading inconsistent: ");
235 write_u32(uart, consistent_reads);
236 uart.write_str_blocking("/");
237 write_u32(uart, total_reads);
238 uart.write_str_blocking(" consistent\n");
239 }
240
241 if final_interrupt_count > initial_interrupt_count {
242 uart.write_str_blocking("PASS: Interrupt fired during counter reading test\n");
243 } else {
244 uart.write_str_blocking("WARNING: No interrupt fired during counter reading test\n");
245 }
246}
247
248// Test concurrent timer operations (embassy-time + alarms)
249async fn test_concurrent_operations(
250 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
251 uart: &mut Lpuart<'_, Blocking>,
252) {
253 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
254
255 // Start an embassy-time timer
256 let timer_future = Timer::after(Duration::from_millis(2));
257
258 // Schedule an alarm that should fire before the timer
259 let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback);
260 if !ostimer.schedule_alarm_delay(&alarm, 1000) {
261 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
262 uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before concurrent operations\n");
263 }
264
265 // Wait for both to complete
266 timer_future.await;
267
268 let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
269
270 if final_interrupt_count > initial_interrupt_count {
271 uart.write_str_blocking("PASS: Concurrent operations completed\n");
272 } else {
273 uart.write_str_blocking("WARNING: No interrupts during concurrent operations\n");
274 }
275}
276
277// Test timer reset during active operations
278async fn test_reset_during_operation(
279 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
280 uart: &mut Lpuart<'_, Blocking>,
281 peripherals: &hal::pac::Peripherals,
282) {
283 let initial_counter = ostimer.now();
284
285 // Schedule an alarm
286 let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback);
287 if !ostimer.schedule_alarm_delay(&alarm, 2000) {
288 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
289 uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before reset test\n");
290 }
291
292 // Wait a bit then reset the timer
293 Timer::after(Duration::from_millis(1)).await;
294 ostimer.reset(peripherals);
295
296 // Check counter after reset
297 let counter_after_reset = ostimer.now();
298
299 // Wait to see if the alarm still fires (it shouldn't after reset)
300 Timer::after(Duration::from_millis(2)).await;
301
302 let final_counter = ostimer.now();
303
304 if counter_after_reset < initial_counter {
305 uart.write_str_blocking("PASS: Timer reset successful\n");
306 } else {
307 RACE_DETECTED.fetch_add(1, Ordering::SeqCst);
308 uart.write_str_blocking("ERROR: Timer reset may have failed\n");
309 }
310
311 uart.write_str_blocking("Counter progression after reset: ");
312 write_u64(uart, initial_counter);
313 uart.write_str_blocking(" -> ");
314 write_u64(uart, counter_after_reset);
315 uart.write_str_blocking(" -> ");
316 write_u64(uart, final_counter);
317 uart.write_str_blocking("\n");
318}
319
320// Helper function to write a u32 value as decimal string
321fn write_u32(uart: &mut Lpuart<'_, Blocking>, value: u32) {
322 if value == 0 {
323 uart.write_str_blocking("0");
324 return;
325 }
326
327 let mut buffer = [0u8; 10]; // Enough for max u32
328 let mut i = 0;
329 let mut v = value;
330
331 while v > 0 {
332 buffer[i] = b'0' + (v % 10) as u8;
333 v /= 10;
334 i += 1;
335 }
336
337 // Write digits in reverse order
338 while i > 0 {
339 i -= 1;
340 match buffer[i] {
341 b'0' => uart.write_str_blocking("0"),
342 b'1' => uart.write_str_blocking("1"),
343 b'2' => uart.write_str_blocking("2"),
344 b'3' => uart.write_str_blocking("3"),
345 b'4' => uart.write_str_blocking("4"),
346 b'5' => uart.write_str_blocking("5"),
347 b'6' => uart.write_str_blocking("6"),
348 b'7' => uart.write_str_blocking("7"),
349 b'8' => uart.write_str_blocking("8"),
350 b'9' => uart.write_str_blocking("9"),
351 _ => uart.write_str_blocking("?"),
352 }
353 }
354}
355
356fn write_hex32(uart: &mut Lpuart<'_, Blocking>, value: u32) {
357 let mut buf = [b'0'; 8];
358 let mut tmp = value;
359 for i in (0..8).rev() {
360 let digit = (tmp & 0xF) as u8;
361 buf[i] = match digit {
362 0..=9 => b'0' + digit,
363 10..=15 => b'A' + (digit - 10),
364 _ => b'?',
365 };
366 tmp >>= 4;
367 }
368 uart.blocking_write(&buf).unwrap();
369}
370
371// Helper function to write a u64 value as decimal string
372fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) {
373 if value == 0 {
374 uart.blocking_write(b"0").unwrap();
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.blocking_write(b"0").unwrap(),
393 b'1' => uart.blocking_write(b"1").unwrap(),
394 b'2' => uart.blocking_write(b"2").unwrap(),
395 b'3' => uart.blocking_write(b"3").unwrap(),
396 b'4' => uart.blocking_write(b"4").unwrap(),
397 b'5' => uart.blocking_write(b"5").unwrap(),
398 b'6' => uart.blocking_write(b"6").unwrap(),
399 b'7' => uart.blocking_write(b"7").unwrap(),
400 b'8' => uart.blocking_write(b"8").unwrap(),
401 b'9' => uart.blocking_write(b"9").unwrap(),
402 _ => uart.blocking_write(b"?").unwrap(),
403 }
404 }
405}
diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs
index 558fb0278..a12e125c6 100644
--- a/src/clocks/mod.rs
+++ b/src/clocks/mod.rs
@@ -867,7 +867,9 @@ macro_rules! impl_cc_gate {
867/// This module contains implementations of MRCC APIs, specifically of the [`Gate`] trait, 867/// This module contains implementations of MRCC APIs, specifically of the [`Gate`] trait,
868/// for various low level peripherals. 868/// for various low level peripherals.
869pub(crate) mod gate { 869pub(crate) mod gate {
870 use super::periph_helpers::{AdcConfig, LpuartConfig, NoConfig, OsTimerConfig}; 870 #[cfg(not(feature = "time"))]
871 use super::periph_helpers::OsTimerConfig;
872 use super::periph_helpers::{AdcConfig, LpuartConfig, NoConfig};
871 use super::*; 873 use super::*;
872 874
873 // These peripherals have no additional upstream clocks or configuration required 875 // These peripherals have no additional upstream clocks or configuration required
@@ -888,7 +890,9 @@ pub(crate) mod gate {
888 890
889 // These peripherals DO have meaningful configuration, and could fail if the system 891 // These peripherals DO have meaningful configuration, and could fail if the system
890 // clocks do not match their needs. 892 // clocks do not match their needs.
893 #[cfg(not(feature = "time"))]
891 impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig); 894 impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig);
895
892 impl_cc_gate!(LPUART2, mrcc_glb_cc0, mrcc_glb_rst0, lpuart2, LpuartConfig); 896 impl_cc_gate!(LPUART2, mrcc_glb_cc0, mrcc_glb_rst0, lpuart2, LpuartConfig);
893 impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); 897 impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig);
894} 898}
diff --git a/src/config.rs b/src/config.rs
index 0939c11f1..9c0d47ecb 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -5,6 +5,7 @@ use crate::interrupt::Priority;
5 5
6#[non_exhaustive] 6#[non_exhaustive]
7pub struct Config { 7pub struct Config {
8 #[cfg(feature = "time")]
8 pub time_interrupt_priority: Priority, 9 pub time_interrupt_priority: Priority,
9 pub rtc_interrupt_priority: Priority, 10 pub rtc_interrupt_priority: Priority,
10 pub adc_interrupt_priority: Priority, 11 pub adc_interrupt_priority: Priority,
@@ -14,6 +15,7 @@ pub struct Config {
14impl Default for Config { 15impl Default for Config {
15 fn default() -> Self { 16 fn default() -> Self {
16 Self { 17 Self {
18 #[cfg(feature = "time")]
17 time_interrupt_priority: Priority::from(0), 19 time_interrupt_priority: Priority::from(0),
18 rtc_interrupt_priority: Priority::from(0), 20 rtc_interrupt_priority: Priority::from(0),
19 adc_interrupt_priority: Priority::from(0), 21 adc_interrupt_priority: Priority::from(0),
diff --git a/src/lib.rs b/src/lib.rs
index c885ecc50..e93ff61a6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,6 +14,9 @@ pub mod lpuart;
14pub mod ostimer; 14pub mod ostimer;
15pub mod rtc; 15pub mod rtc;
16 16
17#[cfg(feature = "rt")]
18pub use crate::pac::NVIC_PRIO_BITS;
19
17#[rustfmt::skip] 20#[rustfmt::skip]
18embassy_hal_internal::peripherals!( 21embassy_hal_internal::peripherals!(
19 ADC0, 22 ADC0,
@@ -83,6 +86,8 @@ embassy_hal_internal::peripherals!(
83 MBC0, 86 MBC0,
84 MRCC0, 87 MRCC0,
85 OPAMP0, 88 OPAMP0,
89
90 #[cfg(not(feature = "time"))]
86 OSTIMER0, 91 OSTIMER0,
87 92
88 P0_0, 93 P0_0,
@@ -335,7 +340,6 @@ pub use interrupt::InterruptExt;
335pub use mcxa_pac as pac; 340pub use mcxa_pac as pac;
336#[cfg(not(feature = "unstable-pac"))] 341#[cfg(not(feature = "unstable-pac"))]
337pub(crate) use mcxa_pac as pac; 342pub(crate) use mcxa_pac as pac;
338pub use ostimer::Ostimer0 as Ostimer0Token;
339pub use rtc::Rtc0 as Rtc0Token; 343pub use rtc::Rtc0 as Rtc0Token;
340 344
341/// Initialize HAL with configuration (mirrors embassy-imxrt style). Minimal: just take peripherals. 345/// Initialize HAL with configuration (mirrors embassy-imxrt style). Minimal: just take peripherals.
@@ -343,6 +347,7 @@ pub use rtc::Rtc0 as Rtc0Token;
343pub fn init(cfg: crate::config::Config) -> Peripherals { 347pub fn init(cfg: crate::config::Config) -> Peripherals {
344 let peripherals = Peripherals::take(); 348 let peripherals = Peripherals::take();
345 // Apply user-configured priority early; enabling is left to examples/apps 349 // Apply user-configured priority early; enabling is left to examples/apps
350 #[cfg(feature = "time")]
346 crate::interrupt::OS_EVENT.set_priority(cfg.time_interrupt_priority); 351 crate::interrupt::OS_EVENT.set_priority(cfg.time_interrupt_priority);
347 // Apply user-configured priority early; enabling is left to examples/apps 352 // Apply user-configured priority early; enabling is left to examples/apps
348 crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); 353 crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority);
@@ -352,6 +357,10 @@ pub fn init(cfg: crate::config::Config) -> Peripherals {
352 // Configure clocks 357 // Configure clocks
353 crate::clocks::init(cfg.clock_cfg).unwrap(); 358 crate::clocks::init(cfg.clock_cfg).unwrap();
354 359
360 // Initialize embassy-time global driver backed by OSTIMER0
361 #[cfg(feature = "time")]
362 crate::ostimer::time_driver::init(crate::config::Config::default().time_interrupt_priority, 1_000_000);
363
355 // Enable GPIO clocks 364 // Enable GPIO clocks
356 unsafe { 365 unsafe {
357 _ = crate::clocks::enable_and_reset::<crate::peripherals::PORT0>(&crate::clocks::periph_helpers::NoConfig); 366 _ = crate::clocks::enable_and_reset::<crate::peripherals::PORT0>(&crate::clocks::periph_helpers::NoConfig);
diff --git a/src/ostimer.rs b/src/ostimer.rs
index cd5451b53..c51812e3d 100644
--- a/src/ostimer.rs
+++ b/src/ostimer.rs
@@ -35,7 +35,6 @@ use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel};
35use crate::clocks::{assert_reset, enable_and_reset, is_reset_released, release_reset, Gate, PoweredClock}; 35use crate::clocks::{assert_reset, enable_and_reset, is_reset_released, release_reset, Gate, PoweredClock};
36use crate::interrupt::InterruptExt; 36use crate::interrupt::InterruptExt;
37use crate::pac; 37use crate::pac;
38use crate::peripherals::OSTIMER0;
39 38
40// PAC defines the shared RegisterBlock under `ostimer0`. 39// PAC defines the shared RegisterBlock under `ostimer0`.
41type Regs = pac::ostimer0::RegisterBlock; 40type Regs = pac::ostimer0::RegisterBlock;
@@ -283,15 +282,15 @@ impl<'d, I: Instance> Ostimer<'d, I> {
283 .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); 282 .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit());
284 283
285 unsafe { 284 unsafe {
286 assert_reset::<OSTIMER0>(); 285 assert_reset::<I>();
287 286
288 for _ in 0..RESET_STABILIZE_SPINS { 287 for _ in 0..RESET_STABILIZE_SPINS {
289 cortex_m::asm::nop(); 288 cortex_m::asm::nop();
290 } 289 }
291 290
292 release_reset::<OSTIMER0>(); 291 release_reset::<I>();
293 292
294 while !is_reset_released::<OSTIMER0>() { 293 while !is_reset_released::<I>() {
295 cortex_m::asm::nop(); 294 cortex_m::asm::nop();
296 } 295 }
297 } 296 }
@@ -490,9 +489,7 @@ pub trait Instance: Gate<MrccPeriphConfig = OsTimerConfig> + PeripheralType {
490 fn ptr() -> *const Regs; 489 fn ptr() -> *const Regs;
491} 490}
492 491
493// Token for OSTIMER0 provided by embassy-hal-internal peripherals macro. 492#[cfg(not(feature = "time"))]
494pub type Ostimer0 = crate::peripherals::OSTIMER0;
495
496impl Instance for crate::peripherals::OSTIMER0 { 493impl Instance for crate::peripherals::OSTIMER0 {
497 #[inline(always)] 494 #[inline(always)]
498 fn ptr() -> *const Regs { 495 fn ptr() -> *const Regs {
@@ -500,14 +497,6 @@ impl Instance for crate::peripherals::OSTIMER0 {
500 } 497 }
501} 498}
502 499
503// Also implement Instance for the Peri wrapper type
504// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::OSTIMER0> {
505// #[inline(always)]
506// fn ptr() -> *const Regs {
507// pac::Ostimer0::ptr()
508// }
509// }
510
511#[inline(always)] 500#[inline(always)]
512fn bin_to_gray(x: u64) -> u64 { 501fn bin_to_gray(x: u64) -> u64 {
513 x ^ (x >> 1) 502 x ^ (x >> 1)
@@ -523,6 +512,7 @@ fn gray_to_bin(gray: u64) -> u64 {
523 bin 512 bin
524} 513}
525 514
515#[cfg(feature = "time")]
526pub mod time_driver { 516pub mod time_driver {
527 use core::sync::atomic::Ordering; 517 use core::sync::atomic::Ordering;
528 use core::task::Waker; 518 use core::task::Waker;
@@ -537,7 +527,55 @@ pub mod time_driver {
537 use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel}; 527 use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel};
538 use crate::clocks::{enable_and_reset, PoweredClock}; 528 use crate::clocks::{enable_and_reset, PoweredClock};
539 use crate::pac; 529 use crate::pac;
540 use crate::peripherals::OSTIMER0; 530
531 #[allow(non_camel_case_types)]
532 pub(crate) struct _OSTIMER0_TIME_DRIVER {
533 _x: (),
534 }
535
536 // #[cfg(feature = "time")]
537 // impl_cc_gate!(_OSTIMER0_TIME_DRIVER, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig);
538
539 impl crate::clocks::Gate for _OSTIMER0_TIME_DRIVER {
540 type MrccPeriphConfig = crate::clocks::periph_helpers::OsTimerConfig;
541
542 #[inline]
543 unsafe fn enable_clock() {
544 let mrcc = unsafe { pac::Mrcc0::steal() };
545 mrcc.mrcc_glb_cc1().modify(|_, w| w.ostimer0().enabled());
546 }
547
548 #[inline]
549 unsafe fn disable_clock() {
550 let mrcc = unsafe { pac::Mrcc0::steal() };
551 mrcc.mrcc_glb_cc1().modify(|_r, w| w.ostimer0().disabled());
552 }
553
554 #[inline]
555 fn is_clock_enabled() -> bool {
556 let mrcc = unsafe { pac::Mrcc0::steal() };
557 mrcc.mrcc_glb_cc1().read().ostimer0().is_enabled()
558 }
559
560 #[inline]
561 unsafe fn release_reset() {
562 let mrcc = unsafe { pac::Mrcc0::steal() };
563 mrcc.mrcc_glb_rst1().modify(|_, w| w.ostimer0().enabled());
564 }
565
566 #[inline]
567 unsafe fn assert_reset() {
568 let mrcc = unsafe { pac::Mrcc0::steal() };
569 mrcc.mrcc_glb_rst1().modify(|_, w| w.ostimer0().disabled());
570 }
571
572 #[inline]
573 fn is_reset_released() -> bool {
574 let mrcc = unsafe { pac::Mrcc0::steal() };
575 mrcc.mrcc_glb_rst1().read().ostimer0().is_enabled()
576 }
577 }
578
541 pub struct Driver; 579 pub struct Driver;
542 static TIMER_WAKER: AtomicWaker = AtomicWaker::new(); 580 static TIMER_WAKER: AtomicWaker = AtomicWaker::new();
543 581
@@ -625,7 +663,7 @@ pub mod time_driver {
625 /// The embassy_time_driver macro handles driver registration automatically. 663 /// The embassy_time_driver macro handles driver registration automatically.
626 pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) { 664 pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) {
627 let _clock_freq = unsafe { 665 let _clock_freq = unsafe {
628 enable_and_reset::<OSTIMER0>(&OsTimerConfig { 666 enable_and_reset::<_OSTIMER0_TIME_DRIVER>(&OsTimerConfig {
629 power: PoweredClock::AlwaysEnabled, 667 power: PoweredClock::AlwaysEnabled,
630 source: OstimerClockSel::Clk1M, 668 source: OstimerClockSel::Clk1M,
631 }) 669 })
@@ -694,12 +732,14 @@ pub mod time_driver {
694 } 732 }
695 }); 733 });
696 } 734 }
735}
697 736
698 /// Type-level handler to be used with bind_interrupts! for OS_EVENT. 737#[cfg(feature = "time")]
699 pub struct OsEventHandler; 738use crate::pac::interrupt;
700 impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::OS_EVENT> for OsEventHandler { 739
701 unsafe fn on_interrupt() { 740#[cfg(feature = "time")]
702 on_interrupt(); 741#[allow(non_snake_case)]
703 } 742#[interrupt]
704 } 743fn OS_EVENT() {
744 time_driver::on_interrupt()
705} 745}