mci_atsamd51/
lib.rs

1#![no_std]
2use atsamd_hal::target_device::SDHC0;
3use bit_field::BitField;
4use core::hint::unreachable_unchecked;
5use embedded_error::mci::CommandOrDataError;
6use embedded_error::mci::MciError;
7use embedded_error::ImplError;
8use mci::command_arguments::mci_command::MciCommand;
9use mci::command_arguments::mmc::BusWidth;
10use mci::mci::Mci;
11
12pub struct AtsamdMci {
13    sdhc: SDHC0,
14    trans_pos: u64,
15    block_size: u16,
16    block_amount: u16,
17}
18
19impl AtsamdMci {
20    pub fn new(sdhc: SDHC0) -> AtsamdMci {
21        AtsamdMci {
22            sdhc,
23            trans_pos: 0,
24            block_size: 0,
25            block_amount: 0,
26        }
27    }
28
29    pub fn reset(&mut self) {
30        self.sdhc.srr.modify(|_, w| w.swrstcmd().set_bit());
31    }
32
33    pub fn wait_busy(&mut self) -> Result<(), MciError> {
34        for n in (0u32..=0xFFFF_FFFFu32).rev() {
35            if n == 0 {
36                self.reset();
37                return Err(MciError::Impl(ImplError::TimedOut));
38            }
39            if self.sdhc.psr.read().datll().bits() == 0x1 {
40                return Ok(());
41            }
42        }
43        unsafe { unreachable_unchecked() }
44    }
45
46    pub fn set_speed(&mut self, speed: u32, prog_clock_mode: u8) {
47        if self.sdhc.ccr.read().sdclken().bit_is_set() {
48            let mut psr = self.sdhc.psr.read();
49            while psr.cmdinhc().bit_is_set() || psr.cmdinhd().bit_is_set() {
50                psr = self.sdhc.psr.read();
51            }
52        }
53        // let clk_base = CONF_BASE_FREQ;
54        let mut clk_base = self.sdhc.ca0r.read().baseclkf().bits();
55        let clk_mult = self.sdhc.ca1r.read().clkmult().bits();
56        let mut div: u32;
57
58        // If programmable clock mode is enabled, baseclk is divided by 2
59        if clk_mult > 0 {
60            clk_base /= 2;
61        }
62
63        if prog_clock_mode == 0 {
64            // divided clock mode
65            self.sdhc.ccr.modify(|_, w| w.clkgsel().clear_bit());
66            div = ((clk_base as u32) / speed) / 2;
67        } else {
68            // programmable clock mode
69            self.sdhc.ccr.modify(|_, w| w.clkgsel().set_bit());
70            // Specific constraint for SDHC/SDMMC IP
71            // speed = Base Clock * Multi Clock / (div+1) */
72            div = ((clk_base as u32) * ((clk_mult as u32) + 1)) / speed;
73            div = if div > 0 { div - 1 } else { div };
74        }
75
76        // Specific constraint for SDHC/SDMMC IP
77        // The clock divider (DIV) in SDMMC_CCR must be set to a value different from 0 when HSEN is 1.
78        div = if self.sdhc.hc1r().read().hsen().bit_is_set() && div == 0 {
79            1
80        } else {
81            div
82        };
83
84        // Set clock divider
85        self.sdhc.ccr.modify(|_, w| unsafe {
86            w.sdclkfsel()
87                .bits(div as u8)
88                .usdclkfsel()
89                .bits((div >> 8) as u8)
90        });
91
92        self.sdhc.ccr.modify(|_, w| w.intclken().set_bit());
93
94        // Repeat this step until Clock Stable is 1
95        while self.sdhc.ccr.read().intclks().bit_is_clear() {}
96
97        // Output the clock to the card -- Set SD Clock Enable
98        self.sdhc.ccr.modify(|_, w| w.sdclken().set_bit());
99    }
100
101    /// Send a command
102    pub fn send_command_execute(
103        &mut self,
104        mut cmdr: u16,
105        cmd: u32,
106        arg: u32,
107    ) -> Result<(), MciError> {
108        cmdr.set_bits(8..16, cmd as u16);
109        let cmd: MciCommand = cmd.into();
110
111        if cmd.have_response() {
112            cmdr.set_bits(
113                0..2,
114                if cmd.have_136bit_response() {
115                    0x1
116                } else if cmd.card_may_send_busy() {
117                    0x3
118                } else {
119                    0x2
120                },
121            );
122        }
123
124        self.sdhc.mc1r.modify(|_, w| {
125            if cmd.open_drain_broadcast_command() {
126                w.opd().set_bit()
127            } else {
128                w.opd().clear_bit()
129            }
130        });
131
132        self.sdhc.arg1r.write(|w| unsafe { w.bits(arg) });
133        self.sdhc.cr.write(|w| unsafe { w.bits(cmdr) });
134
135        loop {
136            let sr = self.sdhc.eister().read();
137            let error = error_from_eistr(
138                sr.cmdteo().bit_is_set(),
139                sr.cmdcrc().bit_is_set(),
140                sr.cmdend().bit_is_set(),
141                sr.cmdidx().bit_is_set(),
142                sr.datteo().bit_is_set(),
143                sr.datcrc().bit_is_set(),
144                sr.datend().bit_is_set(),
145                sr.adma().bit_is_set(),
146                cmd.expect_valid_crc(),
147            );
148            if error.is_some() {
149                self.reset();
150                self.sdhc.eister().write(|w| unsafe { w.bits(0x03FF) });
151                return Err(error.unwrap());
152            }
153            if self.sdhc.nistr().read().cmdc().bit_is_clear() {
154                break;
155            }
156        }
157
158        if !cmdr.get_bit(5) {
159            self.sdhc.nistr().write(|w| w.cmdc().set_bit());
160        }
161
162        if cmd.card_may_send_busy() {
163            return self.wait_busy();
164        }
165
166        Ok(())
167    }
168
169    pub fn eistr_err(&mut self) -> Result<(), MciError> {
170        let sr = self.sdhc.eistr().read();
171        let error = command_error_from_eistr(
172            sr.datteo().bit_is_set(),
173            sr.datcrc().bit_is_set(),
174            sr.datend().bit_is_set(),
175        );
176        if error.is_some() {
177            self.reset();
178            return Err(MciError::CommandError(error.unwrap()));
179        }
180        Ok(())
181    }
182
183    pub fn loop_or_on_eistr_err<F: FnMut(&mut AtsamdMci) -> bool>(
184        &mut self,
185        mut f: F,
186    ) -> Result<(), MciError> {
187        loop {
188            self.eistr_err()?;
189            if f(self) {
190                break;
191            }
192        }
193        Ok(())
194    }
195}
196
197fn command_error_from_eistr(timeout: bool, crc: bool, end: bool) -> Option<CommandOrDataError> {
198    if timeout {
199        Some(CommandOrDataError::Timeout)
200    } else if crc {
201        Some(CommandOrDataError::Crc)
202    } else if end {
203        Some(CommandOrDataError::EndBit)
204    } else {
205        None
206    }
207}
208
209fn error_from_eistr(
210    cmd_timeout: bool,
211    cmd_crc: bool,
212    cmd_endbit: bool,
213    cmd_index: bool,
214    dat_timeout: bool,
215    dat_crc: bool,
216    dat_endbit: bool,
217    adma: bool,
218    expect_valid_crc: bool,
219) -> Option<MciError> {
220    if cmd_timeout {
221        Some(MciError::CommandError(CommandOrDataError::Timeout))
222    } else if cmd_endbit {
223        Some(MciError::CommandError(CommandOrDataError::EndBit))
224    } else if cmd_index {
225        Some(MciError::CommandError(CommandOrDataError::Index))
226    } else if dat_timeout {
227        Some(MciError::DataError(CommandOrDataError::Timeout))
228    } else if dat_endbit {
229        Some(MciError::DataError(CommandOrDataError::EndBit))
230    } else if adma {
231        Some(MciError::Adma)
232    } else if expect_valid_crc && (cmd_crc || dat_crc) {
233        Some(if cmd_crc {
234            MciError::CommandError(CommandOrDataError::Crc)
235        } else {
236            MciError::DataError(CommandOrDataError::Crc)
237        })
238    } else {
239        None
240    }
241}
242
243impl Mci for AtsamdMci {
244    fn init(&mut self) -> Result<(), MciError> {
245        self.sdhc.srr.modify(|_, w| w.swrstall().set_bit());
246        loop {
247            if self.sdhc.srr.read().swrstall().bit_is_clear() {
248                break;
249            }
250        }
251
252        /* Set the Data Timeout Register to 2 Mega Cycles */
253        self.sdhc.tcr.write(|w| unsafe { w.bits(0xe) });
254
255        /* Set 3v3 power supply */
256        self.sdhc.pcr.write(|w| w.sdbpwr().on().sdbvsel()._3v3());
257
258        self.sdhc.nister().write(|w| unsafe { w.bits(0x01FF) });
259        self.sdhc.eister().write(|w| unsafe { w.bits(0x03FF) });
260
261        Ok(())
262    }
263
264    fn send_command(&mut self, cmd: u32, arg: u32) -> Result<(), MciError> {
265        if self.sdhc.psr.read().cmdinhc().bit_is_set() {
266            return Err(MciError::CommandInhibited);
267        }
268
269        self.sdhc.tmr.modify(|_, w| w.dmaen().clear_bit());
270        self.sdhc.bcr.modify(|_, w| unsafe { w.bits(0) });
271        self.send_command_execute(0, cmd, arg)
272    }
273
274    fn deinit(&mut self) -> Result<(), MciError> {
275        // NOP
276        Ok(())
277    }
278
279    fn select_device(
280        &mut self,
281        _slot: u8,
282        clock: u32,
283        bus_width: &BusWidth,
284        high_speed: bool,
285    ) -> Result<(), MciError> {
286        self.sdhc.hc1r().modify(|_, w| {
287            if high_speed {
288                w.hsen().set_bit()
289            } else {
290                w.hsen().clear_bit()
291            }
292        });
293
294        if self.sdhc.hc2r().read().pvalen().bit_is_clear() {
295            self.set_speed(clock, 0);
296        }
297
298        match bus_width {
299            BusWidth::_1BIT => self.sdhc.hc1r().modify(|_, w| w.dw().clear_bit()),
300            BusWidth::_4BIT => self.sdhc.hc1r().modify(|_, w| w.dw().set_bit()),
301            _ => return Err(MciError::Impl(ImplError::InvalidConfiguration)),
302        }
303        Ok(())
304    }
305
306    fn deselect_device(&mut self, _slot: u8) -> Result<(), MciError> {
307        // NOP
308        Ok(())
309    }
310
311    fn get_bus_width(&mut self, slot: u8) -> Result<BusWidth, MciError> {
312        match slot {
313            0 => Ok(BusWidth::_4BIT),
314            _ => Err(MciError::Impl(ImplError::InvalidConfiguration)),
315        }
316    }
317
318    fn is_high_speed_capable(&mut self) -> Result<bool, MciError> {
319        Ok(self.sdhc.ca0r.read().hssup().bit_is_set())
320    }
321
322    /// Send 74 clock cycles on the line.
323    /// Note: It is required after card plug and before card install.
324    fn send_clock(&mut self) -> Result<(), MciError> {
325        for _m in 0..5000u32 {
326            // Nop
327        }
328        Ok(())
329    }
330
331    fn get_response(&mut self) -> Result<u32, MciError> {
332        Ok(self.sdhc.rr[0].read().cmdresp().bits())
333    }
334
335    fn get_response128(&mut self) -> Result<[u32; 4], MciError> {
336        Ok([
337            self.sdhc.rr[0].read().cmdresp().bits(),
338            self.sdhc.rr[1].read().cmdresp().bits(),
339            self.sdhc.rr[2].read().cmdresp().bits(),
340            self.sdhc.rr[3].read().cmdresp().bits(),
341        ])
342    }
343
344    fn adtc_start(
345        &mut self,
346        command: u32,
347        argument: u32,
348        block_size: u16,
349        block_amount: u16,
350        _access_in_blocks: bool,
351    ) -> Result<(), MciError> {
352        let psr = self.sdhc.psr.read();
353        // Check Command Inhibit (CMD/DAT) in the Present State register
354        if psr.cmdinhc().bit_is_set() || psr.cmdinhd().bit_is_set() {
355            return Err(MciError::CommandInhibited);
356        }
357
358        let command: MciCommand = command.into();
359        if !command.sdio_multi_byte_transfer()
360            && !command.sdio_block_mode_transfer()
361            && !command.single_block_data_transfer()
362            && !command.multi_block_data_transfer()
363        {
364            return Err(MciError::Impl(ImplError::InvalidConfiguration));
365        }
366
367        self.sdhc.tmr.write(|w| {
368            if command.data_write_command() {
369                w.dtdsel().write();
370            } else {
371                w.dtdsel().read();
372            }
373            if command.sdio_multi_byte_transfer() {
374                w.msbsel().single();
375            } else if command.sdio_block_mode_transfer() {
376                w.bcen().enable().msbsel().multiple();
377            } else if command.single_block_data_transfer() {
378                w.msbsel().single();
379            } else if command.multi_block_data_transfer() {
380                w.bcen().enable().msbsel().multiple();
381            }
382            w
383        });
384
385        self.sdhc
386            .bsr
387            .write(|w| unsafe { w.blocksize().bits(block_size) }.boundary()._4k());
388        self.sdhc
389            .bcr
390            .write(|w| unsafe { w.bcnt().bits(block_amount) });
391
392        self.block_amount = block_amount;
393        self.block_size = block_size;
394        self.trans_pos = 0;
395
396        self.send_command_execute(1 << 5, command.val, argument)
397    }
398
399    fn adtc_stop(&self, _command: u32, _argument: u32) -> Result<(), MciError> {
400        // Nop
401        Ok(())
402    }
403
404    fn read_word(&mut self) -> Result<(u32, u8), MciError> {
405        let nbytes: u8 =
406            if ((self.block_size as u64) * (self.block_amount as u64)) - self.trans_pos > 4 {
407                (self.block_size % 4) as u8
408            } else {
409                4
410            };
411
412        if self.trans_pos % (self.block_size as u64) == 0 {
413            self.loop_or_on_eistr_err(|f| f.sdhc.nistr().read().brdrdy().bit_is_set())?;
414        }
415
416        // Read data
417        let val = self.sdhc.bdpr.read().bits()
418            & match nbytes {
419                3 => 0xFF_FFFF,
420                2 => 0xFFFF,
421                1 => 0xFF,
422                _ => 0xFFFF_FFFF,
423            };
424
425        self.trans_pos += nbytes as u64;
426
427        if (self.block_size as u64) * (self.block_amount as u64) > self.trans_pos {
428            return Ok((val, nbytes));
429        }
430
431        // Wait end of transfer
432        self.loop_or_on_eistr_err(|f| f.sdhc.nistr().read().trfc().bit_is_set())?;
433        self.sdhc.nistr().modify(|_, w| w.trfc().yes());
434        Ok((val, nbytes))
435    }
436
437    fn write_word(&mut self, val: u32) -> Result<bool, MciError> {
438        let nbytes = 4u64; // self.block_size & 0x3 ? 1 : 4
439        if self.trans_pos % (self.block_size as u64) == 0 {
440            self.loop_or_on_eistr_err(|f| f.sdhc.nistr().read().bwrrdy().bit_is_set())?;
441        }
442
443        // Write data
444        self.sdhc.bdpr.write(|w| unsafe { w.bits(val) });
445        self.trans_pos += nbytes;
446
447        if (self.block_size as u64) * (self.block_amount as u64) > self.trans_pos {
448            return Ok(true);
449        }
450
451        // Wait end of transfer
452        self.loop_or_on_eistr_err(|f| f.sdhc.nistr().read().trfc().bit_is_set())?;
453        self.sdhc.nistr().modify(|_, w| w.trfc().yes());
454        Ok(true)
455    }
456
457    fn read_blocks(
458        &mut self,
459        destination: &mut [u8],
460        number_of_blocks: u16,
461    ) -> Result<bool, MciError> {
462        let mut data = (number_of_blocks as u64) * (self.block_size as u64);
463        let len = data as usize;
464        let mut index = 0usize;
465
466        while data > 0 {
467            let (val, nbytes) = self.read_word()?;
468            for m in 0..nbytes {
469                let mm = m as usize;
470                if mm + index >= len {
471                    break;
472                }
473                destination[index + mm] = val.get_bits((mm * 8)..((mm + 1) * 8)) as u8;
474            }
475            let nbytes = if (nbytes as u64) > data {
476                (self.block_size % (nbytes as u16)) as u8
477            } else {
478                nbytes
479            };
480            index += nbytes as usize;
481            data -= nbytes as u64;
482        }
483        Ok(true)
484    }
485
486    fn write_blocks(&mut self, write_data: &[u8], number_of_blocks: u16) -> Result<bool, MciError> {
487        let mut data = (number_of_blocks as u64) * (self.block_size as u64);
488        let len = data as usize;
489        let mut index = 0usize;
490
491        while data > 0 {
492            let mut nbytes = 0u8;
493            let mut val = 0u32;
494            for m in 0..4 {
495                let mm = m as usize;
496                if mm + index >= len {
497                    break;
498                }
499                val <<= 8;
500                nbytes += 1;
501                val |= write_data[index + mm] as u32;
502            }
503            self.write_word(val)?;
504            data -= nbytes as u64;
505            index += nbytes as usize;
506        }
507        Ok(true)
508    }
509
510    fn wait_until_read_finished(&self) -> Result<(), MciError> {
511        // Nop
512        Ok(())
513    }
514
515    fn wait_until_write_finished(&self) -> Result<(), MciError> {
516        // Nop
517        Ok(())
518    }
519}