aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-12-19 18:35:26 +0000
committerGitHub <[email protected]>2025-12-19 18:35:26 +0000
commit8484b3bfaf11c7b2a9adfe4091c45fc44f1af1dc (patch)
tree4dccb1f479f368de956664fccbc692cecc09c33d /embassy-rp
parentecb395e9334360994a9201c0ad3e7e921aa2d81a (diff)
parent7227c7bde24b9ebd1e3fcc355f708690d1724469 (diff)
Merge pull request #5061 from ericseppanen/pio_dividerHEADmain
embassy_rp: improve calculate_pio_clock_divider
Diffstat (limited to 'embassy-rp')
-rw-r--r--embassy-rp/src/pio_programs/clock_divider.rs61
1 files changed, 55 insertions, 6 deletions
diff --git a/embassy-rp/src/pio_programs/clock_divider.rs b/embassy-rp/src/pio_programs/clock_divider.rs
index 02e353f53..87ba93008 100644
--- a/embassy-rp/src/pio_programs/clock_divider.rs
+++ b/embassy-rp/src/pio_programs/clock_divider.rs
@@ -1,6 +1,5 @@
1//! Helper functions for calculating PIO clock dividers 1//! Helper functions for calculating PIO clock dividers
2 2
3use fixed::traits::ToFixed;
4use fixed::types::extra::U8; 3use fixed::types::extra::U8;
5 4
6use crate::clocks::clk_sys_freq; 5use crate::clocks::clk_sys_freq;
@@ -14,12 +13,62 @@ use crate::clocks::clk_sys_freq;
14/// # Returns 13/// # Returns
15/// 14///
16/// A fixed-point divider value suitable for use in a PIO state machine configuration 15/// A fixed-point divider value suitable for use in a PIO state machine configuration
17#[inline]
18pub fn calculate_pio_clock_divider(target_hz: u32) -> fixed::FixedU32<U8> { 16pub fn calculate_pio_clock_divider(target_hz: u32) -> fixed::FixedU32<U8> {
17 calculate_pio_clock_divider_value(clk_sys_freq(), target_hz)
18}
19
20/// Calculate a PIO clock divider value based on the desired target frequency.
21///
22/// # Arguments
23///
24/// * `sys_hz` - The system clock frequency in Hz
25/// * `target_hz` - The desired PIO clock frequency in Hz
26///
27/// # Returns
28///
29/// A fixed-point divider value suitable for use in a PIO state machine configuration
30pub const fn calculate_pio_clock_divider_value(sys_hz: u32, target_hz: u32) -> fixed::FixedU32<U8> {
19 // Requires a non-zero frequency 31 // Requires a non-zero frequency
20 assert!(target_hz > 0, "PIO clock frequency cannot be zero"); 32 core::assert!(target_hz > 0);
33
34 // Compute the integer and fractional part of the divider.
35 // Doing it this way allows us to avoid u64 division while
36 // maintaining precision.
37 let integer = sys_hz / target_hz;
38 let remainder = sys_hz % target_hz;
39 let frac = (remainder << 8) / target_hz;
40
41 let result = integer << 8 | frac;
42
43 // Ensure the result will fit in 16+8 bits.
44 core::assert!(result <= 0xffff_ff);
45 // The clock divider can't be used to go faster than the system clock.
46 core::assert!(result >= 0x0001_00);
47
48 fixed::FixedU32::from_bits(result)
49}
50
51#[cfg(test)]
52mod tests {
53 use fixed::traits::ToFixed;
54
55 use super::*;
56
57 #[test]
58 fn clock_divider_math() {
59 // A simple divider that must have a fractional part.
60 let divider = calculate_pio_clock_divider_value(125_000_000, 40_000_000);
61 let expected: fixed::FixedU32<U8> = 3.125.to_fixed();
62 assert_eq!(divider, expected);
63
64 // A system clk so high it would overflow a u32 if shifted left.
65 let divider = calculate_pio_clock_divider_value(2_000_000_000, 40_000);
66 let expected: fixed::FixedU32<U8> = 50000.to_fixed();
67 assert_eq!(divider, expected);
21 68
22 // Calculate the divider 69 // A divider that requires all 8 fractional bits.
23 let divider = (clk_sys_freq() + target_hz / 2) / target_hz; 70 let divider = calculate_pio_clock_divider_value(134_283_264, 16_777_216);
24 divider.to_fixed() 71 let expected: fixed::FixedU32<U8> = 8.00390625.to_fixed();
72 assert_eq!(divider, expected);
73 }
25} 74}