aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThales Fragoso <[email protected]>2021-05-17 21:35:29 -0300
committerThales Fragoso <[email protected]>2021-05-21 20:13:37 -0300
commit054f0d51dc8f953140c10585e697e6cf9b500ae7 (patch)
tree144dde7e747fae22ec2934dc7037170eac683363
parent7e388fcf5882011b00508a4e67f68d26c5137f7e (diff)
H7: Add initial PLL configuration
-rw-r--r--embassy-stm32/src/lib.rs4
-rw-r--r--embassy-stm32/src/rcc/h7/mod.rs27
-rw-r--r--embassy-stm32/src/rcc/h7/pll.rs150
-rw-r--r--embassy-stm32/src/rcc/mod.rs4
4 files changed, 183 insertions, 2 deletions
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index c856c8eb1..8d7b67b74 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -13,6 +13,7 @@ pub mod fmt;
13pub mod dma; 13pub mod dma;
14pub mod exti; 14pub mod exti;
15pub mod gpio; 15pub mod gpio;
16mod rcc;
16#[cfg(feature = "_rng")] 17#[cfg(feature = "_rng")]
17pub mod rng; 18pub mod rng;
18#[cfg(feature = "_sdmmc")] 19#[cfg(feature = "_sdmmc")]
@@ -23,8 +24,7 @@ pub mod spi;
23pub mod usart; 24pub mod usart;
24 25
25// This must go LAST so that it sees the `impl_foo!` macros 26// This must go LAST so that it sees the `impl_foo!` macros
26mod pac; 27pub mod pac;
27
28pub mod time; 28pub mod time;
29 29
30pub use embassy_macros::interrupt; 30pub use embassy_macros::interrupt;
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs
new file mode 100644
index 000000000..69b9c79a9
--- /dev/null
+++ b/embassy-stm32/src/rcc/h7/mod.rs
@@ -0,0 +1,27 @@
1use crate::pac::RCC;
2
3mod pll;
4pub use pll::PllConfig;
5
6const HSI: u32 = 64_000_000; // Hz
7const CSI: u32 = 4_000_000; // Hz
8const HSI48: u32 = 48_000_000; // Hz
9const LSI: u32 = 32_000; // Hz
10
11/// Configuration of the core clocks
12#[non_exhaustive]
13#[derive(Default)]
14pub struct Config {
15 pub hse: Option<u32>,
16 pub bypass_hse: bool,
17 pub sys_ck: Option<u32>,
18 pub per_ck: Option<u32>,
19 pub hclk: Option<u32>,
20 pub pclk1: Option<u32>,
21 pub pclk2: Option<u32>,
22 pub pclk3: Option<u32>,
23 pub pclk4: Option<u32>,
24 pub pll1: PllConfig,
25 pub pll2: PllConfig,
26 pub pll3: PllConfig,
27}
diff --git a/embassy-stm32/src/rcc/h7/pll.rs b/embassy-stm32/src/rcc/h7/pll.rs
new file mode 100644
index 000000000..37bd611cc
--- /dev/null
+++ b/embassy-stm32/src/rcc/h7/pll.rs
@@ -0,0 +1,150 @@
1use super::{Config, HSI, RCC};
2use crate::fmt::assert;
3
4const VCO_MIN: u32 = 150_000_000;
5const VCO_MAX: u32 = 420_000_000;
6
7#[derive(Default)]
8pub struct PllConfig {
9 pub p_ck: Option<u32>,
10 pub q_ck: Option<u32>,
11 pub r_ck: Option<u32>,
12}
13
14pub(super) struct PllConfigResults {
15 pub ref_x_ck: u32,
16 pub pll_x_m: u32,
17 pub pll_x_p: u32,
18 pub vco_ck_target: u32,
19}
20
21fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
22 let pll_x_p = if plln == 0 {
23 if output > VCO_MAX / 2 {
24 1
25 } else {
26 ((VCO_MAX / output) | 1) - 1 // Must be even or unity
27 }
28 } else {
29 // Specific to PLL2/3, will subtract 1 later
30 if output > VCO_MAX / 2 {
31 1
32 } else {
33 VCO_MAX / output
34 }
35 };
36
37 let vco_ck = output + pll_x_p;
38
39 assert!(pll_x_p < 128);
40 assert!(vco_ck >= VCO_MIN);
41 assert!(vco_ck <= VCO_MAX);
42
43 (vco_ck, pll_x_p)
44}
45
46/// # Safety
47///
48/// Must have exclusive access to the RCC register block
49unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
50 use crate::pac::rcc::vals::{Pll1rge, Pll1vcosel};
51
52 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
53
54 // Input divisor, resulting in a reference clock in the range
55 // 1 to 2 MHz. Choose the highest reference clock (lowest m)
56 let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
57 assert!(pll_x_m < 64);
58
59 // Calculate resulting reference clock
60 let ref_x_ck = pll_src / pll_x_m;
61 assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
62
63 RCC.pllcfgr().modify(|w| {
64 w.set_pllvcosel(plln, Pll1vcosel::MEDIUMVCO);
65 w.set_pllrge(plln, Pll1rge::RANGE1);
66 });
67 PllConfigResults {
68 ref_x_ck,
69 pll_x_m,
70 pll_x_p,
71 vco_ck_target,
72 }
73}
74
75/// # Safety
76///
77/// Must have exclusive access to the RCC register block
78pub(super) unsafe fn pll_setup(
79 pll_src: u32,
80 config: &PllConfig,
81 plln: usize,
82) -> (Option<u32>, Option<u32>, Option<u32>) {
83 use crate::pac::rcc::vals::{Divp1, Divp1en, Pll1fracen};
84
85 match config.p_ck {
86 Some(requested_output) => {
87 let config_results = vco_setup(pll_src, requested_output, plln);
88 let PllConfigResults {
89 ref_x_ck,
90 pll_x_m,
91 pll_x_p,
92 vco_ck_target,
93 } = config_results;
94
95 RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
96
97 // Feedback divider. Integer only
98 let pll_x_n = vco_ck_target / ref_x_ck;
99 assert!(pll_x_n >= 4);
100 assert!(pll_x_n <= 512);
101 RCC.plldivr(plln)
102 .modify(|w| w.set_divn1((pll_x_n - 1) as u16));
103
104 // No FRACN
105 RCC.pllcfgr()
106 .modify(|w| w.set_pllfracen(plln, Pll1fracen::RESET));
107 let vco_ck = ref_x_ck * pll_x_n;
108
109 RCC.plldivr(plln)
110 .modify(|w| w.set_divp1(Divp1((pll_x_p - 1) as u8)));
111 RCC.pllcfgr()
112 .modify(|w| w.set_divpen(plln, Divp1en::ENABLED));
113
114 // Calulate additional output dividers
115 let q_ck = match config.q_ck {
116 Some(ck) if ck > 0 => {
117 let div = (vco_ck + ck - 1) / ck;
118 RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
119 RCC.pllcfgr()
120 .modify(|w| w.set_divqen(plln, Divp1en::ENABLED));
121 Some(vco_ck / div)
122 }
123 _ => None,
124 };
125 let r_ck = match config.r_ck {
126 Some(ck) if ck > 0 => {
127 let div = (vco_ck + ck - 1) / ck;
128 RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
129 RCC.pllcfgr()
130 .modify(|w| w.set_divren(plln, Divp1en::ENABLED));
131 Some(vco_ck / div)
132 }
133 _ => None,
134 };
135
136 (Some(vco_ck / pll_x_p), q_ck, r_ck)
137 }
138 None => {
139 assert!(
140 config.q_ck.is_none(),
141 "Must set PLL P clock for Q clock to take effect!"
142 );
143 assert!(
144 config.r_ck.is_none(),
145 "Must set PLL P clock for R clock to take effect!"
146 );
147 (None, None, None)
148 }
149 }
150}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
new file mode 100644
index 000000000..0bf62ef7c
--- /dev/null
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -0,0 +1,4 @@
1#[cfg(feature = "_stm32h7")]
2mod h7;
3#[cfg(feature = "_stm32h7")]
4pub use h7::*;