From d9e693d37c0499b3815fab3c4fbaf6269b13de30 Mon Sep 17 00:00:00 2001 From: Andelf Date: Fri, 20 Dec 2024 03:13:54 +0800 Subject: [PATCH] enhance(spi): impl half-duplex spi --- examples/hpm5300evk/src/bin/qspi.rs | 14 +++--- src/spi/mod.rs | 72 ++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/examples/hpm5300evk/src/bin/qspi.rs b/examples/hpm5300evk/src/bin/qspi.rs index 2db0664..f56d645 100644 --- a/examples/hpm5300evk/src/bin/qspi.rs +++ b/examples/hpm5300evk/src/bin/qspi.rs @@ -282,14 +282,12 @@ fn main() -> ! { // PA10 let mut led = Output::new(p.PA10, Level::Low, Speed::Fast); - let spi_config = Config { - frequency: Hertz(40_000_000), - mode: MODE_0, - timing: Timings { - cs2sclk: hpm_hal::spi::Cs2Sclk::_1HalfSclk, - csht: hpm_hal::spi::CsHighTime::_8HalfSclk, - }, - ..Default::default() + let mut spi_config = Config::default(); + spi_config.frequency = Hertz(40_000_000); + spi_config.mode = MODE_0; + spi_config.timing = Timings { + cs2sclk: hpm_hal::spi::Cs2Sclk::_1HalfSclk, + csht: hpm_hal::spi::CsHighTime::_8HalfSclk, }; let spi: hal::spi::Spi<'_, Blocking> = diff --git a/src/spi/mod.rs b/src/spi/mod.rs index 80e5f3a..48eace7 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -142,6 +142,8 @@ pub struct Config { pub frequency: Hertz, /// Timings pub timing: Timings, + /// Half duplex mode, only MOSI is used. + pub half_duplex: bool, } impl Default for Config { @@ -151,6 +153,7 @@ impl Default for Config { mode: MODE_0, frequency: Hertz(10_000_000), timing: Timings::default(), + half_duplex: false, } } } @@ -253,6 +256,36 @@ impl<'d> Spi<'d, Blocking> { ) } + pub fn new_blocking_half_duplex( + peri: impl Peripheral

+ 'd, + sclk: impl Peripheral

> + 'd, + mosi: impl Peripheral

> + 'd, + mut config: Config, + ) -> Self { + into_ref!(sclk, mosi); + + T::add_resource_group(0); + + mosi.set_as_alt(mosi.alt_num()); + sclk.ioc_pad().func_ctl().modify(|w| { + w.set_alt_select(sclk.alt_num()); + w.set_loop_back(true); + }); + config.half_duplex = true; + + Self::new_inner( + peri, + Some(sclk.map_into()), + Some(mosi.map_into()), + None, + None, + None, + None, + None, + config, + ) + } + pub fn new_blocking_rxonly( peri: impl Peripheral

+ 'd, sclk: impl Peripheral

> + 'd, @@ -406,6 +439,39 @@ impl<'d> Spi<'d, Async> { ) } + pub fn new_half_duplex( + peri: impl Peripheral

+ 'd, + sclk: impl Peripheral

> + 'd, + mosi: impl Peripheral

> + 'd, + tx_dma: impl Peripheral

> + 'd, + rx_dma: impl Peripheral

> + 'd, + mut config: Config, + ) -> Self { + into_ref!(sclk, mosi); + + T::add_resource_group(0); + + mosi.set_as_alt(mosi.alt_num()); + sclk.ioc_pad().func_ctl().modify(|w| { + w.set_alt_select(sclk.alt_num()); + w.set_loop_back(true); + }); + + config.half_duplex = true; + + Self::new_inner( + peri, + Some(sclk.map_into()), + Some(mosi.map_into()), + None, + None, + None, + new_dma!(tx_dma), + new_dma!(rx_dma), + config, + ) + } + pub fn new_rxonly( peri: impl Peripheral

+ 'd, sclk: impl Peripheral

> + 'd, @@ -690,7 +756,11 @@ impl<'d, M: PeriMode> Spi<'d, M> { // 32 bit data length only works when the data is 32bit aligned w.set_datalen(::CONFIG); w.set_datamerge(false); - w.set_mosibidir(false); + if config.half_duplex { + w.set_mosibidir(true); + } else { + w.set_mosibidir(false); + } w.set_lsb(config.bit_order == BitOrder::LsbFirst); w.set_slvmode(false); // default master mode w.set_cpha(cpha);