Add set_config method to RP SPI driver

Add a `set_config` method to `Spi` to allow reconfiguring SPI mode after creation.

The existing implementation of the `embassy-embedded-hal` trait `SetConfig` is changed to use the new method.

Existing uses of `SetConfig`  trait may need to explicitly call the trait method to maintain current return type.
This commit is contained in:
dstric-aqueduct 2024-10-15 11:48:54 -04:00 committed by djstrickland
parent e350ca836a
commit 96362b33e8
2 changed files with 35 additions and 19 deletions

View File

@ -84,16 +84,9 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
) -> Self {
into_ref!(inner);
let p = inner.regs();
let (presc, postdiv) = calc_prescs(config.frequency);
Self::apply_config(&inner, &config);
p.cpsr().write(|w| w.set_cpsdvsr(presc));
p.cr0().write(|w| {
w.set_dss(0b0111); // 8bit
w.set_spo(config.polarity == Polarity::IdleHigh);
w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
w.set_scr(postdiv);
});
let p = inner.regs();
// Always enable DREQ signals -- harmless if DMA is not listening
p.dmacr().write(|reg| {
@ -164,6 +157,23 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
}
}
/// Private function to apply SPI configuration (phase, polarity, frequency) settings.
///
/// Driver should be disabled before making changes and reenabled after the modifications
/// are applied.
fn apply_config(inner: &PeripheralRef<'d, T>, config: &Config) {
let p = inner.regs();
let (presc, postdiv) = calc_prescs(config.frequency);
p.cpsr().write(|w| w.set_cpsdvsr(presc));
p.cr0().write(|w| {
w.set_dss(0b0111); // 8bit
w.set_spo(config.polarity == Polarity::IdleHigh);
w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
w.set_scr(postdiv);
});
}
/// Write data to SPI blocking execution until done.
pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
let p = self.inner.regs();
@ -244,6 +254,20 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
// enable
p.cr1().write(|w| w.set_sse(true));
}
/// Set SPI config.
pub fn set_config(&mut self, config: &Config) {
let p = self.inner.regs();
// disable
p.cr1().write(|w| w.set_sse(false));
// change stuff
Self::apply_config(&self.inner, config);
// enable
p.cr1().write(|w| w.set_sse(true));
}
}
impl<'d, T: Instance> Spi<'d, T, Blocking> {
@ -696,15 +720,7 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
type Config = Config;
type ConfigError = ();
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
let p = self.inner.regs();
let (presc, postdiv) = calc_prescs(config.frequency);
p.cpsr().write(|w| w.set_cpsdvsr(presc));
p.cr0().write(|w| {
w.set_dss(0b0111); // 8bit
w.set_spo(config.polarity == Polarity::IdleHigh);
w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
w.set_scr(postdiv);
});
self.set_config(config);
Ok(())
}

View File

@ -56,7 +56,7 @@ async fn main(_spawner: Spawner) {
// Now that the card is initialized, the SPI clock can go faster
let mut config = spi::Config::default();
config.frequency = 16_000_000;
sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok();
sdcard.spi(|dev| SetConfig::set_config(dev.bus_mut(), &config)).ok();
// Now let's look for volumes (also known as partitions) on our block device.
// To do this we need a Volume Manager. It will take ownership of the block device.