diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-07-12 02:45:59 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-07-12 03:45:57 +0200 |
| commit | 1a4c13cf262869d88a38575eb14abd09900e8e01 (patch) | |
| tree | c96a99138be33048dc73b1c04c6a2532bf11d3ad | |
| parent | 7547c8d8d6800dd661dcda9f62ba988eefadd38e (diff) | |
rp/spi: add set_frequency
| -rw-r--r-- | embassy-rp/src/spi.rs | 75 |
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 | ||
| 36 | fn div_roundup(a: u32, b: u32) -> u32 { | ||
| 37 | (a + b - 1) / b | ||
| 38 | } | ||
| 39 | |||
| 40 | fn 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 | |||
| 36 | impl<'d, T: Instance> Spi<'d, T> { | 63 | impl<'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 | ||
| 144 | impl<'d, T: Instance> eh::Write<u8> for Spi<'d, T> { | 151 | impl<'d, T: Instance> eh::Write<u8> for Spi<'d, T> { |
