diff --git a/boards/rp-pico/Cargo.toml b/boards/rp-pico/Cargo.toml index 1a5bf84..6f0444d 100644 --- a/boards/rp-pico/Cargo.toml +++ b/boards/rp-pico/Cargo.toml @@ -26,7 +26,7 @@ cortex-m-rtic = "1.1.2" nb = "1.0" i2c-pio = "0.6.0" heapless = "0.7.9" -embedded-sdmmc = "0.4.0" +embedded-sdmmc = "0.5.0" smart-leds = "0.3.0" ws2812-pio = "0.6.0" ssd1306 = "0.7.0" diff --git a/boards/rp-pico/examples/pico_spi_sd_card.rs b/boards/rp-pico/examples/pico_spi_sd_card.rs index c8e5ae3..b42129f 100644 --- a/boards/rp-pico/examples/pico_spi_sd_card.rs +++ b/boards/rp-pico/examples/pico_spi_sd_card.rs @@ -78,10 +78,8 @@ //! If everything is successful (9 long blink signals), the example will go //! into a loop and either blink in a _"short long"_ or _"short short long"_ pattern. //! -//! If there are 5 different error patterns, all with short blinking pulses: +//! If there are 4 different error patterns, all with short blinking pulses: //! -//! - **2 short blink (in a loop)**: Block device could not be acquired, either -//! no SD card is present or some electrical problem. //! - **3 short blink (in a loop)**: Card size could not be retrieved. //! - **4 short blink (in a loop)**: Error getting volume/partition 0. //! - **5 short blink (in a loop)**: Error opening root directory. @@ -92,6 +90,8 @@ #![no_std] #![no_main] +use core::cell::RefCell; + // The macro for our start-up function use rp_pico::entry; @@ -126,11 +126,14 @@ use rp_pico::hal; // Link in the embedded_sdmmc crate. // The `SdMmcSpi` is used for block level access to the card. // And the `Controller` gives access to the FAT filesystem functions. -use embedded_sdmmc::{Controller, SdMmcSpi, TimeSource, Timestamp, VolumeIdx}; +use embedded_sdmmc::{Controller, SdCard, TimeSource, Timestamp, VolumeIdx}; // Get the file open mode enum: use embedded_sdmmc::filesystem::Mode; +use embedded_hal::blocking::delay::DelayMs; +use embedded_hal::blocking::delay::DelayUs; + /// A dummy timesource, which is mostly important for creating files. #[derive(Default)] pub struct DummyTimesource(); @@ -154,7 +157,6 @@ impl TimeSource for DummyTimesource { const BLINK_OK_LONG: [u8; 1] = [8u8]; const BLINK_OK_SHORT_LONG: [u8; 4] = [1u8, 0u8, 6u8, 0u8]; const BLINK_OK_SHORT_SHORT_LONG: [u8; 6] = [1u8, 0u8, 1u8, 0u8, 6u8, 0u8]; -const BLINK_ERR_2_SHORT: [u8; 4] = [1u8, 0u8, 1u8, 0u8]; const BLINK_ERR_3_SHORT: [u8; 6] = [1u8, 0u8, 1u8, 0u8, 1u8, 0u8]; const BLINK_ERR_4_SHORT: [u8; 8] = [1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8]; const BLINK_ERR_5_SHORT: [u8; 10] = [1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8]; @@ -162,7 +164,7 @@ const BLINK_ERR_6_SHORT: [u8; 12] = [1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8 fn blink_signals( pin: &mut dyn embedded_hal::digital::v2::OutputPin, - delay: &mut cortex_m::delay::Delay, + delay: &mut dyn DelayMs, sig: &[u8], ) { for bit in sig { @@ -186,7 +188,7 @@ fn blink_signals( fn blink_signals_loop( pin: &mut dyn embedded_hal::digital::v2::OutputPin, - delay: &mut cortex_m::delay::Delay, + delay: &mut dyn DelayMs, sig: &[u8], ) -> ! { loop { @@ -235,9 +237,6 @@ fn main() -> ! { // Set the LED to be an output let mut led_pin = pins.led.into_push_pull_output(); - // Setup a delay for the LED blink signals: - let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); - // These are implicitly used by the spi driver if they are in the correct mode let _spi_sclk = pins.gpio2.into_mode::(); let _spi_mosi = pins.gpio3.into_mode::(); @@ -251,34 +250,25 @@ fn main() -> ! { let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), - 16_000_000u32.Hz(), + 400.kHz(), // card initialization happens at low baud rate &embedded_hal::spi::MODE_0, ); - info!("Aquire SPI SD/MMC BlockDevice..."); - let mut sdspi = SdMmcSpi::new(spi, spi_cs); + // We need a delay implementation that can be passed to SdCard and still be used + // for the blink signals. + let mut delay = &SharedDelay::new(cortex_m::delay::Delay::new( + core.SYST, + clocks.system_clock.freq().to_Hz(), + )); + + info!("Initialize SPI SD/MMC data structures..."); + let sdcard = SdCard::new(spi, spi_cs, delay); + let mut cont = Controller::new(sdcard, DummyTimesource::default()); blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG); - // Next we need to aquire the block device and initialize the - // communication with the SD card. - let block = match sdspi.acquire() { - Ok(block) => block, - Err(e) => { - error!("Error retrieving card size: {}", defmt::Debug2Format(&e)); - blink_signals_loop(&mut led_pin, &mut delay, &BLINK_ERR_2_SHORT); - } - }; - - blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG); - - info!("Init SD card controller..."); - let mut cont = Controller::new(block, DummyTimesource::default()); - - blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG); - - info!("OK!\nCard size..."); - match cont.device().card_size_bytes() { + info!("Init SD card controller and retrieve card size..."); + match cont.device().num_bytes() { Ok(size) => info!("card size is {} bytes", size), Err(e) => { error!("Error retrieving card size: {}", defmt::Debug2Format(&e)); @@ -288,6 +278,10 @@ fn main() -> ! { blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG); + // Now that the card is initialized, clock can go faster + cont.device() + .spi(|spi| spi.set_baudrate(clocks.peripheral_clock.freq(), 16.MHz())); + info!("Getting Volume 0..."); let mut volume = match cont.get_volume(VolumeIdx(0)) { Ok(v) => v, @@ -379,3 +373,29 @@ fn main() -> ! { delay.delay_ms(1000); } } + +// Can be removed once we have https://github.com/rp-rs/rp-hal/pull/614, +// ie. when we move to rp2040-hal 0.9 +struct SharedDelay { + inner: RefCell, +} + +impl SharedDelay { + fn new(delay: cortex_m::delay::Delay) -> Self { + Self { + inner: delay.into(), + } + } +} + +impl DelayMs for &SharedDelay { + fn delay_ms(&mut self, ms: u32) { + self.inner.borrow_mut().delay_ms(ms); + } +} + +impl DelayUs for &SharedDelay { + fn delay_us(&mut self, us: u8) { + self.inner.borrow_mut().delay_us(us as u32); + } +}