aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-07-12 02:45:59 +0200
committerDario Nieuwenhuis <[email protected]>2021-07-12 03:45:57 +0200
commit1a4c13cf262869d88a38575eb14abd09900e8e01 (patch)
treec96a99138be33048dc73b1c04c6a2532bf11d3ad
parent7547c8d8d6800dd661dcda9f62ba988eefadd38e (diff)
rp/spi: add set_frequency
-rw-r--r--embassy-rp/src/spi.rs75
1 files changed, 41 insertions, 34 deletions
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 6c3aabfbe..ec2437e93 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -33,6 +33,33 @@ pub struct Spi<'d, T: Instance> {
33 phantom: PhantomData<&'d mut T>, 33 phantom: PhantomData<&'d mut T>,
34} 34}
35 35
36fn div_roundup(a: u32, b: u32) -> u32 {
37 (a + b - 1) / b
38}
39
40fn calc_prescs(freq: u32) -> (u8, u8) {
41 let clk_peri = crate::clocks::clk_peri_freq();
42
43 // final SPI frequency: spi_freq = clk_peri / presc / postdiv
44 // presc must be in 2..=254, and must be even
45 // postdiv must be in 1..=256
46
47 // divide extra by 2, so we get rid of the "presc must be even" requirement
48 let ratio = div_roundup(clk_peri, freq * 2);
49 if ratio > 127 * 256 {
50 panic!("Requested too low SPI frequency");
51 }
52
53 let presc = div_roundup(ratio, 256);
54 let postdiv = if presc == 1 {
55 ratio
56 } else {
57 div_roundup(ratio, presc)
58 };
59
60 ((presc * 2) as u8, (postdiv - 1) as u8)
61}
62
36impl<'d, T: Instance> Spi<'d, T> { 63impl<'d, T: Instance> Spi<'d, T> {
37 pub fn new( 64 pub fn new(
38 inner: impl Unborrow<Target = T>, 65 inner: impl Unborrow<Target = T>,
@@ -46,45 +73,14 @@ impl<'d, T: Instance> Spi<'d, T> {
46 73
47 unsafe { 74 unsafe {
48 let p = inner.regs(); 75 let p = inner.regs();
76 let (presc, postdiv) = calc_prescs(config.frequency);
49 77
50 let clk_peri = crate::clocks::clk_peri_freq(); 78 p.cpsr().write(|w| w.set_cpsdvsr(presc));
51 assert!(config.frequency <= clk_peri);
52
53 // final SPI frequency: spi_freq = clk_peri / presc / postdiv
54 // presc must be in 2..=254, and must be even
55 // postdiv must be in 1..=256
56
57 fn div_roundup(a: u32, b: u32) -> u32 {
58 (a + b - 1) / b
59 }
60
61 // divide extra by 2, so we get rid of the "presc must be even" requirement
62 let ratio = div_roundup(clk_peri, config.frequency * 2);
63 if ratio > 127 * 256 {
64 panic!("Requested too low SPI frequency");
65 }
66
67 let presc = div_roundup(ratio, 256);
68 let postdiv = if presc == 1 {
69 ratio
70 } else {
71 div_roundup(ratio, presc)
72 };
73
74 debug!(
75 "SPI: requested freq {=u32}, actual freq {=u32}, presc {=u32}, postdiv {=u32}",
76 config.frequency,
77 clk_peri / (presc * 2 * postdiv),
78 presc * 2,
79 postdiv
80 );
81
82 p.cpsr().write(|w| w.set_cpsdvsr((presc * 2) as _));
83 p.cr0().write(|w| { 79 p.cr0().write(|w| {
84 w.set_dss(0b0111); // 8bit 80 w.set_dss(0b0111); // 8bit
85 w.set_spo(config.polarity == ehnb::Polarity::IdleHigh); 81 w.set_spo(config.polarity == ehnb::Polarity::IdleHigh);
86 w.set_sph(config.phase == ehnb::Phase::CaptureOnSecondTransition); 82 w.set_sph(config.phase == ehnb::Phase::CaptureOnSecondTransition);
87 w.set_scr((postdiv - 1) as u8); 83 w.set_scr(postdiv);
88 }); 84 });
89 p.cr1().write(|w| { 85 p.cr1().write(|w| {
90 w.set_sse(true); // enable 86 w.set_sse(true); // enable
@@ -139,6 +135,17 @@ impl<'d, T: Instance> Spi<'d, T> {
139 while p.sr().read().bsy() {} 135 while p.sr().read().bsy() {}
140 } 136 }
141 } 137 }
138
139 pub fn set_frequency(&mut self, freq: u32) {
140 let (presc, postdiv) = calc_prescs(freq);
141 let p = self.inner.regs();
142 unsafe {
143 p.cpsr().write(|w| w.set_cpsdvsr(presc));
144 p.cr0().modify(|w| {
145 w.set_scr(postdiv);
146 });
147 }
148 }
142} 149}
143 150
144impl<'d, T: Instance> eh::Write<u8> for Spi<'d, T> { 151impl<'d, T: Instance> eh::Write<u8> for Spi<'d, T> {