diff options
| -rw-r--r-- | embassy-rp/src/spi.rs | 46 |
1 files changed, 27 insertions, 19 deletions
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 3316d248a..6c3aabfbe 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs | |||
| @@ -50,26 +50,36 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 50 | let clk_peri = crate::clocks::clk_peri_freq(); | 50 | let clk_peri = crate::clocks::clk_peri_freq(); |
| 51 | assert!(config.frequency <= clk_peri); | 51 | assert!(config.frequency <= clk_peri); |
| 52 | 52 | ||
| 53 | // TODO replace these trial-and-error loops with decent calculations. | 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 | ||
| 54 | 56 | ||
| 55 | // Find smallest prescale value which puts output frequency in range of | 57 | fn div_roundup(a: u32, b: u32) -> u32 { |
| 56 | // post-divide. Prescale is an even number from 2 to 254 inclusive. | 58 | (a + b - 1) / b |
| 57 | let presc = (2u32..=254).step_by(2).find(|&presc| { | 59 | } |
| 58 | (clk_peri as u64) < (presc as u64 + 2) * 256 * config.frequency as u64 | ||
| 59 | }); | ||
| 60 | |||
| 61 | // if this fails, frequency is too low. | ||
| 62 | let presc = unwrap!(presc); | ||
| 63 | 60 | ||
| 64 | // Find largest post-divide which makes output <= baudrate. Post-divide is | 61 | // divide extra by 2, so we get rid of the "presc must be even" requirement |
| 65 | // an integer in the range 1 to 256 inclusive. | 62 | let ratio = div_roundup(clk_peri, config.frequency * 2); |
| 66 | // TODO figure what's up with postdiv=1, it is dividing by 0. Iterate down to 2 for now. | 63 | if ratio > 127 * 256 { |
| 67 | let postdiv = (2u32..=256) | 64 | panic!("Requested too low SPI frequency"); |
| 68 | .rev() | 65 | } |
| 69 | .find(|&postdiv| clk_peri / (presc * (postdiv - 1)) > config.frequency); | ||
| 70 | let postdiv = unwrap!(postdiv); | ||
| 71 | 66 | ||
| 72 | p.cpsr().write(|w| w.set_cpsdvsr(presc as _)); | 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 _)); | ||
| 73 | p.cr0().write(|w| { | 83 | p.cr0().write(|w| { |
| 74 | w.set_dss(0b0111); // 8bit | 84 | w.set_dss(0b0111); // 8bit |
| 75 | w.set_spo(config.polarity == ehnb::Polarity::IdleHigh); | 85 | w.set_spo(config.polarity == ehnb::Polarity::IdleHigh); |
| @@ -80,8 +90,6 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 80 | w.set_sse(true); // enable | 90 | w.set_sse(true); // enable |
| 81 | }); | 91 | }); |
| 82 | 92 | ||
| 83 | info!("SPI freq: {=u32}", clk_peri / (presc * postdiv)); | ||
| 84 | |||
| 85 | if let Some(pin) = clk.pin_mut() { | 93 | if let Some(pin) = clk.pin_mut() { |
| 86 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 94 | pin.io().ctrl().write(|w| w.set_funcsel(1)); |
| 87 | } | 95 | } |
