embedded_sdmmc/
sdmmc.rs

1//! embedded-sdmmc-rs - SDMMC Protocol
2//!
3//! Implements the SD/MMC protocol on some generic SPI interface.
4//!
5//! This is currently optimised for readability and debugability, not
6//! performance.
7
8use super::sdmmc_proto::*;
9use super::{Block, BlockCount, BlockDevice, BlockIdx};
10use core::cell::RefCell;
11use nb::block;
12
13const DEFAULT_DELAY_COUNT: u32 = 32_000;
14
15/// Represents an SD Card interface built from an SPI peripheral and a Chip
16/// Select pin. We need Chip Select to be separate so we can clock out some
17/// bytes without Chip Select asserted (which puts the card into SPI mode).
18pub struct SdMmcSpi<SPI, CS>
19where
20    SPI: embedded_hal::spi::FullDuplex<u8>,
21    CS: embedded_hal::digital::v2::OutputPin,
22    <SPI as embedded_hal::spi::FullDuplex<u8>>::Error: core::fmt::Debug,
23{
24    spi: RefCell<SPI>,
25    cs: RefCell<CS>,
26    card_type: CardType,
27    state: State,
28}
29
30/// The possible errors `SdMmcSpi` can generate.
31#[derive(Debug, Copy, Clone)]
32pub enum Error {
33    /// We got an error from the SPI peripheral
34    Transport,
35    /// We failed to enable CRC checking on the SD card
36    CantEnableCRC,
37    /// We didn't get a response when reading data from the card
38    TimeoutReadBuffer,
39    /// We didn't get a response when waiting for the card to not be busy
40    TimeoutWaitNotBusy,
41    /// We didn't get a response when executing this command
42    TimeoutCommand(u8),
43    /// We didn't get a response when executing this application-specific command
44    TimeoutACommand(u8),
45    /// We got a bad response from Command 58
46    Cmd58Error,
47    /// We failed to read the Card Specific Data register
48    RegisterReadError,
49    /// We got a CRC mismatch (card gave us, we calculated)
50    CrcError(u16, u16),
51    /// Error reading from the card
52    ReadError,
53    /// Error writing to the card
54    WriteError,
55    /// Can't perform this operation with the card in this state
56    BadState,
57    /// Couldn't find the card
58    CardNotFound,
59    /// Couldn't set a GPIO pin
60    GpioError,
61}
62
63/// The possible states `SdMmcSpi` can be in.
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65pub enum State {
66    NoInit,
67    Error,
68    Idle,
69}
70
71/// The different types of card we support.
72#[derive(Debug, Copy, Clone, PartialEq)]
73enum CardType {
74    SD1,
75    SD2,
76    SDHC,
77}
78
79/// A terrible hack for busy-waiting the CPU while we wait for the card to
80/// sort itself out.
81///
82/// @TODO replace this!
83struct Delay(u32);
84
85impl Delay {
86    fn new() -> Delay {
87        Delay(DEFAULT_DELAY_COUNT)
88    }
89
90    fn delay(&mut self, err: Error) -> Result<(), Error> {
91        if self.0 == 0 {
92            Err(err)
93        } else {
94            let dummy_var: u32 = 0;
95            for _ in 0..100 {
96                unsafe { core::ptr::read_volatile(&dummy_var) };
97            }
98            self.0 -= 1;
99            Ok(())
100        }
101    }
102}
103
104impl<SPI, CS> SdMmcSpi<SPI, CS>
105where
106    SPI: embedded_hal::spi::FullDuplex<u8>,
107    CS: embedded_hal::digital::v2::OutputPin,
108    <SPI as embedded_hal::spi::FullDuplex<u8>>::Error: core::fmt::Debug,
109{
110    /// Create a new SD/MMC controller using a raw SPI interface.
111    pub fn new(spi: SPI, cs: CS) -> SdMmcSpi<SPI, CS> {
112        SdMmcSpi {
113            spi: RefCell::new(spi),
114            cs: RefCell::new(cs),
115            card_type: CardType::SD1,
116            state: State::NoInit,
117        }
118    }
119
120    /// Get a temporary borrow on the underlying SPI device. Useful if you
121    /// need to re-clock the SPI after performing `init()`.
122    pub fn spi(&mut self) -> core::cell::RefMut<SPI> {
123        self.spi.borrow_mut()
124    }
125
126    fn cs_high(&self) -> Result<(), Error> {
127        self.cs
128            .borrow_mut()
129            .set_high()
130            .map_err(|_| Error::GpioError)
131    }
132
133    fn cs_low(&self) -> Result<(), Error> {
134        self.cs.borrow_mut().set_low().map_err(|_| Error::GpioError)
135    }
136
137    /// This routine must be performed with an SPI clock speed of around 100 - 400 kHz.
138    /// Afterwards you may increase the SPI clock speed.
139    pub fn init(&mut self) -> Result<(), Error> {
140        let f = |s: &mut Self| {
141            // Assume it hasn't worked
142            s.state = State::Error;
143            // Supply minimum of 74 clock cycles without CS asserted.
144            s.cs_high()?;
145            for _ in 0..10 {
146                s.send(0xFF)?;
147            }
148            // Assert CS
149            s.cs_low()?;
150            // Enter SPI mode
151            let mut attempts = 32;
152            while attempts > 0 {
153                match s.card_command(CMD0, 0) {
154                    Err(Error::TimeoutCommand(0)) => {
155                        // Try again?
156                        attempts -= 1;
157                    }
158                    Err(e) => {
159                        return Err(e);
160                    }
161                    Ok(R1_IDLE_STATE) => {
162                        break;
163                    }
164                    Ok(_) => {
165                        // Try again
166                    }
167                }
168            }
169            if attempts == 0 {
170                return Err(Error::CardNotFound);
171            }
172            // Enable CRC
173            if s.card_command(CMD59, 1)? != R1_IDLE_STATE {
174                return Err(Error::CantEnableCRC);
175            }
176            // Check card version
177            let mut delay = Delay::new();
178            loop {
179                if s.card_command(CMD8, 0x1AA)? == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE) {
180                    s.card_type = CardType::SD1;
181                    break;
182                }
183                s.receive()?;
184                s.receive()?;
185                s.receive()?;
186                let status = s.receive()?;
187                if status == 0xAA {
188                    s.card_type = CardType::SD2;
189                    break;
190                }
191                delay.delay(Error::TimeoutCommand(CMD8))?;
192            }
193
194            let arg = match s.card_type {
195                CardType::SD1 => 0,
196                CardType::SD2 | CardType::SDHC => 0x4000_0000,
197            };
198
199            let mut delay = Delay::new();
200            while s.card_acmd(ACMD41, arg)? != R1_READY_STATE {
201                delay.delay(Error::TimeoutACommand(ACMD41))?;
202            }
203
204            if s.card_type == CardType::SD2 {
205                if s.card_command(CMD58, 0)? != 0 {
206                    return Err(Error::Cmd58Error);
207                }
208                if (s.receive()? & 0xC0) == 0xC0 {
209                    s.card_type = CardType::SDHC;
210                }
211                // Discard other three bytes
212                s.receive()?;
213                s.receive()?;
214                s.receive()?;
215            }
216            s.state = State::Idle;
217            Ok(())
218        };
219        let result = f(self);
220        self.cs_high()?;
221        let _ = self.receive();
222        result
223    }
224
225    /// De-init the card so it can't be used
226    pub fn deinit(&mut self) {
227        self.state = State::NoInit;
228    }
229
230    /// Return the usable size of this SD card in bytes.
231    pub fn card_size_bytes(&self) -> Result<u64, Error> {
232        self.check_state()?;
233        self.with_chip_select(|s| {
234            let csd = s.read_csd()?;
235            match csd {
236                Csd::V1(ref contents) => Ok(contents.card_capacity_bytes()),
237                Csd::V2(ref contents) => Ok(contents.card_capacity_bytes()),
238            }
239        })
240    }
241
242    /// Erase some blocks on the card.
243    pub fn erase(&mut self, _first_block: BlockIdx, _last_block: BlockIdx) -> Result<(), Error> {
244        self.check_state()?;
245        unimplemented!();
246    }
247
248    /// Can this card erase single blocks?
249    pub fn erase_single_block_enabled(&self) -> Result<bool, Error> {
250        self.check_state()?;
251        self.with_chip_select(|s| {
252            let csd = s.read_csd()?;
253            match csd {
254                Csd::V1(ref contents) => Ok(contents.erase_single_block_enabled()),
255                Csd::V2(ref contents) => Ok(contents.erase_single_block_enabled()),
256            }
257        })
258    }
259
260    /// Return an error if we're not in  `State::Idle`. It probably means
261    /// they haven't called `begin()`.
262    fn check_state(&self) -> Result<(), Error> {
263        if self.state != State::Idle {
264            Err(Error::BadState)
265        } else {
266            Ok(())
267        }
268    }
269
270    /// Perform a function that might error with the chipselect low.
271    /// Always releases the chipselect, even if the function errors.
272    fn with_chip_select_mut<F, T>(&self, func: F) -> Result<T, Error>
273    where
274        F: FnOnce(&Self) -> Result<T, Error>,
275    {
276        self.cs_low()?;
277        let result = func(self);
278        self.cs_high()?;
279        result
280    }
281
282    /// Perform a function that might error with the chipselect low.
283    /// Always releases the chipselect, even if the function errors.
284    fn with_chip_select<F, T>(&self, func: F) -> Result<T, Error>
285    where
286        F: FnOnce(&Self) -> Result<T, Error>,
287    {
288        self.cs_low()?;
289        let result = func(self);
290        self.cs_high()?;
291        result
292    }
293
294    /// Read the 'card specific data' block.
295    fn read_csd(&self) -> Result<Csd, Error> {
296        match self.card_type {
297            CardType::SD1 => {
298                let mut csd = CsdV1::new();
299                if self.card_command(CMD9, 0)? != 0 {
300                    return Err(Error::RegisterReadError);
301                }
302                self.read_data(&mut csd.data)?;
303                Ok(Csd::V1(csd))
304            }
305            CardType::SD2 | CardType::SDHC => {
306                let mut csd = CsdV2::new();
307                if self.card_command(CMD9, 0)? != 0 {
308                    return Err(Error::RegisterReadError);
309                }
310                self.read_data(&mut csd.data)?;
311                Ok(Csd::V2(csd))
312            }
313        }
314    }
315
316    /// Read an arbitrary number of bytes from the card. Always fills the
317    /// given buffer, so make sure it's the right size.
318    fn read_data(&self, buffer: &mut [u8]) -> Result<(), Error> {
319        // Get first non-FF byte.
320        let mut delay = Delay::new();
321        let status = loop {
322            let s = self.receive()?;
323            if s != 0xFF {
324                break s;
325            }
326            delay.delay(Error::TimeoutReadBuffer)?;
327        };
328        if status != DATA_START_BLOCK {
329            return Err(Error::ReadError);
330        }
331
332        for b in buffer.iter_mut() {
333            *b = self.receive()?;
334        }
335
336        let mut crc = u16::from(self.receive()?);
337        crc <<= 8;
338        crc |= u16::from(self.receive()?);
339
340        let calc_crc = crc16(buffer);
341        if crc != calc_crc {
342            return Err(Error::CrcError(crc, calc_crc));
343        }
344
345        Ok(())
346    }
347
348    /// Write an arbitrary number of bytes to the card.
349    fn write_data(&self, token: u8, buffer: &[u8]) -> Result<(), Error> {
350        let calc_crc = crc16(buffer);
351        self.send(token)?;
352        for &b in buffer.iter() {
353            self.send(b)?;
354        }
355        self.send((calc_crc >> 8) as u8)?;
356        self.send(calc_crc as u8)?;
357        let status = self.receive()?;
358        if (status & DATA_RES_MASK) != DATA_RES_ACCEPTED {
359            Err(Error::WriteError)
360        } else {
361            Ok(())
362        }
363    }
364
365    /// Perform an application-specific command.
366    fn card_acmd(&self, command: u8, arg: u32) -> Result<u8, Error> {
367        self.card_command(CMD55, 0)?;
368        self.card_command(command, arg)
369    }
370
371    /// Perform a command.
372    fn card_command(&self, command: u8, arg: u32) -> Result<u8, Error> {
373        self.wait_not_busy()?;
374        let mut buf = [
375            0x40 | command,
376            (arg >> 24) as u8,
377            (arg >> 16) as u8,
378            (arg >> 8) as u8,
379            arg as u8,
380            0,
381        ];
382        buf[5] = crc7(&buf[0..5]);
383
384        for b in buf.iter() {
385            self.send(*b)?;
386        }
387
388        // skip stuff byte for stop read
389        if command == CMD12 {
390            let _result = self.receive()?;
391        }
392
393        for _ in 0..512 {
394            let result = self.receive()?;
395            if (result & 0x80) == 0 {
396                return Ok(result);
397            }
398        }
399
400        Err(Error::TimeoutCommand(command))
401    }
402
403    /// Receive a byte from the SD card by clocking in an 0xFF byte.
404    fn receive(&self) -> Result<u8, Error> {
405        self.transfer(0xFF)
406    }
407
408    /// Send a byte from the SD card.
409    fn send(&self, out: u8) -> Result<(), Error> {
410        let _ = self.transfer(out)?;
411        Ok(())
412    }
413
414    /// Send one byte and receive one byte.
415    fn transfer(&self, out: u8) -> Result<u8, Error> {
416        let mut spi = self.spi.borrow_mut();
417        block!(spi.send(out)).map_err(|_e| Error::Transport)?;
418        block!(spi.read()).map_err(|_e| Error::Transport)
419    }
420
421    /// Spin until the card returns 0xFF, or we spin too many times and
422    /// timeout.
423    fn wait_not_busy(&self) -> Result<(), Error> {
424        let mut delay = Delay::new();
425        loop {
426            let s = self.receive()?;
427            if s == 0xFF {
428                break;
429            }
430            delay.delay(Error::TimeoutWaitNotBusy)?;
431        }
432        Ok(())
433    }
434}
435
436impl<SPI, CS> BlockDevice for SdMmcSpi<SPI, CS>
437where
438    SPI: embedded_hal::spi::FullDuplex<u8>,
439    <SPI as embedded_hal::spi::FullDuplex<u8>>::Error: core::fmt::Debug,
440    CS: embedded_hal::digital::v2::OutputPin,
441{
442    type Error = Error;
443
444    /// Read one or more blocks, starting at the given block index.
445    fn read(
446        &self,
447        blocks: &mut [Block],
448        start_block_idx: BlockIdx,
449        _reason: &str,
450    ) -> Result<(), Self::Error> {
451        self.check_state()?;
452        let start_idx = match self.card_type {
453            CardType::SD1 | CardType::SD2 => start_block_idx.0 * 512,
454            CardType::SDHC => start_block_idx.0,
455        };
456        self.with_chip_select(|s| {
457            if blocks.len() == 1 {
458                // Start a single-block read
459                s.card_command(CMD17, start_idx)?;
460                s.read_data(&mut blocks[0].contents)?;
461            } else {
462                // Start a multi-block read
463                s.card_command(CMD18, start_idx)?;
464                for block in blocks.iter_mut() {
465                    s.read_data(&mut block.contents)?;
466                }
467                // Stop the read
468                s.card_command(CMD12, 0)?;
469            }
470            Ok(())
471        })
472    }
473
474    /// Write one or more blocks, starting at the given block index.
475    fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
476        self.check_state()?;
477        let start_idx = match self.card_type {
478            CardType::SD1 | CardType::SD2 => start_block_idx.0 * 512,
479            CardType::SDHC => start_block_idx.0,
480        };
481        self.with_chip_select_mut(|s| {
482            if blocks.len() == 1 {
483                // Start a single-block write
484                s.card_command(CMD24, start_idx)?;
485                s.write_data(DATA_START_BLOCK, &blocks[0].contents)?;
486                s.wait_not_busy()?;
487                if s.card_command(CMD13, 0)? != 0x00 {
488                    return Err(Error::WriteError);
489                }
490                if s.receive()? != 0x00 {
491                    return Err(Error::WriteError);
492                }
493            } else {
494                // Start a multi-block write
495                s.card_command(CMD25, start_idx)?;
496                for block in blocks.iter() {
497                    s.wait_not_busy()?;
498                    s.write_data(WRITE_MULTIPLE_TOKEN, &block.contents)?;
499                }
500                // Stop the write
501                s.wait_not_busy()?;
502                s.send(STOP_TRAN_TOKEN)?;
503            }
504            Ok(())
505        })
506    }
507
508    /// Determine how many blocks this device can hold.
509    fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
510        let num_bytes = self.card_size_bytes()?;
511        let num_blocks = (num_bytes / 512) as u32;
512        Ok(BlockCount(num_blocks))
513    }
514}
515
516// ****************************************************************************
517//
518// End Of File
519//
520// ****************************************************************************