aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-11-18 14:19:09 +0100
committerGitHub <[email protected]>2025-11-18 14:19:09 +0100
commit5b1149a52dbec9e3bdd10dc341dc0751ab4798a6 (patch)
tree3ff7098471cf660a54a707464a0e2feb2080b09e
parent62e297c130ac26afe4d7d5752bb79709bd370e39 (diff)
parentc8942aec2478ff077b55da0e86801f8a6a88a7de (diff)
Merge pull request #11 from jamesmunns/james/impl-clocks
Implement initial `clock` driver. This PR introduces an initial two-phase clock driver system: 1. The first stage is responsible for initializing the core/system clocks at the time of `embassy_mcxa::init()` 2. The second stage is done on creation of peripherals This work is limited to currently used clocks and peripherals, but has room for expansion for later peripherals. This model is based on the preliminary refactoring performed for the `embassy-imxrt` crate.
-rw-r--r--examples/src/bin/adc_interrupt.rs34
-rw-r--r--examples/src/bin/adc_polling.rs34
-rw-r--r--examples/src/bin/blink.rs5
-rw-r--r--examples/src/bin/hello.rs31
-rw-r--r--examples/src/bin/lpuart_buffered.rs21
-rw-r--r--examples/src/bin/lpuart_polling.rs16
-rw-r--r--examples/src/bin/ostimer_alarm.rs34
-rw-r--r--examples/src/bin/ostimer_async.rs30
-rw-r--r--examples/src/bin/ostimer_counter.rs32
-rw-r--r--examples/src/bin/ostimer_race_test.rs74
-rw-r--r--examples/src/bin/rtc_alarm.rs29
-rw-r--r--examples/src/bin/uart_interrupt.rs66
-rw-r--r--examples/src/common/mod.rs45
-rw-r--r--examples/src/lib.rs58
-rw-r--r--src/adc.rs73
-rw-r--r--src/board.rs14
-rw-r--r--src/clocks.rs134
-rw-r--r--src/clocks/config.rs199
-rw-r--r--src/clocks/mod.rs887
-rw-r--r--src/clocks/periph_helpers.rs393
-rw-r--r--src/config.rs3
-rw-r--r--src/lib.rs10
-rw-r--r--src/lpuart/buffered.rs11
-rw-r--r--src/lpuart/mod.rs156
-rw-r--r--src/ostimer.rs73
-rw-r--r--src/reset.rs112
-rw-r--r--src/rtc.rs30
-rw-r--r--src/uart.rs316
-rw-r--r--supply-chain/config.toml40
-rw-r--r--supply-chain/imports.lock414
30 files changed, 1903 insertions, 1471 deletions
diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs
index e174a5272..6812ba5d3 100644
--- a/examples/src/bin/adc_interrupt.rs
+++ b/examples/src/bin/adc_interrupt.rs
@@ -2,13 +2,16 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa_examples::{init_adc, init_uart2}; 5use embassy_mcxa_examples::init_adc_pins;
6use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; 6use hal::adc::{LpadcConfig, TriggerPriorityPolicy};
7use hal::clocks::periph_helpers::{AdcClockSel, Div4};
8use hal::clocks::PoweredClock;
9use hal::lpuart::{Config, Lpuart};
7use hal::pac::adc1::cfg::{Pwrsel, Refsel}; 10use hal::pac::adc1::cfg::{Pwrsel, Refsel};
8use hal::pac::adc1::cmdl1::{Adch, Mode}; 11use hal::pac::adc1::cmdl1::{Adch, Mode};
9use hal::pac::adc1::ctrl::CalAvgs; 12use hal::pac::adc1::ctrl::CalAvgs;
10use hal::pac::adc1::tctrl::Tcmd; 13use hal::pac::adc1::tctrl::Tcmd;
11use hal::{bind_interrupts, uart, InterruptExt}; 14use hal::{bind_interrupts, InterruptExt};
12use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 15use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
13 16
14bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
@@ -23,17 +26,29 @@ static KEEP_ADC: unsafe extern "C" fn() = ADC1;
23async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
24 let p = hal::init(hal::config::Config::default()); 27 let p = hal::init(hal::config::Config::default());
25 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
26 unsafe { 38 unsafe {
27 init_uart2(hal::pac()); 39 embassy_mcxa_examples::init_uart2_pins(hal::pac());
28 } 40 }
29 41 let mut uart = Lpuart::new_blocking(
30 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 42 p.LPUART2, // Peripheral
31 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 43 p.PIO2_2, // TX pin
32 44 p.PIO2_3, // RX pin
45 config,
46 )
47 .unwrap();
33 uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); 48 uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n");
34 49
35 unsafe { 50 unsafe {
36 init_adc(hal::pac()); 51 init_adc_pins(hal::pac());
37 } 52 }
38 53
39 let adc_config = LpadcConfig { 54 let adc_config = LpadcConfig {
@@ -47,6 +62,9 @@ async fn main(_spawner: Spawner) {
47 enable_conv_pause: false, 62 enable_conv_pause: false,
48 conv_pause_delay: 0, 63 conv_pause_delay: 0,
49 fifo_watermark: 0, 64 fifo_watermark: 0,
65 power: PoweredClock::NormalEnabledDeepSleepDisabled,
66 source: AdcClockSel::FroLfDiv,
67 div: Div4::no_div(),
50 }; 68 };
51 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); 69 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config);
52 70
diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs
index 741551d49..421306e9b 100644
--- a/examples/src/bin/adc_polling.rs
+++ b/examples/src/bin/adc_polling.rs
@@ -4,13 +4,15 @@
4use core::fmt::Write; 4use core::fmt::Write;
5 5
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_mcxa_examples::{init_adc, init_uart2}; 7use embassy_mcxa_examples::{init_adc_pins, init_uart2_pins};
8use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; 8use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy};
9use hal::clocks::periph_helpers::{AdcClockSel, Div4};
10use hal::clocks::PoweredClock;
11use hal::lpuart::{Config, Lpuart};
9use hal::pac::adc1::cfg::{Pwrsel, Refsel}; 12use hal::pac::adc1::cfg::{Pwrsel, Refsel};
10use hal::pac::adc1::cmdl1::{Adch, Mode}; 13use hal::pac::adc1::cmdl1::{Adch, Mode};
11use hal::pac::adc1::ctrl::CalAvgs; 14use hal::pac::adc1::ctrl::CalAvgs;
12use hal::pac::adc1::tctrl::Tcmd; 15use hal::pac::adc1::tctrl::Tcmd;
13use hal::uart;
14use heapless::String; 16use heapless::String;
15use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 17use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
16 18
@@ -21,16 +23,33 @@ async fn main(_spawner: Spawner) {
21 let p = hal::init(hal::config::Config::default()); 23 let p = hal::init(hal::config::Config::default());
22 24
23 unsafe { 25 unsafe {
24 init_uart2(hal::pac()); 26 init_uart2_pins(hal::pac());
25 } 27 }
26 28
27 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 29 // Create UART configuration
28 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 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
38 unsafe {
39 init_uart2_pins(hal::pac());
40 }
41 let mut uart = Lpuart::new_blocking(
42 p.LPUART2, // Peripheral
43 p.PIO2_2, // TX pin
44 p.PIO2_3, // RX pin
45 config,
46 )
47 .unwrap();
29 48
30 uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); 49 uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n");
31 50
32 unsafe { 51 unsafe {
33 init_adc(hal::pac()); 52 init_adc_pins(hal::pac());
34 } 53 }
35 54
36 let adc_config = LpadcConfig { 55 let adc_config = LpadcConfig {
@@ -44,6 +63,9 @@ async fn main(_spawner: Spawner) {
44 enable_conv_pause: false, 63 enable_conv_pause: false,
45 conv_pause_delay: 0, 64 conv_pause_delay: 0,
46 fifo_watermark: 0, 65 fifo_watermark: 0,
66 power: PoweredClock::NormalEnabledDeepSleepDisabled,
67 source: AdcClockSel::FroLfDiv,
68 div: Div4::no_div(),
47 }; 69 };
48 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); 70 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config);
49 71
diff --git a/examples/src/bin/blink.rs b/examples/src/bin/blink.rs
index c36fc9421..d8b158d50 100644
--- a/examples/src/bin/blink.rs
+++ b/examples/src/bin/blink.rs
@@ -4,7 +4,7 @@
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa as hal; 5use embassy_mcxa as hal;
6use embassy_mcxa::bind_interrupts; 6use embassy_mcxa::bind_interrupts;
7use embassy_mcxa_examples::{init_led, init_ostimer0}; 7use embassy_mcxa_examples::init_led_gpio_clocks;
8use embassy_time::{Duration, Timer}; 8use embassy_time::{Duration, Timer};
9use hal::gpio::pins::PIO3_18; 9use hal::gpio::pins::PIO3_18;
10use hal::gpio::{Level, Output}; 10use hal::gpio::{Level, Output};
@@ -23,8 +23,7 @@ async fn main(_spawner: Spawner) {
23 let _p = hal::init(hal::config::Config::default()); 23 let _p = hal::init(hal::config::Config::default());
24 24
25 unsafe { 25 unsafe {
26 init_led(hal::pac()); 26 init_led_gpio_clocks(hal::pac());
27 init_ostimer0(hal::pac());
28 } 27 }
29 28
30 defmt::info!("Blink example"); 29 defmt::info!("Blink example");
diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs
index 5c4336d50..207c157c3 100644
--- a/examples/src/bin/hello.rs
+++ b/examples/src/bin/hello.rs
@@ -2,12 +2,11 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa_examples::init_uart2; 5use hal::lpuart::{Blocking, Config, Lpuart};
6use hal::uart;
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 6use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8 7
9/// Simple helper to write a byte as hex to UART 8/// Simple helper to write a byte as hex to UART
10fn write_hex_byte(uart: &hal::uart::Uart<hal::uart::Lpuart2>, byte: u8) { 9fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) {
11 const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; 10 const HEX_DIGITS: &[u8] = b"0123456789ABCDEF";
12 uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); 11 uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]);
13 uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); 12 uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]);
@@ -19,15 +18,25 @@ async fn main(_spawner: Spawner) {
19 18
20 defmt::info!("boot"); 19 defmt::info!("boot");
21 20
22 // Board-level init for UART2 clocks and pins. 21 // Create UART configuration
22 let config = Config {
23 baudrate_bps: 115_200,
24 enable_tx: true,
25 enable_rx: true,
26 ..Default::default()
27 };
28
29 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
23 unsafe { 30 unsafe {
24 init_uart2(hal::pac()); 31 embassy_mcxa_examples::init_uart2_pins(hal::pac());
25 } 32 }
26 33 let mut uart = Lpuart::new_blocking(
27 // Get UART source frequency from clock configuration 34 p.LPUART2, // Peripheral
28 // Using hardcoded frequency for now - dynamic detection may have issues 35 p.PIO2_2, // TX pin
29 let src = 12_000_000; // FRO_LF_DIV at 12MHz with DIV=0 36 p.PIO2_3, // RX pin
30 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 37 config,
38 )
39 .unwrap();
31 40
32 // Print welcome message before any async delays to guarantee early console output 41 // Print welcome message before any async delays to guarantee early console output
33 uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); 42 uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n");
@@ -66,7 +75,7 @@ async fn main(_spawner: Spawner) {
66 let num_str = &command[4..]; 75 let num_str = &command[4..];
67 if let Ok(num) = parse_u8(num_str) { 76 if let Ok(num) = parse_u8(num_str) {
68 uart.write_str_blocking("Hex: 0x"); 77 uart.write_str_blocking("Hex: 0x");
69 write_hex_byte(&uart, num); 78 write_hex_byte(&mut uart, num);
70 uart.write_str_blocking("\r\n"); 79 uart.write_str_blocking("\r\n");
71 } else { 80 } else {
72 uart.write_str_blocking("Invalid number for hex command\r\n"); 81 uart.write_str_blocking("Invalid number for hex command\r\n");
diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs
index 480d8e1f7..642d4af65 100644
--- a/examples/src/bin/lpuart_buffered.rs
+++ b/examples/src/bin/lpuart_buffered.rs
@@ -5,24 +5,24 @@ use embassy_executor::Spawner;
5use embassy_mcxa as hal; 5use embassy_mcxa as hal;
6use embassy_mcxa::interrupt::typelevel::Handler; 6use embassy_mcxa::interrupt::typelevel::Handler;
7use embassy_mcxa::lpuart::buffered::BufferedLpuart; 7use embassy_mcxa::lpuart::buffered::BufferedLpuart;
8use embassy_mcxa::lpuart::Config;
8use embassy_mcxa::{bind_interrupts, lpuart}; 9use embassy_mcxa::{bind_interrupts, lpuart};
9use embassy_mcxa_examples::{init_ostimer0, init_uart2}; 10use embassy_mcxa_examples::init_uart2_pins;
10use embedded_io_async::{Read, Write}; 11use embedded_io_async::{Read, Write};
11 12
12// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver 13// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver
13bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
14 LPUART2 => lpuart::buffered::BufferedInterruptHandler::<lpuart::lib::peripherals::LPUART2>; 15 LPUART2 => lpuart::buffered::BufferedInterruptHandler::<hal::peripherals::LPUART2>;
15}); 16});
16 17
17// Wrapper function for the interrupt handler 18// Wrapper function for the interrupt handler
18unsafe extern "C" fn lpuart2_handler() { 19unsafe extern "C" fn lpuart2_handler() {
19 lpuart::buffered::BufferedInterruptHandler::<lpuart::lib::peripherals::LPUART2>::on_interrupt(); 20 lpuart::buffered::BufferedInterruptHandler::<hal::peripherals::LPUART2>::on_interrupt();
20} 21}
21 22
22#[embassy_executor::main] 23#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
24 let _p = hal::init(hal::config::Config::default()); 25 let p = hal::init(hal::config::Config::default());
25 let p2 = lpuart::lib::init();
26 26
27 unsafe { 27 unsafe {
28 hal::interrupt::install_irq_handler(hal::pac::Interrupt::LPUART2, lpuart2_handler); 28 hal::interrupt::install_irq_handler(hal::pac::Interrupt::LPUART2, lpuart2_handler);
@@ -32,12 +32,11 @@ async fn main(_spawner: Spawner) {
32 hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); 32 hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3);
33 33
34 unsafe { 34 unsafe {
35 init_uart2(hal::pac()); 35 init_uart2_pins(hal::pac());
36 init_ostimer0(hal::pac());
37 } 36 }
38 37
39 // UART configuration (enable both TX and RX) 38 // UART configuration (enable both TX and RX)
40 let config = lpuart::Config { 39 let config = Config {
41 baudrate_bps: 115_200, 40 baudrate_bps: 115_200,
42 enable_tx: true, 41 enable_tx: true,
43 enable_rx: true, 42 enable_rx: true,
@@ -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/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs
index 215714569..bea82c33e 100644
--- a/examples/src/bin/lpuart_polling.rs
+++ b/examples/src/bin/lpuart_polling.rs
@@ -2,20 +2,20 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa_examples::init_uart2; 5use embassy_mcxa_examples::init_uart2_pins;
6use hal::lpuart::{lib, Config, Lpuart};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 6use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8 7
8use crate::hal::lpuart::{Config, Lpuart};
9
9#[embassy_executor::main] 10#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 11async fn main(_spawner: Spawner) {
11 let _p = hal::init(hal::config::Config::default()); 12 let p = hal::init(hal::config::Config::default());
12 let p2 = lib::init();
13 13
14 defmt::info!("boot"); 14 defmt::info!("boot");
15 15
16 // Board-level init for UART2 clocks and pins. 16 // Board-level init for UART2 clocks and pins.
17 unsafe { 17 unsafe {
18 init_uart2(hal::pac()); 18 init_uart2_pins(hal::pac());
19 } 19 }
20 20
21 // Create UART configuration 21 // Create UART configuration
@@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) {
28 28
29 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX 29 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
30 let lpuart = Lpuart::new_blocking( 30 let lpuart = Lpuart::new_blocking(
31 p2.LPUART2, // Peripheral 31 p.LPUART2, // Peripheral
32 p2.PIO2_2, // TX pin 32 p.PIO2_2, // TX pin
33 p2.PIO2_3, // RX pin 33 p.PIO2_3, // RX pin
34 config, 34 config,
35 ) 35 )
36 .unwrap(); 36 .unwrap();
diff --git a/examples/src/bin/ostimer_alarm.rs b/examples/src/bin/ostimer_alarm.rs
index 953f98c01..03fb93319 100644
--- a/examples/src/bin/ostimer_alarm.rs
+++ b/examples/src/bin/ostimer_alarm.rs
@@ -5,8 +5,10 @@ use core::sync::atomic::{AtomicBool, Ordering};
5 5
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_mcxa::bind_interrupts; 7use embassy_mcxa::bind_interrupts;
8use embassy_mcxa_examples::{init_ostimer0, init_uart2}; 8use embassy_mcxa::clocks::periph_helpers::OstimerClockSel;
9use hal::uart; 9use embassy_mcxa::clocks::PoweredClock;
10use embassy_mcxa::lpuart::{Config, Lpuart};
11use embassy_mcxa_examples::init_uart2_pins;
10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 12use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11 13
12// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. 14// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed.
@@ -30,13 +32,26 @@ fn alarm_callback() {
30async fn main(_spawner: Spawner) { 32async fn main(_spawner: Spawner) {
31 let p = hal::init(hal::config::Config::default()); 33 let p = hal::init(hal::config::Config::default());
32 34
33 // Enable/clock OSTIMER0 and UART2 before touching their registers 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 PIO2_2 as TX and PIO2_3 as RX
34 unsafe { 44 unsafe {
35 init_ostimer0(hal::pac()); 45 init_uart2_pins(hal::pac());
36 init_uart2(hal::pac());
37 } 46 }
38 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 47 let mut uart = Lpuart::new_blocking(
39 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 48 p.LPUART2, // Peripheral
49 p.PIO2_2, // TX pin
50 p.PIO2_3, // RX pin
51 config,
52 )
53 .unwrap();
54
40 uart.write_str_blocking("OSTIMER Alarm Example\n"); 55 uart.write_str_blocking("OSTIMER Alarm Example\n");
41 56
42 // Initialize embassy-time global driver backed by OSTIMER0 57 // Initialize embassy-time global driver backed by OSTIMER0
@@ -45,9 +60,10 @@ async fn main(_spawner: Spawner) {
45 // Create OSTIMER instance 60 // Create OSTIMER instance
46 let config = hal::ostimer::Config { 61 let config = hal::ostimer::Config {
47 init_match_max: true, 62 init_match_max: true,
48 clock_frequency_hz: 1_000_000, // 1MHz 63 power: PoweredClock::NormalEnabledDeepSleepDisabled,
64 source: OstimerClockSel::Clk1M,
49 }; 65 };
50 let ostimer = hal::ostimer::Ostimer::<hal::ostimer::Ostimer0>::new(p.OSTIMER0, config, hal::pac()); 66 let ostimer = hal::ostimer::Ostimer::<hal::ostimer::Ostimer0>::new(p.OSTIMER0, config);
51 67
52 // Create alarm with callback 68 // Create alarm with callback
53 let alarm = hal::ostimer::Alarm::new() 69 let alarm = hal::ostimer::Alarm::new()
diff --git a/examples/src/bin/ostimer_async.rs b/examples/src/bin/ostimer_async.rs
index 34862b61f..881f09374 100644
--- a/examples/src/bin/ostimer_async.rs
+++ b/examples/src/bin/ostimer_async.rs
@@ -3,9 +3,9 @@
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa::bind_interrupts; 5use embassy_mcxa::bind_interrupts;
6use embassy_mcxa_examples::{init_ostimer0, init_uart2}; 6use embassy_mcxa_examples::init_uart2_pins;
7use embassy_time::{Duration, Timer}; 7use embassy_time::{Duration, Timer};
8use hal::uart; 8use hal::lpuart::{Config, Lpuart};
9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
10 10
11// Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed. 11// Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed.
@@ -19,16 +19,28 @@ static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT;
19 19
20#[embassy_executor::main] 20#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
22 let _p = hal::init(hal::config::Config::default()); 22 let p = hal::init(hal::config::Config::default());
23 23
24 // Enable/clock OSTIMER0 and UART2 before touching their registers 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
25 unsafe { 33 unsafe {
26 init_ostimer0(hal::pac()); 34 init_uart2_pins(hal::pac());
27 init_uart2(hal::pac());
28 } 35 }
29 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 36 let mut uart = Lpuart::new_blocking(
30 let uart = uart::Uart::<uart::Lpuart2>::new(_p.LPUART2, uart::Config::new(src)); 37 p.LPUART2, // Peripheral
31 uart.write_str_blocking("boot\n"); 38 p.PIO2_2, // TX pin
39 p.PIO2_3, // RX pin
40 config,
41 )
42 .unwrap();
43 uart.blocking_write(b"boot\n").unwrap();
32 44
33 // Avoid mass NVIC writes here; DefaultHandler now safely returns. 45 // Avoid mass NVIC writes here; DefaultHandler now safely returns.
34 46
diff --git a/examples/src/bin/ostimer_counter.rs b/examples/src/bin/ostimer_counter.rs
index 20044760a..2fbc251b9 100644
--- a/examples/src/bin/ostimer_counter.rs
+++ b/examples/src/bin/ostimer_counter.rs
@@ -7,7 +7,9 @@
7#![no_main] 7#![no_main]
8 8
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_mcxa_examples::{init_ostimer0, init_uart2}; 10use embassy_mcxa::clocks::periph_helpers::OstimerClockSel;
11use embassy_mcxa::clocks::PoweredClock;
12use embassy_mcxa::lpuart::{Blocking, Config, Lpuart};
11use embassy_time::{Duration, Timer}; 13use embassy_time::{Duration, Timer};
12use hal::bind_interrupts; 14use hal::bind_interrupts;
13use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 15use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -20,13 +22,25 @@ bind_interrupts!(struct Irqs {
20async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
21 let p = hal::init(Default::default()); 23 let p = hal::init(Default::default());
22 24
23 // Enable/clock OSTIMER0 and UART2 before touching their registers 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 PIO2_2 as TX and PIO2_3 as RX
24 unsafe { 34 unsafe {
25 init_ostimer0(hal::pac()); 35 embassy_mcxa_examples::init_uart2_pins(hal::pac());
26 init_uart2(hal::pac());
27 } 36 }
28 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 37 let mut uart = Lpuart::new_blocking(
29 let mut uart = hal::uart::Uart::<hal::uart::Lpuart2>::new(p.LPUART2, hal::uart::Config::new(src)); 38 p.LPUART2, // Peripheral
39 p.PIO2_2, // TX pin
40 p.PIO2_3, // RX pin
41 config,
42 )
43 .unwrap();
30 44
31 uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); 45 uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n");
32 46
@@ -41,9 +55,9 @@ async fn main(_spawner: Spawner) {
41 p.OSTIMER0, 55 p.OSTIMER0,
42 hal::ostimer::Config { 56 hal::ostimer::Config {
43 init_match_max: true, 57 init_match_max: true,
44 clock_frequency_hz: 1_000_000, 58 power: PoweredClock::NormalEnabledDeepSleepDisabled,
59 source: OstimerClockSel::Clk1M,
45 }, 60 },
46 hal::pac(),
47 ); 61 );
48 62
49 // Read initial counter value 63 // Read initial counter value
@@ -89,7 +103,7 @@ async fn main(_spawner: Spawner) {
89} 103}
90 104
91// Helper function to write a u64 value as decimal string 105// Helper function to write a u64 value as decimal string
92fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) { 106fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) {
93 if value == 0 { 107 if value == 0 {
94 uart.write_str_blocking("0"); 108 uart.write_str_blocking("0");
95 return; 109 return;
diff --git a/examples/src/bin/ostimer_race_test.rs b/examples/src/bin/ostimer_race_test.rs
index 720a058d5..168a952cd 100644
--- a/examples/src/bin/ostimer_race_test.rs
+++ b/examples/src/bin/ostimer_race_test.rs
@@ -12,7 +12,9 @@
12use core::sync::atomic::{AtomicU32, Ordering}; 12use core::sync::atomic::{AtomicU32, Ordering};
13 13
14use embassy_executor::Spawner; 14use embassy_executor::Spawner;
15use embassy_mcxa_examples::{init_ostimer0, init_uart2}; 15use embassy_mcxa::clocks::periph_helpers::OstimerClockSel;
16use embassy_mcxa::clocks::PoweredClock;
17use embassy_mcxa::lpuart::{Blocking, Config, Lpuart};
16use embassy_time::{Duration, Timer}; 18use embassy_time::{Duration, Timer};
17use hal::bind_interrupts; 19use hal::bind_interrupts;
18use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 20use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -41,7 +43,7 @@ fn alarm_callback() {
41 } 43 }
42} 44}
43 45
44fn report_default_handler(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>) { 46fn report_default_handler(uart: &mut Lpuart<'_, Blocking>) {
45 let snapshot = hal::interrupt::default_handler_snapshot(); 47 let snapshot = hal::interrupt::default_handler_snapshot();
46 if snapshot.count == 0 { 48 if snapshot.count == 0 {
47 return; 49 return;
@@ -70,13 +72,25 @@ fn report_default_handler(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>) {
70async fn main(_spawner: Spawner) { 72async fn main(_spawner: Spawner) {
71 let p = hal::init(Default::default()); 73 let p = hal::init(Default::default());
72 74
73 // Enable/clock OSTIMER0 and UART2 before touching their registers 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 PIO2_2 as TX and PIO2_3 as RX
74 unsafe { 84 unsafe {
75 init_ostimer0(hal::pac()); 85 embassy_mcxa_examples::init_uart2_pins(hal::pac());
76 init_uart2(hal::pac());
77 } 86 }
78 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 87 let mut uart = Lpuart::new_blocking(
79 let mut uart = hal::uart::Uart::<hal::uart::Lpuart2>::new(p.LPUART2, hal::uart::Config::new(src)); 88 p.LPUART2, // Peripheral
89 p.PIO2_2, // TX pin
90 p.PIO2_3, // RX pin
91 config,
92 )
93 .unwrap();
80 94
81 uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); 95 uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n");
82 96
@@ -95,9 +109,9 @@ async fn main(_spawner: Spawner) {
95 p.OSTIMER0, 109 p.OSTIMER0,
96 hal::ostimer::Config { 110 hal::ostimer::Config {
97 init_match_max: true, 111 init_match_max: true,
98 clock_frequency_hz: 1_000_000, 112 power: PoweredClock::NormalEnabledDeepSleepDisabled,
113 source: OstimerClockSel::Clk1M,
99 }, 114 },
100 hal::pac(),
101 ); 115 );
102 116
103 uart.write_str_blocking("OSTIMER instance created\n"); 117 uart.write_str_blocking("OSTIMER instance created\n");
@@ -136,7 +150,7 @@ async fn main(_spawner: Spawner) {
136// Test rapid alarm scheduling to stress interrupt handling 150// Test rapid alarm scheduling to stress interrupt handling
137async fn test_rapid_alarms( 151async fn test_rapid_alarms(
138 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, 152 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
139 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, 153 uart: &mut Lpuart<'_, Blocking>,
140) { 154) {
141 let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); 155 let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst);
142 156
@@ -173,7 +187,7 @@ async fn test_rapid_alarms(
173// Test reading counter while interrupts are firing 187// Test reading counter while interrupts are firing
174async fn test_counter_reading_during_interrupts( 188async fn test_counter_reading_during_interrupts(
175 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, 189 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
176 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, 190 uart: &mut Lpuart<'_, Blocking>,
177) { 191) {
178 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); 192 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
179 193
@@ -234,7 +248,7 @@ async fn test_counter_reading_during_interrupts(
234// Test concurrent timer operations (embassy-time + alarms) 248// Test concurrent timer operations (embassy-time + alarms)
235async fn test_concurrent_operations( 249async fn test_concurrent_operations(
236 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, 250 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
237 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, 251 uart: &mut Lpuart<'_, Blocking>,
238) { 252) {
239 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); 253 let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst);
240 254
@@ -263,7 +277,7 @@ async fn test_concurrent_operations(
263// Test timer reset during active operations 277// Test timer reset during active operations
264async fn test_reset_during_operation( 278async fn test_reset_during_operation(
265 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, 279 ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>,
266 uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, 280 uart: &mut Lpuart<'_, Blocking>,
267 peripherals: &hal::pac::Peripherals, 281 peripherals: &hal::pac::Peripherals,
268) { 282) {
269 let initial_counter = ostimer.now(); 283 let initial_counter = ostimer.now();
@@ -304,7 +318,7 @@ async fn test_reset_during_operation(
304} 318}
305 319
306// Helper function to write a u32 value as decimal string 320// Helper function to write a u32 value as decimal string
307fn write_u32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) { 321fn write_u32(uart: &mut Lpuart<'_, Blocking>, value: u32) {
308 if value == 0 { 322 if value == 0 {
309 uart.write_str_blocking("0"); 323 uart.write_str_blocking("0");
310 return; 324 return;
@@ -339,7 +353,7 @@ fn write_u32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) {
339 } 353 }
340} 354}
341 355
342fn write_hex32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) { 356fn write_hex32(uart: &mut Lpuart<'_, Blocking>, value: u32) {
343 let mut buf = [b'0'; 8]; 357 let mut buf = [b'0'; 8];
344 let mut tmp = value; 358 let mut tmp = value;
345 for i in (0..8).rev() { 359 for i in (0..8).rev() {
@@ -351,15 +365,13 @@ fn write_hex32(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u32) {
351 }; 365 };
352 tmp >>= 4; 366 tmp >>= 4;
353 } 367 }
354 for b in &buf { 368 uart.blocking_write(&buf).unwrap();
355 uart.write_byte(*b);
356 }
357} 369}
358 370
359// Helper function to write a u64 value as decimal string 371// Helper function to write a u64 value as decimal string
360fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) { 372fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) {
361 if value == 0 { 373 if value == 0 {
362 uart.write_str_blocking("0"); 374 uart.blocking_write(b"0").unwrap();
363 return; 375 return;
364 } 376 }
365 377
@@ -377,17 +389,17 @@ fn write_u64(uart: &mut hal::uart::Uart<hal::uart::Lpuart2>, value: u64) {
377 while i > 0 { 389 while i > 0 {
378 i -= 1; 390 i -= 1;
379 match buffer[i] { 391 match buffer[i] {
380 b'0' => uart.write_str_blocking("0"), 392 b'0' => uart.blocking_write(b"0").unwrap(),
381 b'1' => uart.write_str_blocking("1"), 393 b'1' => uart.blocking_write(b"1").unwrap(),
382 b'2' => uart.write_str_blocking("2"), 394 b'2' => uart.blocking_write(b"2").unwrap(),
383 b'3' => uart.write_str_blocking("3"), 395 b'3' => uart.blocking_write(b"3").unwrap(),
384 b'4' => uart.write_str_blocking("4"), 396 b'4' => uart.blocking_write(b"4").unwrap(),
385 b'5' => uart.write_str_blocking("5"), 397 b'5' => uart.blocking_write(b"5").unwrap(),
386 b'6' => uart.write_str_blocking("6"), 398 b'6' => uart.blocking_write(b"6").unwrap(),
387 b'7' => uart.write_str_blocking("7"), 399 b'7' => uart.blocking_write(b"7").unwrap(),
388 b'8' => uart.write_str_blocking("8"), 400 b'8' => uart.blocking_write(b"8").unwrap(),
389 b'9' => uart.write_str_blocking("9"), 401 b'9' => uart.blocking_write(b"9").unwrap(),
390 _ => uart.write_str_blocking("?"), 402 _ => uart.blocking_write(b"?").unwrap(),
391 } 403 }
392 } 404 }
393} 405}
diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs
index dc07b5757..40a1207df 100644
--- a/examples/src/bin/rtc_alarm.rs
+++ b/examples/src/bin/rtc_alarm.rs
@@ -3,11 +3,11 @@
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa as hal; 5use embassy_mcxa as hal;
6use embassy_mcxa_examples::init_uart2; 6use hal::lpuart::{Config, Lpuart};
7use hal::rtc::{RtcDateTime, RtcInterruptEnable}; 7use hal::rtc::{RtcDateTime, RtcInterruptEnable};
8use hal::{uart, InterruptExt}; 8use hal::InterruptExt;
9 9
10type MyRtc = hal::rtc::Rtc<hal::rtc::Rtc0>; 10type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>;
11 11
12use embassy_mcxa::bind_interrupts; 12use embassy_mcxa::bind_interrupts;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -24,17 +24,28 @@ static KEEP_RTC: unsafe extern "C" fn() = RTC;
24async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
25 let p = hal::init(hal::config::Config::default()); 25 let p = hal::init(hal::config::Config::default());
26 26
27 // Create UART configuration
28 let config = Config {
29 baudrate_bps: 115_200,
30 enable_tx: true,
31 enable_rx: true,
32 ..Default::default()
33 };
34
35 // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX
27 unsafe { 36 unsafe {
28 init_uart2(hal::pac()); 37 embassy_mcxa_examples::init_uart2_pins(hal::pac());
29 } 38 }
30 39 let mut uart = Lpuart::new_blocking(
31 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; 40 p.LPUART2, // Peripheral
32 let uart = uart::Uart::<uart::Lpuart2>::new(p.LPUART2, uart::Config::new(src)); 41 p.PIO2_2, // TX pin
42 p.PIO2_3, // RX pin
43 config,
44 )
45 .unwrap();
33 46
34 uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n"); 47 uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n");
35 48
36 unsafe { hal::clocks::init_fro16k(hal::pac()) };
37
38 let rtc_config = hal::rtc::get_default_config(); 49 let rtc_config = hal::rtc::get_default_config();
39 50
40 let rtc = MyRtc::new(p.RTC0, rtc_config); 51 let rtc = MyRtc::new(p.RTC0, rtc_config);
diff --git a/examples/src/bin/uart_interrupt.rs b/examples/src/bin/uart_interrupt.rs
deleted file mode 100644
index 100588727..000000000
--- a/examples/src/bin/uart_interrupt.rs
+++ /dev/null
@@ -1,66 +0,0 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::bind_interrupts;
6use embassy_mcxa_examples::init_uart2;
7use hal::interrupt::typelevel::Handler;
8use hal::uart;
9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
10
11// Bind LPUART2 interrupt to our handler
12bind_interrupts!(struct Irqs {
13 LPUART2 => hal::uart::UartInterruptHandler;
14});
15
16#[used]
17#[no_mangle]
18static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2;
19
20// Wrapper function for the interrupt handler
21unsafe extern "C" fn lpuart2_handler() {
22 hal::uart::UartInterruptHandler::on_interrupt();
23}
24
25#[embassy_executor::main]
26async fn main(_spawner: Spawner) {
27 let _p = hal::init(hal::config::Config::default());
28
29 // Enable/clock UART2 before touching its registers
30 unsafe {
31 init_uart2(hal::pac());
32 }
33 let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) };
34 let uart = uart::Uart::<uart::Lpuart2>::new(_p.LPUART2, uart::Config::new(src));
35
36 // Configure LPUART2 interrupt for UART operation BEFORE any UART usage
37 hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3));
38
39 // Manually install the interrupt handler and enable RX IRQs in the peripheral
40 unsafe {
41 hal::interrupt::LPUART2.install_handler(lpuart2_handler);
42 // Enable RX interrupts so the handler actually fires on incoming bytes
43 uart.enable_rx_interrupts();
44 }
45
46 // Print welcome message
47 uart.write_str_blocking("UART interrupt echo demo starting...\r\n");
48 uart.write_str_blocking("Type characters to echo them back.\r\n");
49
50 // Log using defmt if enabled
51 defmt::info!("UART interrupt echo demo starting...");
52
53 loop {
54 // Check if we have received any data
55 if uart.rx_data_available() {
56 if let Some(byte) = uart.try_read_byte() {
57 // Echo it back
58 uart.write_byte(byte);
59 uart.write_str_blocking(" (received)\r\n");
60 }
61 } else {
62 // No data available, wait a bit before checking again
63 cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz
64 }
65 }
66}
diff --git a/examples/src/common/mod.rs b/examples/src/common/mod.rs
deleted file mode 100644
index 8cb4590f8..000000000
--- a/examples/src/common/mod.rs
+++ /dev/null
@@ -1,45 +0,0 @@
1//! Shared board-specific helpers for the FRDM-MCXA276 examples.
2//! These live with the examples so the HAL stays generic.
3
4use hal::{clocks, pins, reset};
5use {embassy_mcxa as hal, panic_probe as _};
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/src/lib.rs b/examples/src/lib.rs
index cf4194559..4bb334da5 100644
--- a/examples/src/lib.rs
+++ b/examples/src/lib.rs
@@ -1,63 +1,31 @@
1#![no_std] 1#![no_std]
2#![allow(clippy::missing_safety_doc)]
2 3
3//! Shared board-specific helpers for the FRDM-MCXA276 examples. 4//! Shared board-specific helpers for the FRDM-MCXA276 examples.
4//! These live with the examples so the HAL stays generic. 5//! These live with the examples so the HAL stays generic.
5 6
6use hal::{clocks, pins, reset}; 7use hal::{clocks, pins};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 8use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8 9
9/// Initialize clocks and pin muxing for UART2 debug console. 10/// Initialize clocks and pin muxing for UART2 debug console.
10/// Safe to call multiple times; writes are idempotent for our use. 11/// Safe to call multiple times; writes are idempotent for our use.
11/// 12pub unsafe fn init_uart2_pins(_p: &hal::pac::Peripherals) {
12/// # Safety 13 // NOTE: Lpuart has been updated to properly enable + reset its own clocks.
13/// 14 // GPIO has not.
14/// Called only once to initialize the peripheral 15 _ = clocks::enable_and_reset::<hal::peripherals::PORT2>(&clocks::periph_helpers::NoConfig);
15#[allow(dead_code)]
16pub unsafe fn init_uart2(p: &hal::pac::Peripherals) {
17 clocks::ensure_frolf_running(p);
18 clocks::enable_uart2_port2(p);
19 reset::release_reset_port2(p);
20 reset::release_reset_lpuart2(p);
21 pins::configure_uart2_pins_port2(); 16 pins::configure_uart2_pins_port2();
22 clocks::select_uart2_clock(p);
23} 17}
24 18
25/// Initialize clocks for the LED GPIO/PORT used by the blink example. 19/// Initialize clocks for the LED GPIO/PORT used by the blink example.
26/// 20pub unsafe fn init_led_gpio_clocks(_p: &hal::pac::Peripherals) {
27/// # Safety 21 _ = clocks::enable_and_reset::<hal::peripherals::PORT3>(&clocks::periph_helpers::NoConfig);
28/// 22 _ = clocks::enable_and_reset::<hal::peripherals::GPIO3>(&clocks::periph_helpers::NoConfig);
29/// Called only once to initialize the peripheral
30#[allow(dead_code)]
31pub unsafe fn init_led(p: &hal::pac::Peripherals) {
32 clocks::enable_led_port(p);
33 reset::release_reset_gpio3(p);
34 reset::release_reset_port3(p);
35}
36
37/// Initialize clocks for OSTIMER0 (1 MHz source).
38///
39/// # Safety
40///
41/// Called only once to initialize the peripheral
42#[allow(dead_code)]
43pub unsafe fn init_ostimer0(p: &hal::pac::Peripherals) {
44 clocks::ensure_frolf_running(p);
45 clocks::enable_ostimer0(p);
46 reset::release_reset_ostimer0(p);
47 clocks::select_ostimer0_clock_1m(p);
48} 23}
49 24
50/// Initialize clocks and pin muxing for ADC. 25/// Initialize clocks and pin muxing for ADC.
51/// 26pub unsafe fn init_adc_pins(_p: &hal::pac::Peripherals) {
52/// # Safety 27 // NOTE: Lpuart has been updated to properly enable + reset its own clocks.
53/// 28 // GPIO has not.
54/// Called only once to initialize the peripheral 29 _ = clocks::enable_and_reset::<hal::peripherals::PORT1>(&clocks::periph_helpers::NoConfig);
55#[allow(dead_code)]
56pub unsafe fn init_adc(p: &hal::pac::Peripherals) {
57 clocks::ensure_frolf_running(p);
58 clocks::enable_adc(p);
59 reset::release_reset_port1(p);
60 reset::release_reset_adc1(p);
61 pins::configure_adc_pins(); 30 pins::configure_adc_pins();
62 clocks::select_adc_clock(p);
63} 31}
diff --git a/src/adc.rs b/src/adc.rs
index 655bf934f..b5ec5983f 100644
--- a/src/adc.rs
+++ b/src/adc.rs
@@ -1,6 +1,10 @@
1//! ADC driver 1//! ADC driver
2use core::sync::atomic::{AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering};
3 3
4use embassy_hal_internal::{Peri, PeripheralType};
5
6use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4};
7use crate::clocks::{enable_and_reset, Gate, PoweredClock};
4use crate::pac; 8use crate::pac;
5use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; 9use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres};
6use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; 10use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts};
@@ -12,7 +16,7 @@ type Regs = pac::adc1::RegisterBlock;
12 16
13static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false); 17static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false);
14// Token-based instance pattern like embassy-imxrt 18// Token-based instance pattern like embassy-imxrt
15pub trait Instance { 19pub trait Instance: Gate<MrccPeriphConfig = AdcConfig> + PeripheralType {
16 fn ptr() -> *const Regs; 20 fn ptr() -> *const Regs;
17} 21}
18 22
@@ -26,12 +30,12 @@ impl Instance for crate::peripherals::ADC1 {
26} 30}
27 31
28// Also implement Instance for the Peri wrapper type 32// Also implement Instance for the Peri wrapper type
29impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> { 33// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> {
30 #[inline(always)] 34// #[inline(always)]
31 fn ptr() -> *const Regs { 35// fn ptr() -> *const Regs {
32 pac::Adc1::ptr() 36// pac::Adc1::ptr()
33 } 37// }
34} 38// }
35 39
36#[derive(Debug, Clone, Copy, PartialEq, Eq)] 40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37#[repr(u8)] 41#[repr(u8)]
@@ -60,6 +64,29 @@ pub struct LpadcConfig {
60 pub enable_conv_pause: bool, 64 pub enable_conv_pause: bool,
61 pub conv_pause_delay: u16, 65 pub conv_pause_delay: u16,
62 pub fifo_watermark: u8, 66 pub fifo_watermark: u8,
67 pub power: PoweredClock,
68 pub source: AdcClockSel,
69 pub div: Div4,
70}
71
72impl Default for LpadcConfig {
73 fn default() -> Self {
74 LpadcConfig {
75 enable_in_doze_mode: true,
76 conversion_average_mode: CalAvgs::NoAverage,
77 enable_analog_preliminary: false,
78 power_up_delay: 0x80,
79 reference_voltage_source: Refsel::Option1,
80 power_level_mode: Pwrsel::Lowest,
81 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
82 enable_conv_pause: false,
83 conv_pause_delay: 0,
84 fifo_watermark: 0,
85 power: PoweredClock::NormalEnabledDeepSleepDisabled,
86 source: AdcClockSel::FroLfDiv,
87 div: Div4::no_div(),
88 }
89 }
63} 90}
64 91
65#[derive(Debug, Clone, Copy, PartialEq, Eq)] 92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -94,15 +121,24 @@ pub struct ConvResult {
94 pub conv_value: u16, 121 pub conv_value: u16,
95} 122}
96 123
97pub struct Adc<I: Instance> { 124pub struct Adc<'a, I: Instance> {
98 _inst: core::marker::PhantomData<I>, 125 _inst: core::marker::PhantomData<&'a mut I>,
99} 126}
100 127
101impl<I: Instance> Adc<I> { 128impl<'a, I: Instance> Adc<'a, I> {
102 /// initialize ADC 129 /// initialize ADC
103 pub fn new(_inst: impl Instance, config: LpadcConfig) -> Self { 130 pub fn new(_inst: Peri<'a, I>, config: LpadcConfig) -> Self {
104 let adc = unsafe { &*I::ptr() }; 131 let adc = unsafe { &*I::ptr() };
105 132
133 let _clock_freq = unsafe {
134 enable_and_reset::<I>(&AdcConfig {
135 power: config.power,
136 source: config.source,
137 div: config.div,
138 })
139 .expect("Adc Init should not fail")
140 };
141
106 /* Reset the module. */ 142 /* Reset the module. */
107 adc.ctrl().modify(|_, w| w.rst().held_in_reset()); 143 adc.ctrl().modify(|_, w| w.rst().held_in_reset());
108 adc.ctrl().modify(|_, w| w.rst().released_from_reset()); 144 adc.ctrl().modify(|_, w| w.rst().released_from_reset());
@@ -194,21 +230,6 @@ impl<I: Instance> Adc<I> {
194 adc.ctrl().modify(|_, w| w.adcen().disabled()); 230 adc.ctrl().modify(|_, w| w.adcen().disabled());
195 } 231 }
196 232
197 pub fn get_default_config() -> LpadcConfig {
198 LpadcConfig {
199 enable_in_doze_mode: true,
200 conversion_average_mode: CalAvgs::NoAverage,
201 enable_analog_preliminary: false,
202 power_up_delay: 0x80,
203 reference_voltage_source: Refsel::Option1,
204 power_level_mode: Pwrsel::Lowest,
205 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
206 enable_conv_pause: false,
207 conv_pause_delay: 0,
208 fifo_watermark: 0,
209 }
210 }
211
212 pub fn do_offset_calibration(&self) { 233 pub fn do_offset_calibration(&self) {
213 let adc = unsafe { &*I::ptr() }; 234 let adc = unsafe { &*I::ptr() };
214 // Enable calibration mode 235 // Enable calibration mode
diff --git a/src/board.rs b/src/board.rs
deleted file mode 100644
index fa679e82c..000000000
--- a/src/board.rs
+++ /dev/null
@@ -1,14 +0,0 @@
1use crate::{clocks, pac, pins};
2
3/// Initialize clocks and pin muxing for UART2 debug console.
4pub unsafe fn init_uart2(p: &pac::Peripherals) {
5 clocks::ensure_frolf_running(p);
6 clocks::enable_uart2_port2(p);
7 pins::configure_uart2_pins_port2();
8 clocks::select_uart2_clock(p);
9}
10
11/// Initialize clocks for the LED GPIO/PORT used by the blink example.
12pub unsafe fn init_led(p: &pac::Peripherals) {
13 clocks::enable_led_port(p);
14}
diff --git a/src/clocks.rs b/src/clocks.rs
deleted file mode 100644
index 65a17cef6..000000000
--- a/src/clocks.rs
+++ /dev/null
@@ -1,134 +0,0 @@
1//! Clock control helpers (no magic numbers, PAC field access only).
2//! Provides reusable gate abstractions for peripherals used by the examples.
3use crate::pac;
4
5/// Trait describing an AHB clock gate that can be toggled through MRCC.
6pub trait Gate {
7 /// Enable the clock gate.
8 unsafe fn enable(mrcc: &pac::mrcc0::RegisterBlock);
9
10 /// Return whether the clock gate is currently enabled.
11 fn is_enabled(mrcc: &pac::mrcc0::RegisterBlock) -> bool;
12}
13
14/// Enable a clock gate for the given peripheral set.
15#[inline]
16pub unsafe fn enable<G: Gate>(peripherals: &pac::Peripherals) {
17 let mrcc = &peripherals.mrcc0;
18 G::enable(mrcc);
19 while !G::is_enabled(mrcc) {}
20 core::arch::asm!("dsb sy; isb sy", options(nomem, nostack, preserves_flags));
21}
22
23/// Check whether a gate is currently enabled.
24#[inline]
25pub fn is_enabled<G: Gate>(peripherals: &pac::Peripherals) -> bool {
26 G::is_enabled(&peripherals.mrcc0)
27}
28
29macro_rules! impl_cc_gate {
30 ($name:ident, $reg:ident, $field:ident) => {
31 pub struct $name;
32
33 impl Gate for $name {
34 #[inline]
35 unsafe fn enable(mrcc: &pac::mrcc0::RegisterBlock) {
36 mrcc.$reg().modify(|_, w| w.$field().enabled());
37 }
38
39 #[inline]
40 fn is_enabled(mrcc: &pac::mrcc0::RegisterBlock) -> bool {
41 mrcc.$reg().read().$field().is_enabled()
42 }
43 }
44 };
45}
46
47pub mod gate {
48 use super::*;
49
50 impl_cc_gate!(Port2, mrcc_glb_cc1, port2);
51 impl_cc_gate!(Port3, mrcc_glb_cc1, port3);
52 impl_cc_gate!(Ostimer0, mrcc_glb_cc1, ostimer0);
53 impl_cc_gate!(Lpuart2, mrcc_glb_cc0, lpuart2);
54 impl_cc_gate!(Gpio3, mrcc_glb_cc2, gpio3);
55 impl_cc_gate!(Port1, mrcc_glb_cc1, port1);
56 impl_cc_gate!(Adc1, mrcc_glb_cc1, adc1);
57}
58
59/// Convenience helper enabling the PORT2 and LPUART2 gates required for the debug UART.
60pub unsafe fn enable_uart2_port2(peripherals: &pac::Peripherals) {
61 enable::<gate::Port2>(peripherals);
62 enable::<gate::Lpuart2>(peripherals);
63}
64
65/// Convenience helper enabling the PORT3 and GPIO3 gates used by the LED in the examples.
66pub unsafe fn enable_led_port(peripherals: &pac::Peripherals) {
67 enable::<gate::Port3>(peripherals);
68 enable::<gate::Gpio3>(peripherals);
69}
70
71/// Convenience helper enabling the OSTIMER0 clock gate.
72pub unsafe fn enable_ostimer0(peripherals: &pac::Peripherals) {
73 enable::<gate::Ostimer0>(peripherals);
74}
75
76pub unsafe fn select_uart2_clock(peripherals: &pac::Peripherals) {
77 // Use FRO_LF_DIV (already running) MUX=0 DIV=0
78 let mrcc = &peripherals.mrcc0;
79 mrcc.mrcc_lpuart2_clksel().write(|w| w.mux().clkroot_func_0());
80 mrcc.mrcc_lpuart2_clkdiv().write(|w| unsafe { w.bits(0) });
81}
82
83pub unsafe fn ensure_frolf_running(peripherals: &pac::Peripherals) {
84 // Ensure FRO_LF divider clock is running (reset default HALT=1 stops it)
85 let sys = &peripherals.syscon;
86 sys.frolfdiv().modify(|_, w| {
87 // DIV defaults to 0; keep it explicit and clear HALT
88 unsafe { w.div().bits(0) }.halt().run()
89 });
90}
91
92/// Compute the FRO_LF_DIV output frequency currently selected for LPUART2.
93/// Assumes select_uart2_clock() has chosen MUX=0 (FRO_LF_DIV) and DIV is set in SYSCON.FRO_LF_DIV.
94pub unsafe fn uart2_src_hz(peripherals: &pac::Peripherals) -> u32 {
95 // SYSCON.FRO_LF_DIV: DIV field is simple divider: freq_out = 12_000_000 / (DIV+1) for many NXP parts.
96 // On MCXA276 FRO_LF base is 12 MHz; our init keeps DIV=0, so result=12_000_000.
97 // Read it anyway for future generality.
98 let div = peripherals.syscon.frolfdiv().read().div().bits() as u32;
99 let base = 12_000_000u32;
100 base / (div + 1)
101}
102
103/// Enable clock gate and release reset for OSTIMER0.
104/// Select OSTIMER0 clock source = 1 MHz root (working bring-up configuration).
105pub unsafe fn select_ostimer0_clock_1m(peripherals: &pac::Peripherals) {
106 let mrcc = &peripherals.mrcc0;
107 mrcc.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_1m());
108}
109
110pub unsafe fn init_fro16k(peripherals: &pac::Peripherals) {
111 let vbat = &peripherals.vbat0;
112 // Enable FRO16K oscillator
113 vbat.froctla().modify(|_, w| w.fro_en().set_bit());
114
115 // Lock the control register
116 vbat.frolcka().modify(|_, w| w.lock().set_bit());
117
118 // Enable clock outputs to both VSYS and VDD_CORE domains
119 // Bit 0: clk_16k0 to VSYS domain
120 // Bit 1: clk_16k1 to VDD_CORE domain
121 vbat.froclke().modify(|_, w| unsafe { w.clke().bits(0x3) });
122}
123
124pub unsafe fn enable_adc(peripherals: &pac::Peripherals) {
125 enable::<gate::Port1>(peripherals);
126 enable::<gate::Adc1>(peripherals);
127}
128
129pub unsafe fn select_adc_clock(peripherals: &pac::Peripherals) {
130 // Use FRO_LF_DIV (already running) MUX=0 DIV=0
131 let mrcc = &peripherals.mrcc0;
132 mrcc.mrcc_adc_clksel().write(|w| w.mux().clkroot_func_0());
133 mrcc.mrcc_adc_clkdiv().write(|w| unsafe { w.bits(0) });
134}
diff --git a/src/clocks/config.rs b/src/clocks/config.rs
new file mode 100644
index 000000000..a517afcca
--- /dev/null
+++ b/src/clocks/config.rs
@@ -0,0 +1,199 @@
1//! Clock Configuration
2//!
3//! This module holds configuration types used for the system clocks. For
4//! configuration of individual peripherals, see [`super::periph_helpers`].
5
6use super::PoweredClock;
7
8/// This type represents a divider in the range 1..=256.
9///
10/// At a hardware level, this is an 8-bit register from 0..=255,
11/// which adds one.
12#[derive(Copy, Clone, Debug, PartialEq, Eq)]
13pub struct Div8(pub(super) u8);
14
15impl Div8 {
16 /// Store a "raw" divisor value that will divide the source by
17 /// `(n + 1)`, e.g. `Div8::from_raw(0)` will divide the source
18 /// by 1, and `Div8::from_raw(255)` will divide the source by
19 /// 256.
20 pub const fn from_raw(n: u8) -> Self {
21 Self(n)
22 }
23
24 /// Store a specific divisor value that will divide the source
25 /// by `n`. e.g. `Div8::from_divisor(1)` will divide the source
26 /// by 1, and `Div8::from_divisor(256)` will divide the source
27 /// by 256.
28 ///
29 /// Will return `None` if `n` is not in the range `1..=256`.
30 /// Consider [`Self::from_raw`] for an infallible version.
31 pub const fn from_divisor(n: u16) -> Option<Self> {
32 let Some(n) = n.checked_sub(1) else {
33 return None;
34 };
35 if n > (u8::MAX as u16) {
36 return None;
37 }
38 Some(Self(n as u8))
39 }
40
41 /// Convert into "raw" bits form
42 #[inline(always)]
43 pub const fn into_bits(self) -> u8 {
44 self.0
45 }
46
47 /// Convert into "divisor" form, as a u32 for convenient frequency math
48 #[inline(always)]
49 pub const fn into_divisor(self) -> u32 {
50 self.0 as u32 + 1
51 }
52}
53
54/// ```text
55/// ┌─────────────────────────────────────────────────────────┐
56/// │ │
57/// │ ┌───────────┐ clk_out ┌─────────┐ │
58/// XTAL ──────┼──▷│ System │───────────▷│ │ clk_in │
59/// │ │ OSC │ clkout_byp │ MUX │──────────────────┼──────▷
60/// EXTAL ──────┼──▷│ │───────────▷│ │ │
61/// │ └───────────┘ └─────────┘ │
62/// │ │
63/// │ ┌───────────┐ fro_hf_root ┌────┐ fro_hf │
64/// │ │ FRO180 ├───────┬─────▷│ CG │─────────────────────┼──────▷
65/// │ │ │ │ ├────┤ clk_45m │
66/// │ │ │ └─────▷│ CG │─────────────────────┼──────▷
67/// │ └───────────┘ └────┘ │
68/// │ ┌───────────┐ fro_12m_root ┌────┐ fro_12m │
69/// │ │ FRO12M │────────┬─────▷│ CG │────────────────────┼──────▷
70/// │ │ │ │ ├────┤ clk_1m │
71/// │ │ │ └─────▷│1/12│────────────────────┼──────▷
72/// │ └───────────┘ └────┘ │
73/// │ │
74/// │ ┌──────────┐ │
75/// │ │000 │ │
76/// │ clk_in │ │ │
77/// │ ───────────────▷│001 │ │
78/// │ fro_12m │ │ │
79/// │ ───────────────▷│010 │ │
80/// │ fro_hf_root │ │ │
81/// │ ───────────────▷│011 │ main_clk │
82/// │ │ │───────────────────────────┼──────▷
83/// clk_16k ──────┼─────────────────▷│100 │ │
84/// │ none │ │ │
85/// │ ───────────────▷│101 │ │
86/// │ pll1_clk │ │ │
87/// │ ───────────────▷│110 │ │
88/// │ none │ │ │
89/// │ ───────────────▷│111 │ │
90/// │ └──────────┘ │
91/// │ ▲ │
92/// │ │ │
93/// │ SCG SCS │
94/// │ SCG-Lite │
95/// └─────────────────────────────────────────────────────────┘
96///
97///
98/// clk_in ┌─────┐
99/// ───────────────▷│00 │
100/// clk_45m │ │
101/// ───────────────▷│01 │ ┌───────────┐ pll1_clk
102/// none │ │─────▷│ SPLL │───────────────▷
103/// ───────────────▷│10 │ └───────────┘
104/// fro_12m │ │
105/// ───────────────▷│11 │
106/// └─────┘
107/// ```
108#[non_exhaustive]
109pub struct ClocksConfig {
110 /// FIRC, FRO180, 45/60/90/180M clock source
111 pub firc: Option<FircConfig>,
112 /// SIRC, FRO12M, clk_12m clock source
113 // NOTE: I don't think we *can* disable the SIRC?
114 pub sirc: SircConfig,
115 /// FRO16K clock source
116 pub fro16k: Option<Fro16KConfig>,
117}
118
119// FIRC/FRO180M
120
121/// ```text
122/// ┌───────────┐ fro_hf_root ┌────┐ fro_hf
123/// │ FRO180M ├───────┬─────▷│GATE│──────────▷
124/// │ │ │ ├────┤ clk_45m
125/// │ │ └─────▷│GATE│──────────▷
126/// └───────────┘ └────┘
127/// ```
128#[non_exhaustive]
129pub struct FircConfig {
130 /// Selected clock frequency
131 pub frequency: FircFreqSel,
132 /// Selected power state of the clock
133 pub power: PoweredClock,
134 /// Is the "fro_hf" gated clock enabled?
135 pub fro_hf_enabled: bool,
136 /// Is the "clk_45m" gated clock enabled?
137 pub clk_45m_enabled: bool,
138 /// Is the "fro_hf_div" clock enabled? Requires `fro_hf`!
139 pub fro_hf_div: Option<Div8>,
140}
141
142/// Selected FIRC frequency
143pub enum FircFreqSel {
144 /// 45MHz Output
145 Mhz45,
146 /// 60MHz Output
147 Mhz60,
148 /// 90MHz Output
149 Mhz90,
150 /// 180MHz Output
151 Mhz180,
152}
153
154// SIRC/FRO12M
155
156/// ```text
157/// ┌───────────┐ fro_12m_root ┌────┐ fro_12m
158/// │ FRO12M │────────┬─────▷│ CG │──────────▷
159/// │ │ │ ├────┤ clk_1m
160/// │ │ └─────▷│1/12│──────────▷
161/// └───────────┘ └────┘
162/// ```
163#[non_exhaustive]
164pub struct SircConfig {
165 pub power: PoweredClock,
166 // peripheral output, aka sirc_12mhz
167 pub fro_12m_enabled: bool,
168 /// Is the "fro_lf_div" clock enabled? Requires `fro_12m`!
169 pub fro_lf_div: Option<Div8>,
170}
171
172#[non_exhaustive]
173pub struct Fro16KConfig {
174 pub vsys_domain_active: bool,
175 pub vdd_core_domain_active: bool,
176}
177
178impl Default for ClocksConfig {
179 fn default() -> Self {
180 Self {
181 firc: Some(FircConfig {
182 frequency: FircFreqSel::Mhz45,
183 power: PoweredClock::NormalEnabledDeepSleepDisabled,
184 fro_hf_enabled: true,
185 clk_45m_enabled: true,
186 fro_hf_div: None,
187 }),
188 sirc: SircConfig {
189 power: PoweredClock::AlwaysEnabled,
190 fro_12m_enabled: true,
191 fro_lf_div: None,
192 },
193 fro16k: Some(Fro16KConfig {
194 vsys_domain_active: true,
195 vdd_core_domain_active: true,
196 }),
197 }
198 }
199}
diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs
new file mode 100644
index 000000000..e02840592
--- /dev/null
+++ b/src/clocks/mod.rs
@@ -0,0 +1,887 @@
1//! # Clock Module
2//!
3//! For the MCX-A, we separate clock and peripheral control into two main stages:
4//!
5//! 1. At startup, e.g. when `embassy_mcxa::init()` is called, we configure the
6//! core system clocks, including external and internal oscillators. This
7//! configuration is then largely static for the duration of the program.
8//! 2. When HAL drivers are created, e.g. `Lpuart::new()` is called, the driver
9//! is responsible for two main things:
10//! * Ensuring that any required "upstream" core system clocks necessary for
11//! clocking the peripheral is active and configured to a reasonable value
12//! * Enabling the clock gates for that peripheral, and resetting the peripheral
13//!
14//! From a user perspective, only step 1 is visible. Step 2 is automatically handled
15//! by HAL drivers, using interfaces defined in this module.
16//!
17//! It is also possible to *view* the state of the clock configuration after [`init()`]
18//! has been called, using the [`with_clocks()`] function, which provides a view of the
19//! [`Clocks`] structure.
20//!
21//! ## For HAL driver implementors
22//!
23//! The majority of peripherals in the MCXA chip are fed from either a "hard-coded" or
24//! configurable clock source, e.g. selecting the FROM12M or `clk_1m` as a source. This
25//! selection, as well as often any pre-scaler division from that source clock, is made
26//! through MRCC registers.
27//!
28//! Any peripheral that is controlled through the MRCC register can automatically implement
29//! the necessary APIs using the `impl_cc_gate!` macro in this module. You will also need
30//! to define the configuration surface and steps necessary to fully configure that peripheral
31//! from a clocks perspective by:
32//!
33//! 1. Defining a configuration type in the [`periph_helpers`] module that contains any selects
34//! or divisions available to the HAL driver
35//! 2. Implementing the [`periph_helpers::SPConfHelper`] trait, which should check that the
36//! necessary input clocks are reasonable
37
38use core::cell::RefCell;
39
40use config::{ClocksConfig, FircConfig, FircFreqSel, Fro16KConfig, SircConfig};
41use mcxa_pac::scg0::firccsr::{FircFclkPeriphEn, FircSclkPeriphEn, Fircsten};
42use mcxa_pac::scg0::sirccsr::{SircClkPeriphEn, Sircsten};
43use periph_helpers::SPConfHelper;
44
45use crate::pac;
46pub mod config;
47pub mod periph_helpers;
48
49//
50// Statics/Consts
51//
52
53/// The state of system core clocks.
54///
55/// Initialized by [`init()`], and then unchanged for the remainder of the program.
56static CLOCKS: critical_section::Mutex<RefCell<Option<Clocks>>> = critical_section::Mutex::new(RefCell::new(None));
57
58//
59// Free functions
60//
61
62/// Initialize the core system clocks with the given [`ClocksConfig`].
63///
64/// This function should be called EXACTLY once at start-up, usually via a
65/// call to [`embassy_mcxa::init()`](crate::init()). Subsequent calls will
66/// return an error.
67pub fn init(settings: ClocksConfig) -> Result<(), ClockError> {
68 critical_section::with(|cs| {
69 if CLOCKS.borrow_ref(cs).is_some() {
70 Err(ClockError::AlreadyInitialized)
71 } else {
72 Ok(())
73 }
74 })?;
75
76 let mut clocks = Clocks::default();
77 let mut operator = ClockOperator {
78 clocks: &mut clocks,
79 config: &settings,
80
81 _mrcc0: unsafe { pac::Mrcc0::steal() },
82 scg0: unsafe { pac::Scg0::steal() },
83 syscon: unsafe { pac::Syscon::steal() },
84 vbat0: unsafe { pac::Vbat0::steal() },
85 };
86
87 operator.configure_firc_clocks()?;
88 operator.configure_sirc_clocks()?;
89 operator.configure_fro16k_clocks()?;
90
91 // For now, just use FIRC as the main/cpu clock, which should already be
92 // the case on reset
93 assert!(operator.scg0.rccr().read().scs().is_firc());
94 assert_eq!(operator.syscon.ahbclkdiv().read().div().bits(), 0);
95 operator.clocks.main_clk = Some(operator.clocks.fro_hf_root.clone().unwrap());
96
97 critical_section::with(|cs| {
98 let mut clks = CLOCKS.borrow_ref_mut(cs);
99 assert!(clks.is_none(), "Clock setup race!");
100 *clks = Some(clocks);
101 });
102
103 Ok(())
104}
105
106/// Obtain the full clocks structure, calling the given closure in a critical section.
107///
108/// The given closure will be called with read-only access to the state of the system
109/// clocks. This can be used to query and return the state of a given clock.
110///
111/// As the caller's closure will be called in a critical section, care must be taken
112/// not to block or cause any other undue delays while accessing.
113///
114/// Calls to this function will not succeed until after a successful call to `init()`,
115/// and will always return None.
116pub fn with_clocks<R: 'static, F: FnOnce(&Clocks) -> R>(f: F) -> Option<R> {
117 critical_section::with(|cs| {
118 let c = CLOCKS.borrow_ref(cs);
119 let c = c.as_ref()?;
120 Some(f(c))
121 })
122}
123
124//
125// Structs/Enums
126//
127
128/// The `Clocks` structure contains the initialized state of the core system clocks
129///
130/// These values are configured by providing [`config::ClocksConfig`] to the [`init()`] function
131/// at boot time.
132#[derive(Default, Debug, Clone)]
133#[non_exhaustive]
134pub struct Clocks {
135 /// The `clk_in` is a clock provided by an external oscillator
136 pub clk_in: Option<Clock>,
137
138 // FRO180M stuff
139 //
140 /// `fro_hf_root` is the direct output of the `FRO180M` internal oscillator
141 ///
142 /// It is used to feed downstream clocks, such as `fro_hf`, `clk_45m`,
143 /// and `fro_hf_div`.
144 pub fro_hf_root: Option<Clock>,
145
146 /// `fro_hf` is the same frequency as `fro_hf_root`, but behind a gate.
147 pub fro_hf: Option<Clock>,
148
149 /// `clk_45` is a 45MHz clock, sourced from `fro_hf`.
150 pub clk_45m: Option<Clock>,
151
152 /// `fro_hf_div` is a configurable frequency clock, sourced from `fro_hf`.
153 pub fro_hf_div: Option<Clock>,
154
155 //
156 // End FRO180M
157
158 // FRO12M stuff
159 //
160 /// `fro_12m_root` is the direct output of the `FRO12M` internal oscillator
161 ///
162 /// It is used to feed downstream clocks, such as `fro_12m`, `clk_1m`,
163 /// `and `fro_lf_div`.
164 pub fro_12m_root: Option<Clock>,
165
166 /// `fro_12m` is the same frequency as `fro_12m_root`, but behind a gate.
167 pub fro_12m: Option<Clock>,
168
169 /// `clk_1m` is a 1MHz clock, sourced from `fro_12m`
170 pub clk_1m: Option<Clock>,
171
172 /// `fro_lf_div` is a configurable frequency clock, sourced from `fro_12m`
173 pub fro_lf_div: Option<Clock>,
174 //
175 // End FRO12M stuff
176 /// `clk_16k_vsys` is one of two outputs of the `FRO16K` internal oscillator.
177 ///
178 /// Also referred to as `clk_16k[0]` in the datasheet, it feeds peripherals in
179 /// the system domain, such as the CMP and RTC.
180 pub clk_16k_vsys: Option<Clock>,
181
182 /// `clk_16k_vdd_core` is one of two outputs of the `FRO16K` internal oscillator.
183 ///
184 /// Also referred to as `clk_16k[1]` in the datasheet, it feeds peripherals in
185 /// the VDD Core domain, such as the OSTimer or LPUarts.
186 pub clk_16k_vdd_core: Option<Clock>,
187
188 /// `main_clk` is the main clock used by the CPU, AHB, APB, IPS bus, and some
189 /// peripherals.
190 pub main_clk: Option<Clock>,
191
192 /// `pll1_clk` is the output of the main system PLL, `pll1`.
193 pub pll1_clk: Option<Clock>,
194}
195
196/// `ClockError` is the main error returned when configuring or checking clock state
197#[derive(Debug, Copy, Clone, Eq, PartialEq)]
198#[cfg_attr(feature = "defmt", derive(defmt::Format))]
199#[non_exhaustive]
200pub enum ClockError {
201 /// The system clocks were never initialized by calling [`init()`]
202 NeverInitialized,
203 /// The [`init()`] function was called more than once
204 AlreadyInitialized,
205 /// The requested configuration was not possible to fulfill, as the system clocks
206 /// were not configured in a compatible way
207 BadConfig { clock: &'static str, reason: &'static str },
208 /// The requested configuration was not possible to fulfill, as the required system
209 /// clocks have not yet been implemented.
210 NotImplemented { clock: &'static str },
211 /// The requested peripheral could not be configured, as the steps necessary to
212 /// enable it have not yet been implemented.
213 UnimplementedConfig,
214}
215
216/// Information regarding a system clock
217#[derive(Debug, Clone)]
218pub struct Clock {
219 /// The frequency, in Hz, of the given clock
220 pub frequency: u32,
221 /// The power state of the clock, e.g. whether it is active in deep sleep mode
222 /// or not.
223 pub power: PoweredClock,
224}
225
226/// The power state of a given clock.
227///
228/// On the MCX-A, when Deep-Sleep is entered, any clock not configured for Deep Sleep
229/// mode will be stopped. This means that any downstream usage, e.g. by peripherals,
230/// will also stop.
231///
232/// In the future, we will provide an API for entering Deep Sleep, and if there are
233/// any peripherals that are NOT using an `AlwaysEnabled` clock active, entry into
234/// Deep Sleep will be prevented, in order to avoid misbehaving peripherals.
235#[derive(Debug, Clone, Copy, PartialEq, Eq)]
236pub enum PoweredClock {
237 /// The given clock will NOT continue running in Deep Sleep mode
238 NormalEnabledDeepSleepDisabled,
239 /// The given clock WILL continue running in Deep Sleep mode
240 AlwaysEnabled,
241}
242
243/// The ClockOperator is a private helper type that contains the methods used
244/// during system clock initialization.
245///
246/// # SAFETY
247///
248/// Concurrent access to clock-relevant peripheral registers, such as `MRCC`, `SCG`,
249/// `SYSCON`, and `VBAT` should not be allowed for the duration of the [`init()`] function.
250struct ClockOperator<'a> {
251 /// A mutable reference to the current state of system clocks
252 clocks: &'a mut Clocks,
253 /// A reference to the requested configuration provided by the caller of [`init()`]
254 config: &'a ClocksConfig,
255
256 // We hold on to stolen peripherals
257 _mrcc0: pac::Mrcc0,
258 scg0: pac::Scg0,
259 syscon: pac::Syscon,
260 vbat0: pac::Vbat0,
261}
262
263/// Trait describing an AHB clock gate that can be toggled through MRCC.
264pub trait Gate {
265 type MrccPeriphConfig: SPConfHelper;
266
267 /// Enable the clock gate.
268 ///
269 /// # SAFETY
270 ///
271 /// The current peripheral must be disabled prior to calling this method
272 unsafe fn enable_clock();
273
274 /// Disable the clock gate.
275 ///
276 /// # SAFETY
277 ///
278 /// There must be no active user of this peripheral when calling this method
279 unsafe fn disable_clock();
280
281 /// Drive the peripheral into reset.
282 ///
283 /// # SAFETY
284 ///
285 /// There must be no active user of this peripheral when calling this method
286 unsafe fn assert_reset();
287
288 /// Drive the peripheral out of reset.
289 ///
290 /// # SAFETY
291 ///
292 /// There must be no active user of this peripheral when calling this method
293 unsafe fn release_reset();
294
295 /// Return whether the clock gate for this peripheral is currently enabled.
296 fn is_clock_enabled() -> bool;
297
298 /// Return whether the peripheral is currently held in reset.
299 fn is_reset_released() -> bool;
300}
301
302/// This is the primary helper method HAL drivers are expected to call when creating
303/// an instance of the peripheral.
304///
305/// This method:
306///
307/// 1. Enables the MRCC clock gate for this peripheral
308/// 2. Calls the `G::MrccPeriphConfig::post_enable_config()` method, returning an error
309/// and re-disabling the peripheral if this fails.
310/// 3. Pulses the MRCC reset line, to reset the peripheral to the default state
311/// 4. Returns the frequency, in Hz that is fed into the peripheral, taking into account
312/// the selected upstream clock, as well as any division specified by `cfg`.
313///
314/// NOTE: if a clock is disabled, sourced from an "ambient" clock source, this method
315/// may return `Ok(0)`. In the future, this might be updated to return the correct
316/// "ambient" clock, e.g. the AHB/APB frequency.
317///
318/// # SAFETY
319///
320/// This peripheral must not yet be in use prior to calling `enable_and_reset`.
321#[inline]
322pub unsafe fn enable_and_reset<G: Gate>(cfg: &G::MrccPeriphConfig) -> Result<u32, ClockError> {
323 let freq = enable::<G>(cfg).inspect_err(|_| disable::<G>())?;
324 pulse_reset::<G>();
325 Ok(freq)
326}
327
328/// Enable the clock gate for the given peripheral.
329///
330/// Prefer [`enable_and_reset`] unless you are specifically avoiding a pulse of the reset, or need
331/// to control the duration of the pulse more directly.
332///
333/// # SAFETY
334///
335/// This peripheral must not yet be in use prior to calling `enable`.
336#[inline]
337pub unsafe fn enable<G: Gate>(cfg: &G::MrccPeriphConfig) -> Result<u32, ClockError> {
338 G::enable_clock();
339 while !G::is_clock_enabled() {}
340 core::arch::asm!("dsb sy; isb sy", options(nomem, nostack, preserves_flags));
341
342 let freq = critical_section::with(|cs| {
343 let clocks = CLOCKS.borrow_ref(cs);
344 let clocks = clocks.as_ref().ok_or(ClockError::NeverInitialized)?;
345 cfg.post_enable_config(clocks)
346 });
347
348 freq.inspect_err(|_e| {
349 G::disable_clock();
350 })
351}
352
353/// Disable the clock gate for the given peripheral.
354///
355/// # SAFETY
356///
357/// This peripheral must no longer be in use prior to calling `enable`.
358#[allow(dead_code)]
359#[inline]
360pub unsafe fn disable<G: Gate>() {
361 G::disable_clock();
362}
363
364/// Check whether a gate is currently enabled.
365#[allow(dead_code)]
366#[inline]
367pub fn is_clock_enabled<G: Gate>() -> bool {
368 G::is_clock_enabled()
369}
370
371/// Release a reset line for the given peripheral set.
372///
373/// Prefer [`enable_and_reset`].
374///
375/// # SAFETY
376///
377/// This peripheral must not yet be in use prior to calling `release_reset`.
378#[inline]
379pub unsafe fn release_reset<G: Gate>() {
380 G::release_reset();
381}
382
383/// Assert a reset line for the given peripheral set.
384///
385/// Prefer [`enable_and_reset`].
386///
387/// # SAFETY
388///
389/// This peripheral must not yet be in use prior to calling `assert_reset`.
390#[inline]
391pub unsafe fn assert_reset<G: Gate>() {
392 G::assert_reset();
393}
394
395/// Check whether the peripheral is held in reset.
396#[inline]
397pub unsafe fn is_reset_released<G: Gate>() -> bool {
398 G::is_reset_released()
399}
400
401/// Pulse a reset line (assert then release) with a short delay.
402///
403/// Prefer [`enable_and_reset`].
404///
405/// # SAFETY
406///
407/// This peripheral must not yet be in use prior to calling `release_reset`.
408#[inline]
409pub unsafe fn pulse_reset<G: Gate>() {
410 G::assert_reset();
411 cortex_m::asm::nop();
412 cortex_m::asm::nop();
413 G::release_reset();
414}
415
416//
417// `impl`s for structs/enums
418//
419
420/// The [`Clocks`] type's methods generally take the form of "ensure X clock is active".
421///
422/// These methods are intended to be used by HAL peripheral implementors to ensure that their
423/// selected clocks are active at a suitable level at time of construction. These methods
424/// return the frequency of the requested clock, in Hertz, or a [`ClockError`].
425impl Clocks {
426 /// Ensure the `fro_lf_div` clock is active and valid at the given power state.
427 pub fn ensure_fro_lf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
428 let Some(clk) = self.fro_lf_div.as_ref() else {
429 return Err(ClockError::BadConfig {
430 clock: "fro_lf_div",
431 reason: "required but not active",
432 });
433 };
434 if !clk.power.meets_requirement_of(at_level) {
435 return Err(ClockError::BadConfig {
436 clock: "fro_lf_div",
437 reason: "not low power active",
438 });
439 }
440 Ok(clk.frequency)
441 }
442
443 /// Ensure the `fro_hf` clock is active and valid at the given power state.
444 pub fn ensure_fro_hf_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
445 let Some(clk) = self.fro_hf.as_ref() else {
446 return Err(ClockError::BadConfig {
447 clock: "fro_hf",
448 reason: "required but not active",
449 });
450 };
451 if !clk.power.meets_requirement_of(at_level) {
452 return Err(ClockError::BadConfig {
453 clock: "fro_hf",
454 reason: "not low power active",
455 });
456 }
457 Ok(clk.frequency)
458 }
459
460 /// Ensure the `fro_hf_div` clock is active and valid at the given power state.
461 pub fn ensure_fro_hf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
462 let Some(clk) = self.fro_hf_div.as_ref() else {
463 return Err(ClockError::BadConfig {
464 clock: "fro_hf_div",
465 reason: "required but not active",
466 });
467 };
468 if !clk.power.meets_requirement_of(at_level) {
469 return Err(ClockError::BadConfig {
470 clock: "fro_hf_div",
471 reason: "not low power active",
472 });
473 }
474 Ok(clk.frequency)
475 }
476
477 /// Ensure the `clk_in` clock is active and valid at the given power state.
478 pub fn ensure_clk_in_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> {
479 Err(ClockError::NotImplemented { clock: "clk_in" })
480 }
481
482 /// Ensure the `clk_16k_vsys` clock is active and valid at the given power state.
483 pub fn ensure_clk_16k_vsys_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> {
484 // NOTE: clk_16k is always active in low power mode
485 Ok(self
486 .clk_16k_vsys
487 .as_ref()
488 .ok_or(ClockError::BadConfig {
489 clock: "clk_16k_vsys",
490 reason: "required but not active",
491 })?
492 .frequency)
493 }
494
495 /// Ensure the `clk_16k_vdd_core` clock is active and valid at the given power state.
496 pub fn ensure_clk_16k_vdd_core_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> {
497 // NOTE: clk_16k is always active in low power mode
498 Ok(self
499 .clk_16k_vdd_core
500 .as_ref()
501 .ok_or(ClockError::BadConfig {
502 clock: "clk_16k_vdd_core",
503 reason: "required but not active",
504 })?
505 .frequency)
506 }
507
508 /// Ensure the `clk_1m` clock is active and valid at the given power state.
509 pub fn ensure_clk_1m_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
510 let Some(clk) = self.clk_1m.as_ref() else {
511 return Err(ClockError::BadConfig {
512 clock: "clk_1m",
513 reason: "required but not active",
514 });
515 };
516 if !clk.power.meets_requirement_of(at_level) {
517 return Err(ClockError::BadConfig {
518 clock: "clk_1m",
519 reason: "not low power active",
520 });
521 }
522 Ok(clk.frequency)
523 }
524
525 /// Ensure the `pll1_clk_div` clock is active and valid at the given power state.
526 pub fn ensure_pll1_clk_div_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> {
527 Err(ClockError::NotImplemented { clock: "pll1_clk_div" })
528 }
529}
530
531impl PoweredClock {
532 /// Does THIS clock meet the power requirements of the OTHER clock?
533 pub fn meets_requirement_of(&self, other: &Self) -> bool {
534 match (self, other) {
535 (PoweredClock::NormalEnabledDeepSleepDisabled, PoweredClock::AlwaysEnabled) => false,
536 (PoweredClock::NormalEnabledDeepSleepDisabled, PoweredClock::NormalEnabledDeepSleepDisabled) => true,
537 (PoweredClock::AlwaysEnabled, PoweredClock::NormalEnabledDeepSleepDisabled) => true,
538 (PoweredClock::AlwaysEnabled, PoweredClock::AlwaysEnabled) => true,
539 }
540 }
541}
542
543impl ClockOperator<'_> {
544 /// Configure the FIRC/FRO180M clock family
545 ///
546 /// NOTE: Currently we require this to be a fairly hardcoded value, as this clock is used
547 /// as the main clock used for the CPU, AHB, APB, etc.
548 fn configure_firc_clocks(&mut self) -> Result<(), ClockError> {
549 const HARDCODED_ERR: Result<(), ClockError> = Err(ClockError::BadConfig {
550 clock: "firc",
551 reason: "For now, FIRC must be enabled and in default state!",
552 });
553
554 // Did the user give us a FIRC config?
555 let Some(firc) = self.config.firc.as_ref() else {
556 return HARDCODED_ERR;
557 };
558 // Is the FIRC set to 45MHz (should be reset default)
559 if !matches!(firc.frequency, FircFreqSel::Mhz45) {
560 return HARDCODED_ERR;
561 }
562 let base_freq = 45_000_000;
563
564 // Now, check if the FIRC as expected for our hardcoded value
565 let mut firc_ok = true;
566
567 // Is the hardware currently set to the default 45MHz?
568 //
569 // NOTE: the SVD currently has the wrong(?) values for these:
570 // 45 -> 48
571 // 60 -> 64
572 // 90 -> 96
573 // 180 -> 192
574 // Probably correct-ish, but for a different trim value?
575 firc_ok &= self.scg0.firccfg().read().freq_sel().is_firc_48mhz_192s();
576
577 // Check some values in the CSR
578 let csr = self.scg0.firccsr().read();
579 // Is it enabled?
580 firc_ok &= csr.fircen().is_enabled();
581 // Is it accurate?
582 firc_ok &= csr.fircacc().is_enabled_and_valid();
583 // Is there no error?
584 firc_ok &= csr.fircerr().is_error_not_detected();
585 // Is the FIRC the system clock?
586 firc_ok &= csr.fircsel().is_firc();
587 // Is it valid?
588 firc_ok &= csr.fircvld().is_enabled_and_valid();
589
590 // Are we happy with the current (hardcoded) state?
591 if !firc_ok {
592 return HARDCODED_ERR;
593 }
594
595 // Note that the fro_hf_root is active
596 self.clocks.fro_hf_root = Some(Clock {
597 frequency: base_freq,
598 power: firc.power,
599 });
600
601 // Okay! Now we're past that, let's enable all the downstream clocks.
602 let FircConfig {
603 frequency: _,
604 power,
605 fro_hf_enabled,
606 clk_45m_enabled,
607 fro_hf_div,
608 } = firc;
609
610 // When is the FRO enabled?
611 let pow_set = match power {
612 PoweredClock::NormalEnabledDeepSleepDisabled => Fircsten::DisabledInStopModes,
613 PoweredClock::AlwaysEnabled => Fircsten::EnabledInStopModes,
614 };
615
616 // Do we enable the `fro_hf` output?
617 let fro_hf_set = if *fro_hf_enabled {
618 self.clocks.fro_hf = Some(Clock {
619 frequency: base_freq,
620 power: *power,
621 });
622 FircFclkPeriphEn::Enabled
623 } else {
624 FircFclkPeriphEn::Disabled
625 };
626
627 // Do we enable the `clk_45m` output?
628 let clk_45m_set = if *clk_45m_enabled {
629 self.clocks.clk_45m = Some(Clock {
630 frequency: 45_000_000,
631 power: *power,
632 });
633 FircSclkPeriphEn::Enabled
634 } else {
635 FircSclkPeriphEn::Disabled
636 };
637
638 self.scg0.firccsr().modify(|_r, w| {
639 w.fircsten().variant(pow_set);
640 w.firc_fclk_periph_en().variant(fro_hf_set);
641 w.firc_sclk_periph_en().variant(clk_45m_set);
642 w
643 });
644
645 // Do we enable the `fro_hf_div` output?
646 if let Some(d) = fro_hf_div.as_ref() {
647 // We need `fro_hf` to be enabled
648 if !*fro_hf_enabled {
649 return Err(ClockError::BadConfig {
650 clock: "fro_hf_div",
651 reason: "fro_hf not enabled",
652 });
653 }
654
655 // Halt and reset the div
656 self.syscon.frohfdiv().write(|w| {
657 w.halt().halt();
658 w.reset().asserted();
659 w
660 });
661 // Then change the div, unhalt it, and reset it
662 self.syscon.frohfdiv().write(|w| {
663 unsafe {
664 w.div().bits(d.into_bits());
665 }
666 w.halt().run();
667 w.reset().released();
668 w
669 });
670
671 // Wait for clock to stabilize
672 while self.syscon.frohfdiv().read().unstab().is_ongoing() {}
673
674 // Store off the clock info
675 self.clocks.fro_hf_div = Some(Clock {
676 frequency: base_freq / d.into_divisor(),
677 power: *power,
678 });
679 }
680
681 Ok(())
682 }
683
684 /// Configure the SIRC/FRO12M clock family
685 fn configure_sirc_clocks(&mut self) -> Result<(), ClockError> {
686 let SircConfig {
687 power,
688 fro_12m_enabled,
689 fro_lf_div,
690 } = &self.config.sirc;
691 let base_freq = 12_000_000;
692
693 // Allow writes
694 self.scg0.sirccsr().modify(|_r, w| w.lk().write_enabled());
695 self.clocks.fro_12m_root = Some(Clock {
696 frequency: base_freq,
697 power: *power,
698 });
699
700 let deep = match power {
701 PoweredClock::NormalEnabledDeepSleepDisabled => Sircsten::Disabled,
702 PoweredClock::AlwaysEnabled => Sircsten::Enabled,
703 };
704 let pclk = if *fro_12m_enabled {
705 self.clocks.fro_12m = Some(Clock {
706 frequency: base_freq,
707 power: *power,
708 });
709 self.clocks.clk_1m = Some(Clock {
710 frequency: base_freq / 12,
711 power: *power,
712 });
713 SircClkPeriphEn::Enabled
714 } else {
715 SircClkPeriphEn::Disabled
716 };
717
718 // Set sleep/peripheral usage
719 self.scg0.sirccsr().modify(|_r, w| {
720 w.sircsten().variant(deep);
721 w.sirc_clk_periph_en().variant(pclk);
722 w
723 });
724
725 while self.scg0.sirccsr().read().sircvld().is_disabled_or_not_valid() {}
726 if self.scg0.sirccsr().read().sircerr().is_error_detected() {
727 return Err(ClockError::BadConfig {
728 clock: "sirc",
729 reason: "error set",
730 });
731 }
732
733 // reset lock
734 self.scg0.sirccsr().modify(|_r, w| w.lk().write_disabled());
735
736 // Do we enable the `fro_lf_div` output?
737 if let Some(d) = fro_lf_div.as_ref() {
738 // We need `fro_lf` to be enabled
739 if !*fro_12m_enabled {
740 return Err(ClockError::BadConfig {
741 clock: "fro_lf_div",
742 reason: "fro_12m not enabled",
743 });
744 }
745
746 // Halt and reset the div
747 self.syscon.frolfdiv().write(|w| {
748 w.halt().halt();
749 w.reset().asserted();
750 w
751 });
752 // Then change the div, unhalt it, and reset it
753 self.syscon.frolfdiv().write(|w| {
754 unsafe {
755 w.div().bits(d.into_bits());
756 }
757 w.halt().run();
758 w.reset().released();
759 w
760 });
761
762 // Wait for clock to stabilize
763 while self.syscon.frolfdiv().read().unstab().is_ongoing() {}
764
765 // Store off the clock info
766 self.clocks.fro_lf_div = Some(Clock {
767 frequency: base_freq / d.into_divisor(),
768 power: *power,
769 });
770 }
771
772 Ok(())
773 }
774
775 /// Configure the FRO16K/clk_16k clock family
776 fn configure_fro16k_clocks(&mut self) -> Result<(), ClockError> {
777 let Some(fro16k) = self.config.fro16k.as_ref() else {
778 return Ok(());
779 };
780 // Enable FRO16K oscillator
781 self.vbat0.froctla().modify(|_, w| w.fro_en().set_bit());
782
783 // Lock the control register
784 self.vbat0.frolcka().modify(|_, w| w.lock().set_bit());
785
786 let Fro16KConfig {
787 vsys_domain_active,
788 vdd_core_domain_active,
789 } = fro16k;
790
791 // Enable clock outputs to both VSYS and VDD_CORE domains
792 // Bit 0: clk_16k0 to VSYS domain
793 // Bit 1: clk_16k1 to VDD_CORE domain
794 //
795 // TODO: Define sub-fields for this register with a PAC patch?
796 let mut bits = 0;
797 if *vsys_domain_active {
798 bits |= 0b01;
799 self.clocks.clk_16k_vsys = Some(Clock {
800 frequency: 16_384,
801 power: PoweredClock::AlwaysEnabled,
802 });
803 }
804 if *vdd_core_domain_active {
805 bits |= 0b10;
806 self.clocks.clk_16k_vdd_core = Some(Clock {
807 frequency: 16_384,
808 power: PoweredClock::AlwaysEnabled,
809 });
810 }
811 self.vbat0.froclke().modify(|_r, w| unsafe { w.clke().bits(bits) });
812
813 Ok(())
814 }
815}
816
817//
818// Macros/macro impls
819//
820
821/// This macro is used to implement the [`Gate`] trait for a given peripheral
822/// that is controlled by the MRCC peripheral.
823macro_rules! impl_cc_gate {
824 ($name:ident, $clk_reg:ident, $rst_reg:ident, $field:ident, $config:ty) => {
825 impl Gate for crate::peripherals::$name {
826 type MrccPeriphConfig = $config;
827
828 #[inline]
829 unsafe fn enable_clock() {
830 let mrcc = unsafe { pac::Mrcc0::steal() };
831 mrcc.$clk_reg().modify(|_, w| w.$field().enabled());
832 }
833
834 #[inline]
835 unsafe fn disable_clock() {
836 let mrcc = unsafe { pac::Mrcc0::steal() };
837 mrcc.$clk_reg().modify(|_r, w| w.$field().disabled());
838 }
839
840 #[inline]
841 fn is_clock_enabled() -> bool {
842 let mrcc = unsafe { pac::Mrcc0::steal() };
843 mrcc.$clk_reg().read().$field().is_enabled()
844 }
845
846 #[inline]
847 unsafe fn release_reset() {
848 let mrcc = unsafe { pac::Mrcc0::steal() };
849 mrcc.$rst_reg().modify(|_, w| w.$field().enabled());
850 }
851
852 #[inline]
853 unsafe fn assert_reset() {
854 let mrcc = unsafe { pac::Mrcc0::steal() };
855 mrcc.$rst_reg().modify(|_, w| w.$field().disabled());
856 }
857
858 #[inline]
859 fn is_reset_released() -> bool {
860 let mrcc = unsafe { pac::Mrcc0::steal() };
861 mrcc.$rst_reg().read().$field().is_enabled()
862 }
863 }
864 };
865}
866
867/// This module contains implementations of MRCC APIs, specifically of the [`Gate`] trait,
868/// for various low level peripherals.
869pub(crate) mod gate {
870 use super::periph_helpers::{AdcConfig, LpuartConfig, NoConfig, OsTimerConfig};
871 use super::*;
872
873 // These peripherals have no additional upstream clocks or configuration required
874 // other than enabling through the MRCC gate. Currently, these peripherals will
875 // ALWAYS return `Ok(0)` when calling [`enable_and_reset()`] and/or
876 // [`SPConfHelper::post_enable_config()`].
877 impl_cc_gate!(PORT1, mrcc_glb_cc1, mrcc_glb_rst1, port1, NoConfig);
878 impl_cc_gate!(PORT2, mrcc_glb_cc1, mrcc_glb_rst1, port2, NoConfig);
879 impl_cc_gate!(PORT3, mrcc_glb_cc1, mrcc_glb_rst1, port3, NoConfig);
880 impl_cc_gate!(GPIO3, mrcc_glb_cc2, mrcc_glb_rst2, gpio3, NoConfig);
881
882 // These peripherals DO have meaningful configuration, and could fail if the system
883 // clocks do not match their needs.
884 impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig);
885 impl_cc_gate!(LPUART2, mrcc_glb_cc0, mrcc_glb_rst0, lpuart2, LpuartConfig);
886 impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig);
887}
diff --git a/src/clocks/periph_helpers.rs b/src/clocks/periph_helpers.rs
new file mode 100644
index 000000000..e5b234c5b
--- /dev/null
+++ b/src/clocks/periph_helpers.rs
@@ -0,0 +1,393 @@
1//! Peripheral Helpers
2//!
3//! The purpose of this module is to define the per-peripheral special handling
4//! required from a clocking perspective. Different peripherals have different
5//! selectable source clocks, and some peripherals have additional pre-dividers
6//! that can be used.
7//!
8//! See the docs of [`SPConfHelper`] for more details.
9
10use super::{ClockError, Clocks, PoweredClock};
11use crate::pac;
12
13/// Sealed Peripheral Configuration Helper
14///
15/// NOTE: the name "sealed" doesn't *totally* make sense because its not sealed yet in the
16/// embassy-mcxa project, but it derives from embassy-imxrt where it is. We should
17/// fix the name, or actually do the sealing of peripherals.
18///
19/// This trait serves to act as a per-peripheral customization for clocking behavior.
20///
21/// This trait should be implemented on a configuration type for a given peripheral, and
22/// provide the methods that will be called by the higher level operations like
23/// `embassy_mcxa::clocks::enable_and_reset()`.
24pub trait SPConfHelper {
25 /// This method is called AFTER a given MRCC peripheral has been enabled (e.g. un-gated),
26 /// but BEFORE the peripheral reset line is reset.
27 ///
28 /// This function should check that any relevant upstream clocks are enabled, are in a
29 /// reasonable power state, and that the requested configuration can be made. If any of
30 /// these checks fail, an `Err(ClockError)` should be returned, likely `ClockError::BadConfig`.
31 ///
32 /// This function SHOULD NOT make any changes to the system clock configuration, even
33 /// unsafely, as this should remain static for the duration of the program.
34 ///
35 /// This function WILL be called in a critical section, care should be taken not to delay
36 /// for an unreasonable amount of time.
37 ///
38 /// On success, this function MUST return an `Ok(freq)`, where `freq` is the frequency
39 /// fed into the peripheral, taking into account the selected source clock, as well as
40 /// any pre-divisors.
41 fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError>;
42}
43
44// config types
45
46/// This type represents a divider in the range 1..=16.
47///
48/// At a hardware level, this is an 8-bit register from 0..=15,
49/// which adds one.
50///
51/// While the *clock* domain seems to use 8-bit dividers, the *peripheral* domain
52/// seems to use 4 bit dividers!
53#[derive(Copy, Clone, Debug, PartialEq, Eq)]
54pub struct Div4(pub(super) u8);
55
56impl Div4 {
57 /// Divide by one, or no division
58 pub const fn no_div() -> Self {
59 Self(0)
60 }
61
62 /// Store a "raw" divisor value that will divide the source by
63 /// `(n + 1)`, e.g. `Div4::from_raw(0)` will divide the source
64 /// by 1, and `Div4::from_raw(15)` will divide the source by
65 /// 16.
66 pub const fn from_raw(n: u8) -> Option<Self> {
67 if n > 0b1111 {
68 None
69 } else {
70 Some(Self(n))
71 }
72 }
73
74 /// Store a specific divisor value that will divide the source
75 /// by `n`. e.g. `Div4::from_divisor(1)` will divide the source
76 /// by 1, and `Div4::from_divisor(16)` will divide the source
77 /// by 16.
78 ///
79 /// Will return `None` if `n` is not in the range `1..=16`.
80 /// Consider [`Self::from_raw`] for an infallible version.
81 pub const fn from_divisor(n: u8) -> Option<Self> {
82 let Some(n) = n.checked_sub(1) else {
83 return None;
84 };
85 if n > 0b1111 {
86 return None;
87 }
88 Some(Self(n))
89 }
90
91 /// Convert into "raw" bits form
92 #[inline(always)]
93 pub const fn into_bits(self) -> u8 {
94 self.0
95 }
96
97 /// Convert into "divisor" form, as a u32 for convenient frequency math
98 #[inline(always)]
99 pub const fn into_divisor(self) -> u32 {
100 self.0 as u32 + 1
101 }
102}
103
104/// A basic type that always returns an error when `post_enable_config` is called.
105///
106/// Should only be used as a placeholder.
107pub struct UnimplementedConfig;
108
109impl SPConfHelper for UnimplementedConfig {
110 fn post_enable_config(&self, _clocks: &Clocks) -> Result<u32, ClockError> {
111 Err(ClockError::UnimplementedConfig)
112 }
113}
114
115/// A basic type that always returns `Ok(0)` when `post_enable_config` is called.
116///
117/// This should only be used for peripherals that are "ambiently" clocked, like `PORTn`
118/// peripherals, which have no selectable/configurable source clock.
119pub struct NoConfig;
120impl SPConfHelper for NoConfig {
121 fn post_enable_config(&self, _clocks: &Clocks) -> Result<u32, ClockError> {
122 Ok(0)
123 }
124}
125
126//
127// LPUart
128//
129
130/// Selectable clocks for Lpuart peripherals
131#[derive(Debug, Clone, Copy)]
132pub enum LpuartClockSel {
133 /// FRO12M/FRO_LF/SIRC clock source, passed through divider
134 /// "fro_lf_div"
135 FroLfDiv,
136 /// FRO180M/FRO_HF/FIRC clock source, passed through divider
137 /// "fro_hf_div"
138 FroHfDiv,
139 /// SOSC/XTAL/EXTAL clock source
140 ClkIn,
141 /// FRO16K/clk_16k source
142 Clk16K,
143 /// clk_1m/FRO_LF divided by 12
144 Clk1M,
145 /// Output of PLL1, passed through clock divider,
146 /// "pll1_clk_div", maybe "pll1_lf_div"?
147 Pll1ClkDiv,
148 /// Disabled
149 None,
150}
151
152/// Which instance of the Lpuart is this?
153///
154/// Should not be directly selectable by end-users.
155#[derive(Copy, Clone, Debug, PartialEq, Eq)]
156pub enum LpuartInstance {
157 /// Instance 0
158 Lpuart0,
159 /// Instance 1
160 Lpuart1,
161 /// Instance 2
162 Lpuart2,
163 /// Instance 3
164 Lpuart3,
165 /// Instance 4
166 Lpuart4,
167 /// Instance 5
168 Lpuart5,
169}
170
171/// Top level configuration for `Lpuart` instances.
172pub struct LpuartConfig {
173 /// Power state required for this peripheral
174 pub power: PoweredClock,
175 /// Clock source
176 pub source: LpuartClockSel,
177 /// Clock divisor
178 pub div: Div4,
179 /// Which instance is this?
180 // NOTE: should not be user settable
181 pub(crate) instance: LpuartInstance,
182}
183
184impl SPConfHelper for LpuartConfig {
185 fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> {
186 // check that source is suitable
187 let mrcc0 = unsafe { pac::Mrcc0::steal() };
188 use mcxa_pac::mrcc0::mrcc_lpuart0_clksel::Mux;
189
190 let (clkdiv, clksel) = match self.instance {
191 LpuartInstance::Lpuart0 => (mrcc0.mrcc_lpuart0_clkdiv(), mrcc0.mrcc_lpuart0_clksel()),
192 LpuartInstance::Lpuart1 => (mrcc0.mrcc_lpuart1_clkdiv(), mrcc0.mrcc_lpuart1_clksel()),
193 LpuartInstance::Lpuart2 => (mrcc0.mrcc_lpuart2_clkdiv(), mrcc0.mrcc_lpuart2_clksel()),
194 LpuartInstance::Lpuart3 => (mrcc0.mrcc_lpuart3_clkdiv(), mrcc0.mrcc_lpuart3_clksel()),
195 LpuartInstance::Lpuart4 => (mrcc0.mrcc_lpuart4_clkdiv(), mrcc0.mrcc_lpuart4_clksel()),
196 LpuartInstance::Lpuart5 => (mrcc0.mrcc_lpuart5_clkdiv(), mrcc0.mrcc_lpuart5_clksel()),
197 };
198
199 let (freq, variant) = match self.source {
200 LpuartClockSel::FroLfDiv => {
201 let freq = clocks.ensure_fro_lf_div_active(&self.power)?;
202 (freq, Mux::ClkrootFunc0)
203 }
204 LpuartClockSel::FroHfDiv => {
205 let freq = clocks.ensure_fro_hf_div_active(&self.power)?;
206 (freq, Mux::ClkrootFunc2)
207 }
208 LpuartClockSel::ClkIn => {
209 let freq = clocks.ensure_clk_in_active(&self.power)?;
210 (freq, Mux::ClkrootFunc3)
211 }
212 LpuartClockSel::Clk16K => {
213 let freq = clocks.ensure_clk_16k_vdd_core_active(&self.power)?;
214 (freq, Mux::ClkrootFunc4)
215 }
216 LpuartClockSel::Clk1M => {
217 let freq = clocks.ensure_clk_1m_active(&self.power)?;
218 (freq, Mux::ClkrootFunc5)
219 }
220 LpuartClockSel::Pll1ClkDiv => {
221 let freq = clocks.ensure_pll1_clk_div_active(&self.power)?;
222 (freq, Mux::ClkrootFunc6)
223 }
224 LpuartClockSel::None => unsafe {
225 // no ClkrootFunc7, just write manually for now
226 clksel.write(|w| w.bits(0b111));
227 clkdiv.modify(|_r, w| {
228 w.reset().on();
229 w.halt().on();
230 w
231 });
232 return Ok(0);
233 },
234 };
235
236 // set clksel
237 clksel.modify(|_r, w| w.mux().variant(variant));
238
239 // Set up clkdiv
240 clkdiv.modify(|_r, w| {
241 w.halt().on();
242 w.reset().on();
243 w
244 });
245 clkdiv.modify(|_r, w| {
246 w.halt().off();
247 w.reset().off();
248 unsafe { w.div().bits(self.div.into_bits()) };
249 w
250 });
251
252 while clkdiv.read().unstab().is_on() {}
253
254 Ok(freq / self.div.into_divisor())
255 }
256}
257
258//
259// OSTimer
260//
261
262/// Selectable clocks for the OSTimer peripheral
263#[derive(Copy, Clone, Debug, PartialEq, Eq)]
264pub enum OstimerClockSel {
265 /// 16k clock, sourced from FRO16K (Vdd Core)
266 Clk16kVddCore,
267 /// 1 MHz Clock sourced from FRO12M
268 Clk1M,
269 /// Disabled
270 None,
271}
272
273/// Top level configuration for the `OSTimer` peripheral
274pub struct OsTimerConfig {
275 /// Power state required for this peripheral
276 pub power: PoweredClock,
277 /// Selected clock source for this peripheral
278 pub source: OstimerClockSel,
279}
280
281impl SPConfHelper for OsTimerConfig {
282 fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> {
283 let mrcc0 = unsafe { pac::Mrcc0::steal() };
284 Ok(match self.source {
285 OstimerClockSel::Clk16kVddCore => {
286 let freq = clocks.ensure_clk_16k_vdd_core_active(&self.power)?;
287 mrcc0.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_16k());
288 freq
289 }
290 OstimerClockSel::Clk1M => {
291 let freq = clocks.ensure_clk_1m_active(&self.power)?;
292 mrcc0.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_1m());
293 freq
294 }
295 OstimerClockSel::None => {
296 mrcc0.mrcc_ostimer0_clksel().write(|w| unsafe { w.mux().bits(0b11) });
297 0
298 }
299 })
300 }
301}
302
303//
304// Adc
305//
306
307/// Selectable clocks for the ADC peripheral
308#[derive(Copy, Clone, Debug, PartialEq, Eq)]
309pub enum AdcClockSel {
310 /// Divided `fro_lf`/`clk_12m`/FRO12M source
311 FroLfDiv,
312 /// Gated `fro_hf`/`FRO180M` source
313 FroHf,
314 /// External Clock Source
315 ClkIn,
316 /// 1MHz clock sourced by a divided `fro_lf`/`clk_12m`
317 Clk1M,
318 /// Internal PLL output, with configurable divisor
319 Pll1ClkDiv,
320 /// No clock/disabled
321 None,
322}
323
324/// Top level configuration for the ADC peripheral
325pub struct AdcConfig {
326 /// Power state required for this peripheral
327 pub power: PoweredClock,
328 /// Selected clock-source for this peripheral
329 pub source: AdcClockSel,
330 /// Pre-divisor, applied to the upstream clock output
331 pub div: Div4,
332}
333
334impl SPConfHelper for AdcConfig {
335 fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> {
336 use mcxa_pac::mrcc0::mrcc_adc_clksel::Mux;
337 let mrcc0 = unsafe { pac::Mrcc0::steal() };
338 let (freq, variant) = match self.source {
339 AdcClockSel::FroLfDiv => {
340 let freq = clocks.ensure_fro_lf_div_active(&self.power)?;
341 (freq, Mux::ClkrootFunc0)
342 }
343 AdcClockSel::FroHf => {
344 let freq = clocks.ensure_fro_hf_active(&self.power)?;
345 (freq, Mux::ClkrootFunc1)
346 }
347 AdcClockSel::ClkIn => {
348 let freq = clocks.ensure_clk_in_active(&self.power)?;
349 (freq, Mux::ClkrootFunc3)
350 }
351 AdcClockSel::Clk1M => {
352 let freq = clocks.ensure_clk_1m_active(&self.power)?;
353 (freq, Mux::ClkrootFunc5)
354 }
355 AdcClockSel::Pll1ClkDiv => {
356 let freq = clocks.ensure_pll1_clk_div_active(&self.power)?;
357 (freq, Mux::ClkrootFunc6)
358 }
359 AdcClockSel::None => {
360 mrcc0.mrcc_adc_clksel().write(|w| unsafe {
361 // no ClkrootFunc7, just write manually for now
362 w.mux().bits(0b111)
363 });
364 mrcc0.mrcc_adc_clkdiv().modify(|_r, w| {
365 w.reset().on();
366 w.halt().on();
367 w
368 });
369 return Ok(0);
370 }
371 };
372
373 // set clksel
374 mrcc0.mrcc_adc_clksel().modify(|_r, w| w.mux().variant(variant));
375
376 // Set up clkdiv
377 mrcc0.mrcc_adc_clkdiv().modify(|_r, w| {
378 w.halt().on();
379 w.reset().on();
380 w
381 });
382 mrcc0.mrcc_adc_clkdiv().modify(|_r, w| {
383 w.halt().off();
384 w.reset().off();
385 unsafe { w.div().bits(self.div.into_bits()) };
386 w
387 });
388
389 while mrcc0.mrcc_adc_clkdiv().read().unstab().is_on() {}
390
391 Ok(freq / self.div.into_divisor())
392 }
393}
diff --git a/src/config.rs b/src/config.rs
index 93aed5a99..0939c11f1 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,5 +1,6 @@
1// HAL configuration (minimal), mirroring embassy-imxrt style 1// HAL configuration (minimal), mirroring embassy-imxrt style
2 2
3use crate::clocks::config::ClocksConfig;
3use crate::interrupt::Priority; 4use crate::interrupt::Priority;
4 5
5#[non_exhaustive] 6#[non_exhaustive]
@@ -7,6 +8,7 @@ pub struct Config {
7 pub time_interrupt_priority: Priority, 8 pub time_interrupt_priority: Priority,
8 pub rtc_interrupt_priority: Priority, 9 pub rtc_interrupt_priority: Priority,
9 pub adc_interrupt_priority: Priority, 10 pub adc_interrupt_priority: Priority,
11 pub clock_cfg: ClocksConfig,
10} 12}
11 13
12impl Default for Config { 14impl Default for Config {
@@ -15,6 +17,7 @@ impl Default for Config {
15 time_interrupt_priority: Priority::from(0), 17 time_interrupt_priority: Priority::from(0),
16 rtc_interrupt_priority: Priority::from(0), 18 rtc_interrupt_priority: Priority::from(0),
17 adc_interrupt_priority: Priority::from(0), 19 adc_interrupt_priority: Priority::from(0),
20 clock_cfg: ClocksConfig::default(),
18 } 21 }
19 } 22 }
20} 23}
diff --git a/src/lib.rs b/src/lib.rs
index 4e5ac0109..86c0dc45b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,7 +6,6 @@
6pub mod clocks; // still provide clock helpers 6pub mod clocks; // still provide clock helpers
7pub mod gpio; 7pub mod gpio;
8pub mod pins; // pin mux helpers 8pub mod pins; // pin mux helpers
9pub mod reset; // reset control helpers
10 9
11pub mod adc; 10pub mod adc;
12pub mod config; 11pub mod config;
@@ -14,9 +13,8 @@ pub mod interrupt;
14pub mod lpuart; 13pub mod lpuart;
15pub mod ostimer; 14pub mod ostimer;
16pub mod rtc; 15pub mod rtc;
17pub mod uart;
18 16
19embassy_hal_internal::peripherals!(LPUART2, OSTIMER0, GPIO, RTC0, ADC1,); 17embassy_hal_internal::peripherals!(PORT1, PORT2, PORT3, LPUART2, OSTIMER0, GPIO, PIO2_2, PIO2_3, GPIO3, RTC0, ADC1,);
20 18
21/// Get access to the PAC Peripherals for low-level register access. 19/// Get access to the PAC Peripherals for low-level register access.
22/// This is a lazy-initialized singleton that can be called after init(). 20/// This is a lazy-initialized singleton that can be called after init().
@@ -46,11 +44,9 @@ pub use mcxa_pac as pac;
46pub(crate) use mcxa_pac as pac; 44pub(crate) use mcxa_pac as pac;
47pub use ostimer::Ostimer0 as Ostimer0Token; 45pub use ostimer::Ostimer0 as Ostimer0Token;
48pub use rtc::Rtc0 as Rtc0Token; 46pub use rtc::Rtc0 as Rtc0Token;
49pub use uart::Lpuart2 as Uart2Token;
50 47
51/// 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.
52/// 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).
53#[allow(unused_variables)]
54pub fn init(cfg: crate::config::Config) -> Peripherals { 50pub fn init(cfg: crate::config::Config) -> Peripherals {
55 let peripherals = Peripherals::take(); 51 let peripherals = Peripherals::take();
56 // Apply user-configured priority early; enabling is left to examples/apps 52 // Apply user-configured priority early; enabling is left to examples/apps
@@ -59,6 +55,10 @@ pub fn init(cfg: crate::config::Config) -> Peripherals {
59 crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); 55 crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority);
60 // Apply user-configured priority early; enabling is left to examples/apps 56 // Apply user-configured priority early; enabling is left to examples/apps
61 crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority); 57 crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority);
58
59 // Configure clocks
60 crate::clocks::init(cfg.clock_cfg).unwrap();
61
62 peripherals 62 peripherals
63} 63}
64 64
diff --git a/src/lpuart/buffered.rs b/src/lpuart/buffered.rs
index a617c10a5..7b575c086 100644
--- a/src/lpuart/buffered.rs
+++ b/src/lpuart/buffered.rs
@@ -212,10 +212,19 @@ impl<'a> BufferedLpuart<'a> {
212 config.enable_tx = true; 212 config.enable_tx = true;
213 config.enable_rx = true; 213 config.enable_rx = true;
214 214
215 // Enable clocks
216 let conf = LpuartConfig {
217 power: config.power,
218 source: config.source,
219 div: config.div,
220 instance: T::CLOCK_INSTANCE,
221 };
222 let clock_freq = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? };
223
215 // Perform standard initialization 224 // Perform standard initialization
216 perform_software_reset(regs); 225 perform_software_reset(regs);
217 disable_transceiver(regs); 226 disable_transceiver(regs);
218 configure_baudrate(regs, config.baudrate_bps, config.clock)?; 227 configure_baudrate(regs, config.baudrate_bps, clock_freq)?;
219 configure_frame_format(regs, &config); 228 configure_frame_format(regs, &config);
220 configure_control_settings(regs, &config); 229 configure_control_settings(regs, &config);
221 configure_fifo(regs, &config); 230 configure_fifo(regs, &config);
diff --git a/src/lpuart/mod.rs b/src/lpuart/mod.rs
index 35b531421..b3d7c4885 100644
--- a/src/lpuart/mod.rs
+++ b/src/lpuart/mod.rs
@@ -3,6 +3,8 @@ use core::marker::PhantomData;
3use embassy_hal_internal::{Peri, PeripheralType}; 3use embassy_hal_internal::{Peri, PeripheralType};
4use paste::paste; 4use paste::paste;
5 5
6use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig};
7use crate::clocks::{enable_and_reset, ClockError, Gate, PoweredClock};
6use crate::pac::lpuart0::baud::Sbns as StopBits; 8use crate::pac::lpuart0::baud::Sbns as StopBits;
7use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits}; 9use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits};
8use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; 10use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource};
@@ -18,71 +20,6 @@ pub mod buffered;
18// Stub implementation for LIB (Peripherals), GPIO, DMA and CLOCK until stable API 20// Stub implementation for LIB (Peripherals), GPIO, DMA and CLOCK until stable API
19// Pin and Clock initialization is currently done at the examples level. 21// Pin and Clock initialization is currently done at the examples level.
20 22
21// --- START LIB ---
22
23// Use our own instance of Peripherals, until we align `lib.rs` with the EMBASSY-IMXRT approach
24// Inlined peripherals_definition! to bypass the `Peripherals::take_with_cs()` check
25// SHOULD NOT BE USED IN THE FINAL VERSION
26pub mod lib {
27 // embassy_hal_internal::peripherals!(LPUART2, PIO2_2, PIO2_3)
28
29 embassy_hal_internal::peripherals_definition!(LPUART2, PIO2_2, PIO2_3,);
30 #[doc = r" Struct containing all the peripheral singletons."]
31 #[doc = r""]
32 #[doc = r" To obtain the peripherals, you must initialize the HAL, by calling [`crate::init`]."]
33 #[allow(non_snake_case)]
34 pub struct Peripherals {
35 #[doc = concat!(stringify!(LPUART2)," peripheral")]
36 pub LPUART2: embassy_hal_internal::Peri<'static, peripherals::LPUART2>,
37 #[doc = concat!(stringify!(PIO2_2)," peripheral")]
38 pub PIO2_2: embassy_hal_internal::Peri<'static, peripherals::PIO2_2>,
39 #[doc = concat!(stringify!(PIO2_3)," peripheral")]
40 pub PIO2_3: embassy_hal_internal::Peri<'static, peripherals::PIO2_3>,
41 }
42 impl Peripherals {
43 #[doc = r"Returns all the peripherals *once*"]
44 #[inline]
45 pub(crate) fn take() -> Self {
46 critical_section::with(Self::take_with_cs)
47 }
48 #[doc = r"Returns all the peripherals *once*"]
49 #[inline]
50 pub(crate) fn take_with_cs(_cs: critical_section::CriticalSection) -> Self {
51 #[no_mangle]
52 static mut _EMBASSY_DEVICE_PERIPHERALS2: bool = false; // ALIGN: Temporary fix to use stub Peripherals
53 unsafe {
54 if _EMBASSY_DEVICE_PERIPHERALS2 {
55 panic!("init called more than once!")
56 }
57 _EMBASSY_DEVICE_PERIPHERALS2 = true;
58 Self::steal()
59 }
60 }
61 }
62 impl Peripherals {
63 #[doc = r" Unsafely create an instance of this peripheral out of thin air."]
64 #[doc = r""]
65 #[doc = r" # Safety"]
66 #[doc = r""]
67 #[doc = r" You must ensure that you're only using one instance of this type at a time."]
68 #[inline]
69 pub unsafe fn steal() -> Self {
70 Self {
71 LPUART2: peripherals::LPUART2::steal(),
72 PIO2_2: peripherals::PIO2_2::steal(),
73 PIO2_3: peripherals::PIO2_3::steal(),
74 }
75 }
76 }
77
78 /// Initialize HAL
79 pub fn init() -> Peripherals {
80 Peripherals::take()
81 }
82}
83
84// --- END LIB ---
85
86// --- START GPIO --- 23// --- START GPIO ---
87 24
88mod gpio { 25mod gpio {
@@ -101,13 +38,13 @@ mod gpio {
101 macro_rules! impl_gpio_pin { 38 macro_rules! impl_gpio_pin {
102 ($($pin:ident),*) => { 39 ($($pin:ident),*) => {
103 $( 40 $(
104 impl SealedPin for super::lib::peripherals::$pin {} 41 impl SealedPin for crate::peripherals::$pin {}
105 42
106 impl GpioPin for super::lib::peripherals::$pin {} 43 impl GpioPin for crate::peripherals::$pin {}
107 44
108 impl From<super::lib::peripherals::$pin> for AnyPin { 45 impl From<crate::peripherals::$pin> for AnyPin {
109 // TODO: AJM: any reason we aren't using $pin? 46 // TODO: AJM: any reason we aren't using $pin?
110 fn from(_val: super::lib::peripherals::$pin) -> Self { 47 fn from(_val: crate::peripherals::$pin) -> Self {
111 AnyPin 48 AnyPin
112 } 49 }
113 } 50 }
@@ -143,18 +80,6 @@ use dma::Channel;
143 80
144// --- END DMA --- 81// --- END DMA ---
145 82
146// --- START CLOCK ---
147mod clock {
148 #[derive(Debug, Clone, Copy)]
149 pub enum Clock {
150 FroLf, // Low-Frequency Free-Running Oscillator
151 }
152}
153
154use clock::Clock;
155
156// --- END CLOCK ---
157
158// ============================================================================ 83// ============================================================================
159// MISC 84// MISC
160// ============================================================================ 85// ============================================================================
@@ -182,7 +107,8 @@ pub struct Info {
182 107
183/// Trait for LPUART peripheral instances 108/// Trait for LPUART peripheral instances
184#[allow(private_bounds)] 109#[allow(private_bounds)]
185pub trait Instance: SealedInstance + PeripheralType + 'static + Send { 110pub trait Instance: SealedInstance + PeripheralType + 'static + Send + Gate<MrccPeriphConfig = LpuartConfig> {
111 const CLOCK_INSTANCE: crate::clocks::periph_helpers::LpuartInstance;
186 type Interrupt: interrupt::typelevel::Interrupt; 112 type Interrupt: interrupt::typelevel::Interrupt;
187} 113}
188 114
@@ -190,7 +116,7 @@ macro_rules! impl_instance {
190 ($($n:expr),*) => { 116 ($($n:expr),*) => {
191 $( 117 $(
192 paste!{ 118 paste!{
193 impl SealedInstance for lib::peripherals::[<LPUART $n>] { 119 impl SealedInstance for crate::peripherals::[<LPUART $n>] {
194 fn info() -> Info { 120 fn info() -> Info {
195 Info { 121 Info {
196 regs: unsafe { &*pac::[<Lpuart $n>]::ptr() }, 122 regs: unsafe { &*pac::[<Lpuart $n>]::ptr() },
@@ -208,7 +134,9 @@ macro_rules! impl_instance {
208 } 134 }
209 } 135 }
210 136
211 impl Instance for lib::peripherals::[<LPUART $n>] { 137 impl Instance for crate::peripherals::[<LPUART $n>] {
138 const CLOCK_INSTANCE: crate::clocks::periph_helpers::LpuartInstance
139 = crate::clocks::periph_helpers::LpuartInstance::[<Lpuart $n>];
212 type Interrupt = crate::interrupt::typelevel::[<LPUART $n>]; 140 type Interrupt = crate::interrupt::typelevel::[<LPUART $n>];
213 } 141 }
214 } 142 }
@@ -236,8 +164,7 @@ pub fn disable_transceiver(regs: Regs) {
236} 164}
237 165
238/// Calculate and configure baudrate settings 166/// Calculate and configure baudrate settings
239pub fn configure_baudrate(regs: Regs, baudrate_bps: u32, clock: Clock) -> Result<()> { 167pub fn configure_baudrate(regs: Regs, baudrate_bps: u32, clock_freq: u32) -> Result<()> {
240 let clock_freq = get_fc_freq(clock)?;
241 let (osr, sbr) = calculate_baudrate(baudrate_bps, clock_freq)?; 168 let (osr, sbr) = calculate_baudrate(baudrate_bps, clock_freq)?;
242 169
243 // Configure BAUD register 170 // Configure BAUD register
@@ -408,16 +335,6 @@ pub fn calculate_baudrate(baudrate: u32, src_clock_hz: u32) -> Result<(u8, u16)>
408 Ok((osr, sbr)) 335 Ok((osr, sbr))
409} 336}
410 337
411pub fn get_fc_freq(clock: Clock) -> Result<u32> {
412 // This is a placeholder - actual implementation would query the clock system
413 // In real implementation, this would get the LPUART clock frequency
414 match clock {
415 Clock::FroLf => Ok(12_000_000), // Low frequency oscillator
416 #[allow(unreachable_patterns)]
417 _ => Err(Error::InvalidArgument),
418 }
419}
420
421/// Wait for all transmit operations to complete 338/// Wait for all transmit operations to complete
422pub fn wait_for_tx_complete(regs: Regs) { 339pub fn wait_for_tx_complete(regs: Regs) {
423 // Wait for TX FIFO to empty 340 // Wait for TX FIFO to empty
@@ -504,7 +421,7 @@ macro_rules! impl_pin_trait {
504 ($fcn:ident, $mode:ident, $($pin:ident, $alt:ident),*) => { 421 ($fcn:ident, $mode:ident, $($pin:ident, $alt:ident),*) => {
505 paste! { 422 paste! {
506 $( 423 $(
507 impl [<$mode:camel Pin>]<lib::peripherals::$fcn> for lib::peripherals::$pin { 424 impl [<$mode:camel Pin>]<crate::peripherals::$fcn> for crate::peripherals::$pin {
508 fn [<as_ $mode>](&self) { 425 fn [<as_ $mode>](&self) {
509 let _alt = gpio::Alt::$alt; 426 let _alt = gpio::Alt::$alt;
510 // todo!("Configure pin for LPUART function") 427 // todo!("Configure pin for LPUART function")
@@ -553,6 +470,8 @@ pub enum Error {
553 TxFifoFull, 470 TxFifoFull,
554 /// TX Busy 471 /// TX Busy
555 TxBusy, 472 TxBusy,
473 /// Clock Error
474 ClockSetup(ClockError),
556} 475}
557 476
558/// A specialized Result type for LPUART operations 477/// A specialized Result type for LPUART operations
@@ -565,10 +484,14 @@ pub type Result<T> = core::result::Result<T, Error>;
565/// Lpuart config 484/// Lpuart config
566#[derive(Debug, Clone, Copy)] 485#[derive(Debug, Clone, Copy)]
567pub struct Config { 486pub struct Config {
487 /// Power state required for this peripheral
488 pub power: PoweredClock,
489 /// Clock source
490 pub source: LpuartClockSel,
491 /// Clock divisor
492 pub div: Div4,
568 /// Baud rate in bits per second 493 /// Baud rate in bits per second
569 pub baudrate_bps: u32, 494 pub baudrate_bps: u32,
570 /// Clock
571 pub clock: Clock,
572 /// Parity configuration 495 /// Parity configuration
573 pub parity_mode: Option<Parity>, 496 pub parity_mode: Option<Parity>,
574 /// Number of data bits 497 /// Number of data bits
@@ -605,7 +528,6 @@ impl Default for Config {
605 fn default() -> Self { 528 fn default() -> Self {
606 Self { 529 Self {
607 baudrate_bps: 115_200u32, 530 baudrate_bps: 115_200u32,
608 clock: Clock::FroLf,
609 parity_mode: None, 531 parity_mode: None,
610 data_bits_count: DataBits::Data8, 532 data_bits_count: DataBits::Data8,
611 msb_firs: MsbFirst::LsbFirst, 533 msb_firs: MsbFirst::LsbFirst,
@@ -621,6 +543,9 @@ impl Default for Config {
621 enable_tx: false, 543 enable_tx: false,
622 enable_rx: false, 544 enable_rx: false,
623 swap_txd_rxd: false, 545 swap_txd_rxd: false,
546 power: PoweredClock::NormalEnabledDeepSleepDisabled,
547 source: LpuartClockSel::FroLfDiv,
548 div: Div4::no_div(),
624 } 549 }
625 } 550 }
626} 551}
@@ -706,10 +631,19 @@ impl<'a, M: Mode> Lpuart<'a, M> {
706 ) -> Result<()> { 631 ) -> Result<()> {
707 let regs = T::info().regs; 632 let regs = T::info().regs;
708 633
634 // Enable clocks
635 let conf = LpuartConfig {
636 power: config.power,
637 source: config.source,
638 div: config.div,
639 instance: T::CLOCK_INSTANCE,
640 };
641 let clock_freq = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? };
642
709 // Perform initialization sequence 643 // Perform initialization sequence
710 perform_software_reset(regs); 644 perform_software_reset(regs);
711 disable_transceiver(regs); 645 disable_transceiver(regs);
712 configure_baudrate(regs, config.baudrate_bps, config.clock)?; 646 configure_baudrate(regs, config.baudrate_bps, clock_freq)?;
713 configure_frame_format(regs, &config); 647 configure_frame_format(regs, &config);
714 configure_control_settings(regs, &config); 648 configure_control_settings(regs, &config);
715 configure_fifo(regs, &config); 649 configure_fifo(regs, &config);
@@ -838,6 +772,10 @@ impl<'a> LpuartTx<'a, Blocking> {
838 Ok(()) 772 Ok(())
839 } 773 }
840 774
775 pub fn write_str_blocking(&mut self, buf: &str) {
776 let _ = self.blocking_write(buf.as_bytes());
777 }
778
841 /// Write data to LPUART TX without blocking. 779 /// Write data to LPUART TX without blocking.
842 pub fn write(&mut self, buf: &[u8]) -> Result<()> { 780 pub fn write(&mut self, buf: &[u8]) -> Result<()> {
843 for x in buf { 781 for x in buf {
@@ -967,6 +905,22 @@ impl<'a> Lpuart<'a, Blocking> {
967 self.tx.blocking_write(buf) 905 self.tx.blocking_write(buf)
968 } 906 }
969 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
970 /// Write data to LPUART TX without blocking 924 /// Write data to LPUART TX without blocking
971 pub fn write(&mut self, buf: &[u8]) -> Result<()> { 925 pub fn write(&mut self, buf: &[u8]) -> Result<()> {
972 self.tx.write(buf) 926 self.tx.write(buf)
diff --git a/src/ostimer.rs b/src/ostimer.rs
index 8bc68389a..cd5451b53 100644
--- a/src/ostimer.rs
+++ b/src/ostimer.rs
@@ -29,8 +29,13 @@
29 29
30use core::sync::atomic::{AtomicBool, Ordering}; 30use core::sync::atomic::{AtomicBool, Ordering};
31 31
32use embassy_hal_internal::{Peri, PeripheralType};
33
34use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel};
35use crate::clocks::{assert_reset, enable_and_reset, is_reset_released, release_reset, Gate, PoweredClock};
32use crate::interrupt::InterruptExt; 36use crate::interrupt::InterruptExt;
33use crate::pac; 37use crate::pac;
38use crate::peripherals::OSTIMER0;
34 39
35// PAC defines the shared RegisterBlock under `ostimer0`. 40// PAC defines the shared RegisterBlock under `ostimer0`.
36type Regs = pac::ostimer0::RegisterBlock; 41type Regs = pac::ostimer0::RegisterBlock;
@@ -197,16 +202,16 @@ impl<'d> Alarm<'d> {
197pub struct Config { 202pub struct Config {
198 /// Initialize MATCH registers to their max values and mask/clear the interrupt flag. 203 /// Initialize MATCH registers to their max values and mask/clear the interrupt flag.
199 pub init_match_max: bool, 204 pub init_match_max: bool,
200 /// OSTIMER clock frequency in Hz (must match the actual hardware clock) 205 pub power: PoweredClock,
201 pub clock_frequency_hz: u64, 206 pub source: OstimerClockSel,
202} 207}
203 208
204impl Default for Config { 209impl Default for Config {
205 fn default() -> Self { 210 fn default() -> Self {
206 Self { 211 Self {
207 init_match_max: true, 212 init_match_max: true,
208 // Default to 1MHz - user should override this with actual frequency 213 power: PoweredClock::NormalEnabledDeepSleepDisabled,
209 clock_frequency_hz: 1_000_000, 214 source: OstimerClockSel::Clk1M,
210 } 215 }
211 } 216 }
212} 217}
@@ -222,8 +227,16 @@ impl<'d, I: Instance> Ostimer<'d, I> {
222 /// Construct OSTIMER handle. 227 /// Construct OSTIMER handle.
223 /// Requires clocks for the instance to be enabled by the board before calling. 228 /// Requires clocks for the instance to be enabled by the board before calling.
224 /// Does not enable NVIC or INTENA; use time_driver::init() for async operation. 229 /// Does not enable NVIC or INTENA; use time_driver::init() for async operation.
225 pub fn new(_inst: impl Instance, cfg: Config, _p: &'d crate::pac::Peripherals) -> Self { 230 pub fn new(_inst: Peri<'d, I>, cfg: Config) -> Self {
226 assert!(cfg.clock_frequency_hz > 0, "OSTIMER frequency must be greater than 0"); 231 let clock_freq = unsafe {
232 enable_and_reset::<I>(&OsTimerConfig {
233 power: cfg.power,
234 source: cfg.source,
235 })
236 .expect("Enabling OsTimer clock should not fail")
237 };
238
239 assert!(clock_freq > 0, "OSTIMER frequency must be greater than 0");
227 240
228 if cfg.init_match_max { 241 if cfg.init_match_max {
229 let r: &Regs = unsafe { &*I::ptr() }; 242 let r: &Regs = unsafe { &*I::ptr() };
@@ -233,7 +246,7 @@ impl<'d, I: Instance> Ostimer<'d, I> {
233 246
234 Self { 247 Self {
235 _inst: core::marker::PhantomData, 248 _inst: core::marker::PhantomData,
236 clock_frequency_hz: cfg.clock_frequency_hz, 249 clock_frequency_hz: clock_freq as u64,
237 _phantom: core::marker::PhantomData, 250 _phantom: core::marker::PhantomData,
238 } 251 }
239 } 252 }
@@ -260,7 +273,7 @@ impl<'d, I: Instance> Ostimer<'d, I> {
260 /// # Safety 273 /// # Safety
261 /// This operation will reset the entire OSTIMER peripheral. Any active alarms 274 /// This operation will reset the entire OSTIMER peripheral. Any active alarms
262 /// or time_driver operations will be disrupted. Use with caution. 275 /// or time_driver operations will be disrupted. Use with caution.
263 pub fn reset(&self, peripherals: &crate::pac::Peripherals) { 276 pub fn reset(&self, _peripherals: &crate::pac::Peripherals) {
264 critical_section::with(|_| { 277 critical_section::with(|_| {
265 let r: &Regs = unsafe { &*I::ptr() }; 278 let r: &Regs = unsafe { &*I::ptr() };
266 279
@@ -270,19 +283,17 @@ impl<'d, I: Instance> Ostimer<'d, I> {
270 .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); 283 .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit());
271 284
272 unsafe { 285 unsafe {
273 crate::reset::assert::<crate::reset::line::Ostimer0>(peripherals); 286 assert_reset::<OSTIMER0>();
274 }
275 287
276 for _ in 0..RESET_STABILIZE_SPINS { 288 for _ in 0..RESET_STABILIZE_SPINS {
277 cortex_m::asm::nop(); 289 cortex_m::asm::nop();
278 } 290 }
279 291
280 unsafe { 292 release_reset::<OSTIMER0>();
281 crate::reset::release::<crate::reset::line::Ostimer0>(peripherals);
282 }
283 293
284 while !<crate::reset::line::Ostimer0 as crate::reset::ResetLine>::is_released(&peripherals.mrcc0) { 294 while !is_reset_released::<OSTIMER0>() {
285 cortex_m::asm::nop(); 295 cortex_m::asm::nop();
296 }
286 } 297 }
287 298
288 for _ in 0..RESET_STABILIZE_SPINS { 299 for _ in 0..RESET_STABILIZE_SPINS {
@@ -469,14 +480,13 @@ fn now_ticks_read() -> u64 {
469 // Read high then low to minimize incoherent snapshots 480 // Read high then low to minimize incoherent snapshots
470 let hi = (r.evtimerh().read().evtimer_count_value().bits() as u64) & (EVTIMER_HI_MASK as u64); 481 let hi = (r.evtimerh().read().evtimer_count_value().bits() as u64) & (EVTIMER_HI_MASK as u64);
471 let lo = r.evtimerl().read().evtimer_count_value().bits() as u64; 482 let lo = r.evtimerl().read().evtimer_count_value().bits() as u64;
472
473 // Combine and convert from Gray code to binary 483 // Combine and convert from Gray code to binary
474 let gray = lo | (hi << EVTIMER_HI_SHIFT); 484 let gray = lo | (hi << EVTIMER_HI_SHIFT);
475 gray_to_bin(gray) 485 gray_to_bin(gray)
476} 486}
477 487
478// Instance trait like other drivers, providing a PAC pointer for this OSTIMER instance 488// Instance trait like other drivers, providing a PAC pointer for this OSTIMER instance
479pub trait Instance { 489pub trait Instance: Gate<MrccPeriphConfig = OsTimerConfig> + PeripheralType {
480 fn ptr() -> *const Regs; 490 fn ptr() -> *const Regs;
481} 491}
482 492
@@ -491,12 +501,12 @@ impl Instance for crate::peripherals::OSTIMER0 {
491} 501}
492 502
493// Also implement Instance for the Peri wrapper type 503// Also implement Instance for the Peri wrapper type
494impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::OSTIMER0> { 504// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::OSTIMER0> {
495 #[inline(always)] 505// #[inline(always)]
496 fn ptr() -> *const Regs { 506// fn ptr() -> *const Regs {
497 pac::Ostimer0::ptr() 507// pac::Ostimer0::ptr()
498 } 508// }
499} 509// }
500 510
501#[inline(always)] 511#[inline(always)]
502fn bin_to_gray(x: u64) -> u64 { 512fn bin_to_gray(x: u64) -> u64 {
@@ -524,7 +534,10 @@ pub mod time_driver {
524 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,
525 EVTIMER_HI_MASK, EVTIMER_HI_SHIFT, LOW_32_BIT_MASK, 535 EVTIMER_HI_MASK, EVTIMER_HI_SHIFT, LOW_32_BIT_MASK,
526 }; 536 };
537 use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel};
538 use crate::clocks::{enable_and_reset, PoweredClock};
527 use crate::pac; 539 use crate::pac;
540 use crate::peripherals::OSTIMER0;
528 pub struct Driver; 541 pub struct Driver;
529 static TIMER_WAKER: AtomicWaker = AtomicWaker::new(); 542 static TIMER_WAKER: AtomicWaker = AtomicWaker::new();
530 543
@@ -611,6 +624,14 @@ pub mod time_driver {
611 /// Note: The frequency parameter is currently accepted for API compatibility. 624 /// Note: The frequency parameter is currently accepted for API compatibility.
612 /// The embassy_time_driver macro handles driver registration automatically. 625 /// The embassy_time_driver macro handles driver registration automatically.
613 pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) { 626 pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) {
627 let _clock_freq = unsafe {
628 enable_and_reset::<OSTIMER0>(&OsTimerConfig {
629 power: PoweredClock::AlwaysEnabled,
630 source: OstimerClockSel::Clk1M,
631 })
632 .expect("Enabling OsTimer clock should not fail")
633 };
634
614 // Mask/clear at peripheral and set default MATCH 635 // Mask/clear at peripheral and set default MATCH
615 let r: &Regs = unsafe { &*pac::Ostimer0::ptr() }; 636 let r: &Regs = unsafe { &*pac::Ostimer0::ptr() };
616 super::prime_match_registers(r); 637 super::prime_match_registers(r);
diff --git a/src/reset.rs b/src/reset.rs
deleted file mode 100644
index 1c131d1cc..000000000
--- a/src/reset.rs
+++ /dev/null
@@ -1,112 +0,0 @@
1//! Reset control helpers built on PAC field writers.
2use crate::pac;
3
4/// Trait describing a reset line that can be asserted/deasserted.
5pub trait ResetLine {
6 /// Drive the peripheral out of reset.
7 unsafe fn release(mrcc: &pac::mrcc0::RegisterBlock);
8
9 /// Drive the peripheral into reset.
10 unsafe fn assert(mrcc: &pac::mrcc0::RegisterBlock);
11
12 /// Check whether the peripheral is currently released.
13 fn is_released(mrcc: &pac::mrcc0::RegisterBlock) -> bool;
14}
15
16/// Release a reset line for the given peripheral set.
17#[inline]
18pub unsafe fn release<R: ResetLine>(peripherals: &pac::Peripherals) {
19 R::release(&peripherals.mrcc0);
20}
21
22/// Assert a reset line for the given peripheral set.
23#[inline]
24pub unsafe fn assert<R: ResetLine>(peripherals: &pac::Peripherals) {
25 R::assert(&peripherals.mrcc0);
26}
27
28/// Pulse a reset line (assert then release) with a short delay.
29#[inline]
30pub unsafe fn pulse<R: ResetLine>(peripherals: &pac::Peripherals) {
31 let mrcc = &peripherals.mrcc0;
32 R::assert(mrcc);
33 cortex_m::asm::nop();
34 cortex_m::asm::nop();
35 R::release(mrcc);
36}
37
38macro_rules! impl_reset_line {
39 ($name:ident, $reg:ident, $field:ident) => {
40 pub struct $name;
41
42 impl ResetLine for $name {
43 #[inline]
44 unsafe fn release(mrcc: &pac::mrcc0::RegisterBlock) {
45 mrcc.$reg().modify(|_, w| w.$field().enabled());
46 }
47
48 #[inline]
49 unsafe fn assert(mrcc: &pac::mrcc0::RegisterBlock) {
50 mrcc.$reg().modify(|_, w| w.$field().disabled());
51 }
52
53 #[inline]
54 fn is_released(mrcc: &pac::mrcc0::RegisterBlock) -> bool {
55 mrcc.$reg().read().$field().is_enabled()
56 }
57 }
58 };
59}
60
61pub mod line {
62 use super::*;
63
64 impl_reset_line!(Port2, mrcc_glb_rst1, port2);
65 impl_reset_line!(Port3, mrcc_glb_rst1, port3);
66 impl_reset_line!(Gpio3, mrcc_glb_rst2, gpio3);
67 impl_reset_line!(Lpuart2, mrcc_glb_rst0, lpuart2);
68 impl_reset_line!(Ostimer0, mrcc_glb_rst1, ostimer0);
69 impl_reset_line!(Port1, mrcc_glb_rst1, port1);
70 impl_reset_line!(Adc1, mrcc_glb_rst1, adc1);
71}
72
73#[inline]
74pub unsafe fn release_reset_port2(peripherals: &pac::Peripherals) {
75 release::<line::Port2>(peripherals);
76}
77
78#[inline]
79pub unsafe fn release_reset_port3(peripherals: &pac::Peripherals) {
80 release::<line::Port3>(peripherals);
81}
82
83#[inline]
84pub unsafe fn release_reset_gpio3(peripherals: &pac::Peripherals) {
85 release::<line::Gpio3>(peripherals);
86}
87
88#[inline]
89pub unsafe fn release_reset_lpuart2(peripherals: &pac::Peripherals) {
90 release::<line::Lpuart2>(peripherals);
91}
92
93#[inline]
94pub unsafe fn release_reset_ostimer0(peripherals: &pac::Peripherals) {
95 release::<line::Ostimer0>(peripherals);
96}
97
98/// Convenience shim retained for existing call sites.
99#[inline]
100pub unsafe fn reset_ostimer0(peripherals: &pac::Peripherals) {
101 pulse::<line::Ostimer0>(peripherals);
102}
103
104#[inline]
105pub unsafe fn release_reset_port1(peripherals: &pac::Peripherals) {
106 release::<line::Port1>(peripherals);
107}
108
109#[inline]
110pub unsafe fn release_reset_adc1(peripherals: &pac::Peripherals) {
111 release::<line::Adc1>(peripherals);
112}
diff --git a/src/rtc.rs b/src/rtc.rs
index facb9cf8c..b750a97ea 100644
--- a/src/rtc.rs
+++ b/src/rtc.rs
@@ -1,6 +1,9 @@
1//! RTC DateTime driver. 1//! RTC DateTime driver.
2use core::sync::atomic::{AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering};
3 3
4use embassy_hal_internal::{Peri, PeripheralType};
5
6use crate::clocks::with_clocks;
4use crate::pac; 7use crate::pac;
5use crate::pac::rtc0::cr::Um; 8use crate::pac::rtc0::cr::Um;
6 9
@@ -9,7 +12,7 @@ type Regs = pac::rtc0::RegisterBlock;
9static ALARM_TRIGGERED: AtomicBool = AtomicBool::new(false); 12static ALARM_TRIGGERED: AtomicBool = AtomicBool::new(false);
10 13
11// Token-based instance pattern like embassy-imxrt 14// Token-based instance pattern like embassy-imxrt
12pub trait Instance { 15pub trait Instance: PeripheralType {
13 fn ptr() -> *const Regs; 16 fn ptr() -> *const Regs;
14} 17}
15 18
@@ -22,14 +25,6 @@ impl Instance for crate::peripherals::RTC0 {
22 } 25 }
23} 26}
24 27
25// Also implement Instance for the Peri wrapper type
26impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::RTC0> {
27 #[inline(always)]
28 fn ptr() -> *const Regs {
29 pac::Rtc0::ptr()
30 }
31}
32
33const DAYS_IN_A_YEAR: u32 = 365; 28const DAYS_IN_A_YEAR: u32 = 365;
34const SECONDS_IN_A_DAY: u32 = 86400; 29const SECONDS_IN_A_DAY: u32 = 86400;
35const SECONDS_IN_A_HOUR: u32 = 3600; 30const SECONDS_IN_A_HOUR: u32 = 3600;
@@ -157,15 +152,24 @@ pub fn get_default_config() -> RtcConfig {
157 } 152 }
158} 153}
159/// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy) 154/// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy)
160pub struct Rtc<I: Instance> { 155pub struct Rtc<'a, I: Instance> {
161 _inst: core::marker::PhantomData<I>, 156 _inst: core::marker::PhantomData<&'a mut I>,
162} 157}
163 158
164impl<I: Instance> Rtc<I> { 159impl<'a, I: Instance> Rtc<'a, I> {
165 /// initialize RTC 160 /// initialize RTC
166 pub fn new(_inst: impl Instance, config: RtcConfig) -> Self { 161 pub fn new(_inst: Peri<'a, I>, config: RtcConfig) -> Self {
167 let rtc = unsafe { &*I::ptr() }; 162 let rtc = unsafe { &*I::ptr() };
168 163
164 // The RTC is NOT gated by the MRCC, but we DO need to make sure the 16k clock
165 // on the vsys domain is active
166 let clocks = with_clocks(|c| c.clk_16k_vsys.clone());
167 match clocks {
168 None => panic!("Clocks have not been initialized"),
169 Some(None) => panic!("Clocks initialized, but clk_16k_vsys not active"),
170 Some(Some(_)) => {}
171 }
172
169 /* RTC reset */ 173 /* RTC reset */
170 rtc.cr().modify(|_, w| w.swr().set_bit()); 174 rtc.cr().modify(|_, w| w.swr().set_bit());
171 rtc.cr().modify(|_, w| w.swr().clear_bit()); 175 rtc.cr().modify(|_, w| w.swr().clear_bit());
diff --git a/src/uart.rs b/src/uart.rs
deleted file mode 100644
index 3705959d3..000000000
--- a/src/uart.rs
+++ /dev/null
@@ -1,316 +0,0 @@
1//! Minimal polling UART2 bring-up replicating MCUXpresso hello_world ordering.
2//! WARNING: This is a narrow implementation only for debug console (115200 8N1).
3
4// TODO(AJM): As of 2025-11-13, we need to do a pass to ensure safety docs
5// are complete prior to release.
6#![allow(clippy::missing_safety_doc)]
7
8use core::cell::RefCell;
9
10use cortex_m::interrupt::Mutex;
11use embassy_sync::signal::Signal;
12
13use crate::pac;
14
15// svd2rust defines the shared LPUART RegisterBlock under lpuart0; all instances reuse it.
16type Regs = pac::lpuart0::RegisterBlock;
17
18// Token-based instance pattern like embassy-imxrt
19pub trait Instance {
20 fn ptr() -> *const Regs;
21}
22
23/// Token for LPUART2 provided by embassy-hal-internal peripherals macro.
24pub type Lpuart2 = crate::peripherals::LPUART2;
25impl Instance for crate::peripherals::LPUART2 {
26 #[inline(always)]
27 fn ptr() -> *const Regs {
28 pac::Lpuart2::ptr()
29 }
30}
31
32// Also implement Instance for the Peri wrapper type
33impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::LPUART2> {
34 #[inline(always)]
35 fn ptr() -> *const Regs {
36 pac::Lpuart2::ptr()
37 }
38}
39
40/// UART configuration (explicit src_hz; no hardcoded frequencies)
41#[derive(Copy, Clone)]
42pub struct Config {
43 pub src_hz: u32,
44 pub baud: u32,
45 pub parity: Parity,
46 pub stop_bits: StopBits,
47}
48
49#[derive(Copy, Clone)]
50pub enum Parity {
51 None,
52 Even,
53 Odd,
54}
55#[derive(Copy, Clone)]
56pub enum StopBits {
57 One,
58 Two,
59}
60
61impl Config {
62 pub fn new(src_hz: u32) -> Self {
63 Self {
64 src_hz,
65 baud: 115_200,
66 parity: Parity::None,
67 stop_bits: StopBits::One,
68 }
69 }
70}
71
72/// Compute a valid (OSR, SBR) tuple for given source clock and baud.
73/// Uses a functional fold approach to find the best OSR/SBR combination
74/// with minimal baud rate error.
75fn compute_osr_sbr(src_hz: u32, baud: u32) -> (u8, u16) {
76 let (best_osr, best_sbr, _best_err) = (8u32..=32).fold(
77 (16u8, 4u16, u32::MAX), // (best_osr, best_sbr, best_err)
78 |(best_osr, best_sbr, best_err), osr| {
79 let denom = baud.saturating_mul(osr);
80 if denom == 0 {
81 return (best_osr, best_sbr, best_err);
82 }
83
84 let sbr = (src_hz + denom / 2) / denom; // round
85 if sbr == 0 || sbr > 0x1FFF {
86 return (best_osr, best_sbr, best_err);
87 }
88
89 let actual = src_hz / (osr * sbr);
90 let err = actual.abs_diff(baud);
91
92 // Update best if this is better, or same error but higher OSR
93 if err < best_err || (err == best_err && osr as u8 > best_osr) {
94 (osr as u8, sbr as u16, err)
95 } else {
96 (best_osr, best_sbr, best_err)
97 }
98 },
99 );
100 (best_osr, best_sbr)
101}
102
103/// Minimal UART handle for a specific instance I (store the zero-sized token like embassy)
104pub struct Uart<I: Instance> {
105 _inst: core::marker::PhantomData<I>,
106}
107
108impl<I: Instance> Uart<I> {
109 /// Create and initialize LPUART (reset + config). Clocks and pins must be prepared by the caller.
110 pub fn new(_inst: impl Instance, cfg: Config) -> Self {
111 let l = unsafe { &*I::ptr() };
112 // 1) software reset pulse
113 l.global().write(|w| w.rst().reset());
114 cortex_m::asm::delay(3); // Short delay for reset to take effect
115 l.global().write(|w| w.rst().no_effect());
116 cortex_m::asm::delay(10); // Allow peripheral to stabilize after reset
117 // 2) BAUD
118 let (osr, sbr) = compute_osr_sbr(cfg.src_hz, cfg.baud);
119 l.baud().modify(|_, w| {
120 let w = match cfg.stop_bits {
121 StopBits::One => w.sbns().one(),
122 StopBits::Two => w.sbns().two(),
123 };
124 // OSR field encodes (osr-1); use raw bits to avoid a long match on all variants
125 let raw_osr = osr.saturating_sub(1);
126 unsafe { w.osr().bits(raw_osr).sbr().bits(sbr) }
127 });
128 // 3) CTRL baseline and parity
129 l.ctrl().write(|w| {
130 let w = w.ilt().from_stop().idlecfg().idle_2();
131 let w = match cfg.parity {
132 Parity::None => w.pe().disabled(),
133 Parity::Even => w.pe().enabled().pt().even(),
134 Parity::Odd => w.pe().enabled().pt().odd(),
135 };
136 w.re().enabled().te().enabled().rie().disabled()
137 });
138 // 4) FIFOs and WATER: keep it simple for polling; disable FIFOs and set RX watermark to 0
139 l.fifo().modify(|_, w| {
140 w.txfe()
141 .disabled()
142 .rxfe()
143 .disabled()
144 .txflush()
145 .txfifo_rst()
146 .rxflush()
147 .rxfifo_rst()
148 });
149 l.water()
150 .modify(|_, w| unsafe { w.txwater().bits(0).rxwater().bits(0) });
151 Self {
152 _inst: core::marker::PhantomData,
153 }
154 }
155
156 /// Enable RX interrupts. The caller must ensure an appropriate IRQ handler is installed.
157 pub unsafe fn enable_rx_interrupts(&self) {
158 let l = &*I::ptr();
159 l.ctrl().modify(|_, w| w.rie().enabled());
160 }
161
162 #[inline(never)]
163 pub fn write_byte(&self, b: u8) {
164 let l = unsafe { &*I::ptr() };
165 // Timeout after ~10ms at 12MHz (assuming 115200 baud, should be plenty)
166 const DATA_OFFSET: usize = 0x1C; // DATA register offset inside LPUART block
167 let data_ptr = unsafe { (I::ptr() as *mut u8).add(DATA_OFFSET) };
168 for _ in 0..120000 {
169 if l.water().read().txcount().bits() == 0 {
170 unsafe { core::ptr::write_volatile(data_ptr, b) };
171 return;
172 }
173 }
174 // If timeout, skip the write to avoid hanging
175 }
176
177 #[inline(never)]
178 pub fn write_str_blocking(&self, s: &str) {
179 for &b in s.as_bytes() {
180 if b == b'\n' {
181 self.write_byte(b'\r');
182 }
183 self.write_byte(b);
184 }
185 }
186 pub fn read_byte_blocking(&self) -> u8 {
187 let l = unsafe { &*I::ptr() };
188 while !l.stat().read().rdrf().is_rxdata() {}
189 (l.data().read().bits() & 0xFF) as u8
190 }
191}
192
193// Simple ring buffer for UART RX data
194const RX_BUFFER_SIZE: usize = 256;
195pub struct RingBuffer {
196 buffer: [u8; RX_BUFFER_SIZE],
197 read_idx: usize,
198 write_idx: usize,
199 count: usize,
200}
201
202impl Default for RingBuffer {
203 fn default() -> Self {
204 Self::new()
205 }
206}
207
208impl RingBuffer {
209 pub const fn new() -> Self {
210 Self {
211 buffer: [0; RX_BUFFER_SIZE],
212 read_idx: 0,
213 write_idx: 0,
214 count: 0,
215 }
216 }
217
218 pub fn push(&mut self, data: u8) -> bool {
219 if self.count >= RX_BUFFER_SIZE {
220 return false; // Buffer full
221 }
222 self.buffer[self.write_idx] = data;
223 self.write_idx = (self.write_idx + 1) % RX_BUFFER_SIZE;
224 self.count += 1;
225 true
226 }
227
228 pub fn pop(&mut self) -> Option<u8> {
229 if self.count == 0 {
230 return None;
231 }
232 let data = self.buffer[self.read_idx];
233 self.read_idx = (self.read_idx + 1) % RX_BUFFER_SIZE;
234 self.count -= 1;
235 Some(data)
236 }
237
238 pub fn is_empty(&self) -> bool {
239 self.count == 0
240 }
241
242 pub fn len(&self) -> usize {
243 self.count
244 }
245}
246
247// Global RX buffer shared between interrupt handler and UART instance
248static RX_BUFFER: Mutex<RefCell<RingBuffer>> = Mutex::new(RefCell::new(RingBuffer::new()));
249static RX_SIGNAL: Signal<embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex, ()> = Signal::new();
250
251// Debug counter for interrupt handler calls
252static mut INTERRUPT_COUNT: u32 = 0;
253
254impl<I: Instance> Uart<I> {
255 /// Read a byte asynchronously using interrupts
256 pub async fn read_byte_async(&self) -> u8 {
257 loop {
258 // Check if we have data in the buffer
259 let byte = cortex_m::interrupt::free(|cs| {
260 let mut buffer = RX_BUFFER.borrow(cs).borrow_mut();
261 buffer.pop()
262 });
263
264 if let Some(byte) = byte {
265 return byte;
266 }
267
268 // Wait for the interrupt signal
269 RX_SIGNAL.wait().await;
270 }
271 }
272
273 /// Check if there's data available in the RX buffer
274 pub fn rx_data_available(&self) -> bool {
275 cortex_m::interrupt::free(|cs| {
276 let buffer = RX_BUFFER.borrow(cs).borrow();
277 !buffer.is_empty()
278 })
279 }
280
281 /// Try to read a byte from RX buffer (non-blocking)
282 pub fn try_read_byte(&self) -> Option<u8> {
283 cortex_m::interrupt::free(|cs| {
284 let mut buffer = RX_BUFFER.borrow(cs).borrow_mut();
285 buffer.pop()
286 })
287 }
288}
289
290/// Type-level handler for LPUART2 interrupts, compatible with bind_interrupts!.
291pub struct UartInterruptHandler;
292
293impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::LPUART2> for UartInterruptHandler {
294 unsafe fn on_interrupt() {
295 INTERRUPT_COUNT += 1;
296
297 let lpuart = &*pac::Lpuart2::ptr();
298
299 // Check if we have RX data
300 if lpuart.stat().read().rdrf().is_rxdata() {
301 // Read the data byte
302 let data = (lpuart.data().read().bits() & 0xFF) as u8;
303
304 // Store in ring buffer
305 cortex_m::interrupt::free(|cs| {
306 let mut buffer = RX_BUFFER.borrow(cs).borrow_mut();
307 if buffer.push(data) {
308 // Data added successfully, signal waiting tasks
309 RX_SIGNAL.signal(());
310 }
311 });
312 }
313 // Always clear any error flags that might cause spurious interrupts
314 let _ = lpuart.stat().read();
315 }
316}
diff --git a/supply-chain/config.toml b/supply-chain/config.toml
index 36a513ee2..173392c16 100644
--- a/supply-chain/config.toml
+++ b/supply-chain/config.toml
@@ -13,10 +13,6 @@ url = "https://raw.githubusercontent.com/google/rust-crate-audits/main/audits.to
13[imports.mozilla] 13[imports.mozilla]
14url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml" 14url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml"
15 15
16[[exemptions.az]]
17version = "1.2.1"
18criteria = "safe-to-deploy"
19
20[[exemptions.bare-metal]] 16[[exemptions.bare-metal]]
21version = "0.2.5" 17version = "0.2.5"
22criteria = "safe-to-deploy" 18criteria = "safe-to-deploy"
@@ -25,14 +21,6 @@ criteria = "safe-to-deploy"
25version = "0.13.2" 21version = "0.13.2"
26criteria = "safe-to-deploy" 22criteria = "safe-to-deploy"
27 23
28[[exemptions.bitfield]]
29version = "0.15.0"
30criteria = "safe-to-deploy"
31
32[[exemptions.chrono]]
33version = "0.4.40"
34criteria = "safe-to-deploy"
35
36[[exemptions.cortex-m]] 24[[exemptions.cortex-m]]
37version = "0.7.7" 25version = "0.7.7"
38criteria = "safe-to-deploy" 26criteria = "safe-to-deploy"
@@ -117,10 +105,6 @@ criteria = "safe-to-deploy"
117version = "0.4.1" 105version = "0.4.1"
118criteria = "safe-to-deploy" 106criteria = "safe-to-deploy"
119 107
120[[exemptions.fixed]]
121version = "1.29.0"
122criteria = "safe-to-deploy"
123
124[[exemptions.futures-core]] 108[[exemptions.futures-core]]
125version = "0.3.31" 109version = "0.3.31"
126criteria = "safe-to-deploy" 110criteria = "safe-to-deploy"
@@ -137,26 +121,10 @@ criteria = "safe-to-deploy"
137version = "0.8.0" 121version = "0.8.0"
138criteria = "safe-to-deploy" 122criteria = "safe-to-deploy"
139 123
140[[exemptions.itertools]]
141version = "0.11.0"
142criteria = "safe-to-deploy"
143
144[[exemptions.log]]
145version = "0.4.27"
146criteria = "safe-to-deploy"
147
148[[exemptions.mimxrt600-fcb]]
149version = "0.2.1"
150criteria = "safe-to-deploy"
151
152[[exemptions.paste]] 124[[exemptions.paste]]
153version = "1.0.15" 125version = "1.0.15"
154criteria = "safe-to-deploy" 126criteria = "safe-to-deploy"
155 127
156[[exemptions.portable-atomic]]
157version = "1.11.0"
158criteria = "safe-to-run"
159
160[[exemptions.proc-macro-error-attr2]] 128[[exemptions.proc-macro-error-attr2]]
161version = "2.0.0" 129version = "2.0.0"
162criteria = "safe-to-deploy" 130criteria = "safe-to-deploy"
@@ -177,14 +145,6 @@ criteria = "safe-to-deploy"
177version = "0.7.0" 145version = "0.7.0"
178criteria = "safe-to-deploy" 146criteria = "safe-to-deploy"
179 147
180[[exemptions.static_cell]]
181version = "2.1.0"
182criteria = "safe-to-run"
183
184[[exemptions.typenum]]
185version = "1.18.0"
186criteria = "safe-to-deploy"
187
188[[exemptions.vcell]] 148[[exemptions.vcell]]
189version = "0.1.3" 149version = "0.1.3"
190criteria = "safe-to-deploy" 150criteria = "safe-to-deploy"
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index 3f541e59f..aa62839e2 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -3,13 +3,6 @@
3 3
4[audits.OpenDevicePartnership.audits] 4[audits.OpenDevicePartnership.audits]
5 5
6[[audits.google.audits.autocfg]]
7who = "Manish Goregaokar <[email protected]>"
8criteria = "safe-to-deploy"
9version = "1.4.0"
10notes = "Contains no unsafe"
11aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
12
13[[audits.google.audits.bitflags]] 6[[audits.google.audits.bitflags]]
14who = "Lukasz Anforowicz <[email protected]>" 7who = "Lukasz Anforowicz <[email protected]>"
15criteria = "safe-to-deploy" 8criteria = "safe-to-deploy"
@@ -26,67 +19,6 @@ Additional review comments can be found at https://crrev.com/c/4723145/31
26""" 19"""
27aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" 20aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
28 21
29[[audits.google.audits.bytemuck]]
30who = "Lukasz Anforowicz <[email protected]>"
31criteria = "safe-to-deploy"
32version = "1.16.3"
33notes = """
34Review notes from the original audit (of 1.14.3) may be found in
35https://crrev.com/c/5362675. Note that this audit has initially missed UB risk
36that was fixed in 1.16.2 - see https://github.com/Lokathor/bytemuck/pull/258.
37Because of this, the original audit has been edited to certify version `1.16.3`
38instead (see also https://crrev.com/c/5771867).
39"""
40aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
41
42[[audits.google.audits.bytemuck]]
43who = "Lukasz Anforowicz <[email protected]>"
44criteria = "safe-to-deploy"
45delta = "1.16.3 -> 1.17.1"
46notes = "Unsafe review comments can be found in https://crrev.com/c/5813463"
47aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
48
49[[audits.google.audits.bytemuck]]
50who = "Adrian Taylor <[email protected]>"
51criteria = "safe-to-deploy"
52delta = "1.17.1 -> 1.18.0"
53notes = "No code changes - just altering feature flag arrangements"
54aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
55
56[[audits.google.audits.bytemuck]]
57who = "Adrian Taylor <[email protected]>"
58criteria = "safe-to-deploy"
59delta = "1.18.0 -> 1.19.0"
60notes = "No code changes - just comment changes and adding the track_caller attribute."
61aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
62
63[[audits.google.audits.bytemuck]]
64who = "Lukasz Anforowicz <[email protected]>"
65criteria = "safe-to-deploy"
66delta = "1.19.0 -> 1.20.0"
67notes = "`unsafe` review can be found at https://crrev.com/c/6096767"
68aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
69
70[[audits.google.audits.bytemuck]]
71who = "Adrian Taylor <[email protected]>"
72criteria = "safe-to-deploy"
73delta = "1.20.0 -> 1.21.0"
74notes = "Unsafe review at https://chromium-review.googlesource.com/c/chromium/src/+/6111154/"
75aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
76
77[[audits.google.audits.bytemuck]]
78who = "Daniel Cheng <[email protected]>"
79criteria = "safe-to-deploy"
80delta = "1.21.0 -> 1.22.0"
81notes = """
82This adds new instances of unsafe, but the uses are justified:
83- BoxBytes is essentially a Box<[u8], which is Send + Sync, so also marking BoxBytes as Send + Sync is justified.
84- core::num::Saturating<T> meets the criteria for Zeroable + Pod, so marking it as such is justified.
85
86See https://crrev.com/c/6321863 for more audit notes.
87"""
88aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
89
90[[audits.google.audits.byteorder]] 22[[audits.google.audits.byteorder]]
91who = "danakj <[email protected]>" 23who = "danakj <[email protected]>"
92criteria = "safe-to-deploy" 24criteria = "safe-to-deploy"
@@ -94,40 +26,6 @@ version = "1.5.0"
94notes = "Unsafe review in https://crrev.com/c/5838022" 26notes = "Unsafe review in https://crrev.com/c/5838022"
95aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" 27aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
96 28
97[[audits.google.audits.cfg-if]]
98who = "George Burgess IV <[email protected]>"
99criteria = "safe-to-deploy"
100version = "1.0.0"
101aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
102
103[[audits.google.audits.either]]
104who = "Manish Goregaokar <[email protected]>"
105criteria = "safe-to-deploy"
106version = "1.13.0"
107notes = "Unsafe code pertaining to wrapping Pin APIs. Mostly passes invariants down."
108aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
109
110[[audits.google.audits.either]]
111who = "Daniel Cheng <[email protected]>"
112criteria = "safe-to-deploy"
113delta = "1.13.0 -> 1.14.0"
114notes = """
115Inheriting ub-risk-1 from the baseline review of 1.13.0. While the delta has some diffs in unsafe code, they are either:
116- migrating code to use helper macros
117- migrating match patterns to take advantage of default bindings mode from RFC 2005
118Either way, the result is code that does exactly the same thing and does not change the risk of UB.
119
120See https://crrev.com/c/6323164 for more audit details.
121"""
122aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
123
124[[audits.google.audits.either]]
125who = "Lukasz Anforowicz <[email protected]>"
126criteria = "safe-to-deploy"
127delta = "1.14.0 -> 1.15.0"
128notes = "The delta in `lib.rs` only tweaks doc comments and `#[cfg(feature = \"std\")]`."
129aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
130
131[[audits.google.audits.nb]] 29[[audits.google.audits.nb]]
132who = "George Burgess IV <[email protected]>" 30who = "George Burgess IV <[email protected]>"
133criteria = "safe-to-deploy" 31criteria = "safe-to-deploy"
@@ -153,320 +51,10 @@ version = "0.2.19"
153notes = "Contains a single line of float-to-int unsafe with decent safety comments" 51notes = "Contains a single line of float-to-int unsafe with decent safety comments"
154aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" 52aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
155 53
156[[audits.google.audits.proc-macro2]]
157who = "Lukasz Anforowicz <[email protected]>"
158criteria = "safe-to-deploy"
159version = "1.0.78"
160notes = """
161Grepped for \"crypt\", \"cipher\", \"fs\", \"net\" - there were no hits
162(except for a benign \"fs\" hit in a doc comment)
163
164Notes from the `unsafe` review can be found in https://crrev.com/c/5385745.
165"""
166aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
167
168[[audits.google.audits.proc-macro2]]
169who = "Adrian Taylor <[email protected]>"
170criteria = "safe-to-deploy"
171delta = "1.0.78 -> 1.0.79"
172aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
173
174[[audits.google.audits.proc-macro2]]
175who = "Adrian Taylor <[email protected]>"
176criteria = "safe-to-deploy"
177delta = "1.0.79 -> 1.0.80"
178aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
179
180[[audits.google.audits.proc-macro2]]
181who = "Dustin J. Mitchell <[email protected]>"
182criteria = "safe-to-deploy"
183delta = "1.0.80 -> 1.0.81"
184notes = "Comment changes only"
185aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
186
187[[audits.google.audits.proc-macro2]]
188who = "danakj <[email protected]>"
189criteria = "safe-to-deploy"
190delta = "1.0.81 -> 1.0.82"
191aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
192
193[[audits.google.audits.proc-macro2]]
194who = "Dustin J. Mitchell <[email protected]>"
195criteria = "safe-to-deploy"
196delta = "1.0.82 -> 1.0.83"
197notes = "Substantive change is replacing String with Box<str>, saving memory."
198aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
199
200[[audits.google.audits.proc-macro2]]
201who = "Lukasz Anforowicz <[email protected]>"
202criteria = "safe-to-deploy"
203delta = "1.0.83 -> 1.0.84"
204notes = "Only doc comment changes in `src/lib.rs`."
205aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
206
207[[audits.google.audits.proc-macro2]]
208who = "[email protected]"
209criteria = "safe-to-deploy"
210delta = "1.0.84 -> 1.0.85"
211notes = "Test-only changes."
212aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
213
214[[audits.google.audits.proc-macro2]]
215who = "Lukasz Anforowicz <[email protected]>"
216criteria = "safe-to-deploy"
217delta = "1.0.85 -> 1.0.86"
218notes = """
219Comment-only changes in `build.rs`.
220Reordering of `Cargo.toml` entries.
221Just bumping up the version number in `lib.rs`.
222Config-related changes in `test_size.rs`.
223"""
224aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
225
226[[audits.google.audits.proc-macro2]]
227who = "danakj <[email protected]>"
228criteria = "safe-to-deploy"
229delta = "1.0.86 -> 1.0.87"
230notes = "No new unsafe interactions."
231aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
232
233[[audits.google.audits.proc-macro2]]
234who = "Liza Burakova <[email protected]"
235criteria = "safe-to-deploy"
236delta = "1.0.87 -> 1.0.89"
237notes = """
238Biggest change is adding error handling in build.rs.
239Some config related changes in wrapper.rs.
240"""
241aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
242
243[[audits.google.audits.proc-macro2]]
244who = "Lukasz Anforowicz <[email protected]>"
245criteria = "safe-to-deploy"
246delta = "1.0.89 -> 1.0.92"
247notes = """
248I looked at the delta and the previous discussion at
249https://chromium-review.googlesource.com/c/chromium/src/+/5385745/3#message-a8e2813129fa3779dab15acede408ee26d67b7f3
250and the changes look okay to me (including the `unsafe fn from_str_unchecked`
251changes in `wrapper.rs`).
252"""
253aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
254
255[[audits.google.audits.proc-macro2]]
256who = "Lukasz Anforowicz <[email protected]>"
257criteria = "safe-to-deploy"
258delta = "1.0.92 -> 1.0.93"
259notes = "No `unsafe`-related changes."
260aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
261
262[[audits.google.audits.proc-macro2]]
263who = "Daniel Cheng <[email protected]>"
264criteria = "safe-to-deploy"
265delta = "1.0.93 -> 1.0.94"
266notes = "Minor doc changes and clippy lint adjustments+fixes."
267aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
268
269[[audits.google.audits.quote]]
270who = "Lukasz Anforowicz <[email protected]>"
271criteria = "safe-to-deploy"
272version = "1.0.35"
273notes = """
274Grepped for \"unsafe\", \"crypt\", \"cipher\", \"fs\", \"net\" - there were no hits
275(except for benign \"net\" hit in tests and \"fs\" hit in README.md)
276"""
277aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
278
279[[audits.google.audits.quote]]
280who = "Adrian Taylor <[email protected]>"
281criteria = "safe-to-deploy"
282delta = "1.0.35 -> 1.0.36"
283aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
284
285[[audits.google.audits.quote]]
286who = "Lukasz Anforowicz <[email protected]>"
287criteria = "safe-to-deploy"
288delta = "1.0.36 -> 1.0.37"
289notes = """
290The delta just 1) inlines/expands `impl ToTokens` that used to be handled via
291`primitive!` macro and 2) adds `impl ToTokens` for `CStr` and `CString`.
292"""
293aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
294
295[[audits.google.audits.quote]]
296who = "Dustin J. Mitchell <[email protected]>"
297criteria = "safe-to-deploy"
298delta = "1.0.37 -> 1.0.38"
299notes = "Still no unsafe"
300aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
301
302[[audits.google.audits.quote]]
303who = "Daniel Cheng <[email protected]>"
304criteria = "safe-to-deploy"
305delta = "1.0.38 -> 1.0.39"
306notes = "Only minor changes for clippy lints and documentation."
307aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
308
309[[audits.google.audits.quote]]
310who = "Lukasz Anforowicz <[email protected]>"
311criteria = "safe-to-deploy"
312delta = "1.0.39 -> 1.0.40"
313notes = """
314The delta is just a simplification of how `tokens.extend(...)` call is made.
315Still no `unsafe` anywhere.
316"""
317aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
318
319[[audits.google.audits.rand_core]]
320who = "Lukasz Anforowicz <[email protected]>"
321criteria = "safe-to-deploy"
322version = "0.6.4"
323notes = """
324For more detailed unsafe review notes please see https://crrev.com/c/6362797
325"""
326aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
327
328[[audits.google.audits.stable_deref_trait]]
329who = "Manish Goregaokar <[email protected]>"
330criteria = "safe-to-deploy"
331version = "1.2.0"
332notes = "Purely a trait, crates using this should be carefully vetted since self-referential stuff can be super tricky around various unsafe rust edges."
333aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
334
335[[audits.google.audits.strsim]]
336who = "[email protected]"
337criteria = "safe-to-deploy"
338version = "0.10.0"
339notes = """
340Reviewed in https://crrev.com/c/5171063
341
342Previously reviewed during security review and the audit is grandparented in.
343"""
344aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
345
346[[audits.google.audits.unicode-ident]]
347who = "Lukasz Anforowicz <[email protected]>"
348criteria = "safe-to-deploy"
349version = "1.0.12"
350notes = '''
351I grepped for \"crypt\", \"cipher\", \"fs\", \"net\" - there were no hits.
352
353All two functions from the public API of this crate use `unsafe` to avoid bound
354checks for an array access. Cross-module analysis shows that the offsets can
355be statically proven to be within array bounds. More details can be found in
356the unsafe review CL at https://crrev.com/c/5350386.
357
358This crate has been added to Chromium in https://crrev.com/c/3891618.
359'''
360aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
361
362[[audits.google.audits.unicode-ident]]
363who = "Dustin J. Mitchell <[email protected]>"
364criteria = "safe-to-deploy"
365delta = "1.0.12 -> 1.0.13"
366notes = "Lots of table updates, and tables are assumed correct with unsafe `.get_unchecked()`, so ub-risk-2 is appropriate"
367aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
368
369[[audits.google.audits.unicode-ident]]
370who = "Lukasz Anforowicz <[email protected]>"
371criteria = "safe-to-deploy"
372delta = "1.0.13 -> 1.0.14"
373notes = "Minimal delta in `.rs` files: new test assertions + doc changes."
374aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
375
376[[audits.google.audits.unicode-ident]]
377who = "Adrian Taylor <[email protected]>"
378criteria = "safe-to-deploy"
379delta = "1.0.14 -> 1.0.15"
380notes = "No changes relevant to any of these criteria."
381aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
382
383[[audits.google.audits.unicode-ident]]
384who = "Liza Burakova <[email protected]>"
385criteria = "safe-to-deploy"
386delta = "1.0.15 -> 1.0.16"
387aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
388
389[[audits.google.audits.unicode-ident]]
390who = "Daniel Cheng <[email protected]>"
391criteria = "safe-to-deploy"
392delta = "1.0.16 -> 1.0.18"
393notes = "Only minor comment and documentation updates."
394aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
395
396[[audits.google.audits.void]] 54[[audits.google.audits.void]]
397who = "George Burgess IV <[email protected]>" 55who = "George Burgess IV <[email protected]>"
398criteria = "safe-to-deploy" 56criteria = "safe-to-deploy"
399version = "1.0.2" 57version = "1.0.2"
400aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" 58aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
401 59
402[[audits.mozilla.audits.crunchy]] 60[audits.mozilla.audits]
403who = "Erich Gubler <[email protected]>"
404criteria = "safe-to-deploy"
405version = "0.2.3"
406aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
407
408[[audits.mozilla.audits.document-features]]
409who = "Erich Gubler <[email protected]>"
410criteria = "safe-to-deploy"
411version = "0.2.8"
412aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
413
414[[audits.mozilla.audits.document-features]]
415who = "Erich Gubler <[email protected]>"
416criteria = "safe-to-deploy"
417delta = "0.2.8 -> 0.2.9"
418aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
419
420[[audits.mozilla.audits.document-features]]
421who = "Erich Gubler <[email protected]>"
422criteria = "safe-to-deploy"
423delta = "0.2.9 -> 0.2.10"
424aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
425
426[[audits.mozilla.audits.document-features]]
427who = "Teodor Tanasoaia <[email protected]>"
428criteria = "safe-to-deploy"
429delta = "0.2.10 -> 0.2.11"
430aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
431
432[[audits.mozilla.audits.fnv]]
433who = "Bobby Holley <[email protected]>"
434criteria = "safe-to-deploy"
435version = "1.0.7"
436notes = "Simple hasher implementation with no unsafe code."
437aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
438
439[[audits.mozilla.audits.half]]
440who = "John M. Schanck <[email protected]>"
441criteria = "safe-to-deploy"
442version = "1.8.2"
443notes = """
444This crate contains unsafe code for bitwise casts to/from binary16 floating-point
445format. I've reviewed these and found no issues. There are no uses of ambient
446capabilities.
447"""
448aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
449
450[[audits.mozilla.audits.half]]
451who = "Erich Gubler <[email protected]>"
452criteria = "safe-to-deploy"
453delta = "1.8.2 -> 1.8.3"
454aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
455
456[[audits.mozilla.audits.half]]
457who = "Erich Gubler <[email protected]>"
458criteria = "safe-to-deploy"
459delta = "1.8.3 -> 2.5.0"
460aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
461
462[[audits.mozilla.audits.litrs]]
463who = "Erich Gubler <[email protected]>"
464criteria = "safe-to-deploy"
465version = "0.4.1"
466aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
467
468[[audits.mozilla.audits.strsim]]
469who = "Ben Dean-Kawamura <[email protected]>"
470criteria = "safe-to-deploy"
471delta = "0.10.0 -> 0.11.1"
472aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"