3 ; Copyright (C) 2010 Leo C.
5 ; This file is part of avrcpm.
7 ; avrcpm is free software: you can redistribute it and/or modify it
8 ; under the terms of the GNU General Public License as published by
9 ; the Free Software Foundation, either version 3 of the License, or
10 ; (at your option) any later version.
12 ; avrcpm is distributed in the hope that it will be useful,
13 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ; GNU General Public License for more details.
17 ; You should have received a copy of the GNU General Public License
18 ; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
23 /* Definitions for MMC/SDC command */
24 #define CMD0 (0) /* GO_IDLE_STATE */
25 #define CMD1 (1) /* SEND_OP_COND (MMC) */
26 #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
27 #define CMD8 (8) /* SEND_IF_COND */
28 #define CMD9 (9) /* SEND_CSD */
29 #define CMD10 (10) /* SEND_CID */
30 #define CMD12 (12) /* STOP_TRANSMISSION */
31 #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
32 #define CMD16 (16) /* SET_BLOCKLEN */
33 #define CMD17 (17) /* READ_SINGLE_BLOCK */
34 #define CMD18 (18) /* READ_MULTIPLE_BLOCK */
35 #define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
36 #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
37 #define CMD24 (24) /* WRITE_BLOCK */
38 #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
39 #define CMD55 (55) /* APP_CMD */
40 #define CMD58 (58) /* READ_OCR */
42 /* Disk Status Bits (DSTATUS) */
43 #define MMCST_NOINIT 0x01 /* Drive not initialized */
44 #define MMCST_NODISK 0x02 /* No medium in the drive */
45 #define MMCST_PROTECT 0x04 /* Write protected */
47 /* Card type flags (CardType) */
48 #define CT_MMC 0x01 /* MMC ver 3 */
49 #define CT_SD1 0x02 /* SD ver 1 */
50 #define CT_SD2 0x04 /* SD ver 2 */
51 #define CT_SDC (CT_SD1|CT_SD2) /* SD */
52 #define CT_BLOCK 0x08 /* Block addressing */
54 #define RES_OK 0 /* 0: Successful */
55 #define RES_ERROR 1 /* 1: R/W Error */
56 #define RES_WRPRT 2 /* 2: Write Protected */
57 #define RES_NOTRDY 3 /* 3: Not Ready */
58 #define RES_PARERR 4 /* 4: Invalid Parameter */
61 #define SPI_MODE_0 (0<<CPOL)|(0<<CPHA)
62 #define SPI_MODE_1 (0<<CPOL)|(1<<CPHA)
63 #define SPI_MODE_2 (1<<CPOL)|(0<<CPHA)
64 #define SPI_MODE_3 (1<<CPOL)|(1<<CPHA)
65 #define SPI_MODE SPI_MODE_0
67 ;------------------------------------------------
71 printstring "SPI_CLK_SLOW "
73 ldi temp,SPI_MODE|(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0) ;clk/128
78 ;------------------------------------------------
82 printstring "SPI_CLK_FAST "
84 ldi temp,SPI_MODE|(1<<SPE)|(1<<MSTR) ;clk/4
94 ;------------------------------------------------
98 printstring "SPI_DISABLE "
104 ;------------------------------------------------
112 ;------------------------------------------------
124 ;------------------------------------------------
125 ; Multiply 32 bit value in yh,yl,xh,xl by 512
137 ;------------------------------------------------
153 ;------------------------------------------------
167 ;------------------------------------------------
168 ; Wait for card ready
169 ; return 1:OK, 0:Timeout
173 ldi temp2,2 ;Wait for ready in timeout of 500ms.
176 sts delay_timer2,_255
185 lds temp,delay_timer2
189 brne mmc_wrl ;tmp is 0 here
197 ;------------------------------------------------
198 ; Deselect the card and release SPI bus
202 sbi P_MMC_CS,mmc_cs ; CS high
207 ;------------------------------------------------
208 ; Select the card and wait for ready
209 ; return 255:Successful, 0:Timeout
212 cbi P_MMC_CS,mmc_cs ; CS low
214 breq mmcDeselect ;return via Deselect
219 ;------------------------------------------------
220 ; Send a command packet to MMC
228 ; ACMD<n> is the command sequence of CMD55-CMD<n>
246 brlo mmc_cmddo ; fall thru, if (retval <= 1)
249 ret ; else return error
251 ; Select the card and wait for ready
260 printstring "mmcCMD: "
280 ; Send command packet
296 ldi temp,0x95 ;CRC for CMD0(0)
299 ldi temp,0x87 ;CRC for CMD8(0x1AA)
302 ldi temp,0x01 ;Dummy CRC + Stop
310 ; Receive command response
312 cpi temp2,CMD12 ; Skip a stuff byte when stop reading
316 ; Wait for a valid response in timeout of 10 attempts
328 ; Return with response value
333 printstring " CMDRes: "
336 rcall uart_wait_empty
341 ;------------------------------------------------
342 ; Send command and receive ocr response
343 ; temp2: Command, zl: expected cmd response
345 ; return: yh..xl: ocr, z flag == 1, if return from mmcCmd was ok.
354 ; Get trailing return value of R7 response
357 ldiw z,0x1a ;memory address of xl
367 ;------------------------------------------------
368 ; Check if 1 sec timeout
369 ; return Z-Flag set, if timeout
372 lds temp,delay_timer1
378 sts delay_timer1,temp
383 ;------------------------------------------------
385 ;------------------------------------------------
387 ;------------------------------------------------
388 ; Initialize MMC/SD card
393 printstring "mmcInit "
395 lds temp,mmcStat ;Set 'NO INIT' status
396 sbr temp,MMCST_NOINIT
403 dec temp2 ;80 dummy clocks
406 ldi temp3,0 ;Card type
410 rcall mmcCmd ;Enter Idle state
415 ldi zh,10 ;Initialization timeout of 1000 ms.
417 sts delay_timer1,temp
424 brne mmci_sdv1 ;SDv2?
431 ; The card can work at vdd range of 2.7-3.6V.
432 ; Wait for leaving idle state (ACMD41 with HCS bit).
446 ; Check CCS bit in the OCR
471 sbr temp3,CT_SD1 ;SDv1
475 sbr temp3,CT_MMC ;MMCv3
478 ; Wait for leaving idle state
484 rjmp mmci_lend ;Timeout
486 ; Set R/W block length to 512
495 sts mmcCardType,temp3
498 ; Initialization succeded?
503 cbr temp,MMCST_NOINIT ;Yes, clear 'NO INIT' status
514 printstring " InitRes: "
523 ;--------------------------------------------------------------
525 ; z: Pointer to the data buffer to store read data
526 ; yh..xl: Start sector number (LBA)
531 printstring "mmcRdSect "
533 ldiw z,hostbuf ;for now
537 sbrc _tmp0,MMCST_NOINIT
542 sbrs temp,log2(CT_BLOCK)
543 rcall mul_yx_512 ;Convert to byte address (*512)
550 ; Receive a data packet from MMC
552 ldiw y,512 ;Number of bytes to tranfer
553 ldi temp,200 ;Wait for data packet in timeout of 200ms.
554 sts delay_timer1,temp
559 lds _tmp0,delay_timer1
563 printstring "TIMEOUT "
569 cpi temp,0xFE ;If not valid data token,
571 printstring "Token: "
576 cpi temp,0xFE ;If not valid data token,
579 rcall spi_rcvr ;Shift in first byte.
585 out SPDR,_255 ;Start shift in next byte.
600 st z+,temp ;Store last byte in buffer
604 rcall spi_wait ;while SPI module shifts in crc part1.
605 rcall spi_rcvr ;Read second crc.
607 ldi temp2,RES_OK ;Return success
613 printstring "RdSectRes: "
620 ;--------------------------------------------------------------
622 ; Read Word to ZL,ZH at given ZL/ZH Offset
623 ; Needed for reading a single FAT16 entry without killing the
624 ; entries in hostbuffer...
626 ; in zh,zl: Pointer to word within the sector to read
627 ; in yh..xl: Start sector number (LBA)
628 ; out zh,zl: Word thats been read
633 printstring "mmcRdWord "
637 sbrc _tmp0,MMCST_NOINIT
642 sbrs temp,log2(CT_BLOCK)
643 rcall mul_yx_512 ;Convert to byte address (*512)
650 ; Receive a data packet from MMC
652 ldiw y,512 ;Number of bytes to tranfer
653 ldi temp,200 ;Wait for data packet in timeout of 200ms.
654 sts delay_timer1,temp
659 lds temp2,delay_timer1
663 cpi temp,0xFE ;If not valid data token,
667 rcall spi_rcvr ;Shift in first byte.
668 out SPDR,_255 ;Start shift in next byte.
697 rcall spi_wait ; while SPI module shifts in crc part1.
698 rcall spi_rcvr ;Read second crc.
700 ldi temp2,RES_OK ;Return success
706 printstring "RdWordRes: "
712 ;--------------------------------------------------------------
714 ; z: Pointer to the data to be written
715 ; yh..xl: Sector number (LBA)
720 printstring "mmcWrSect "
722 ldiw z,hostbuf ;for now
726 sbrc _tmp0,MMCST_NOINIT
731 sbrs temp,log2(CT_BLOCK)
732 rcall mul_yx_512 ;Convert to byte address (*512)
738 ; Send a data packet to MMC
742 printstring "mmcXMIT "
747 ldi temp,0xFE ;Data token
758 ldi temp,0xFF ;dummy crc
763 printstring "XMITRes: "
767 andi temp,0x1F ;If not accepted, return with error
769 ldi temp2,RES_OK ;Return success
779 printstring "WrSectRes: "
785 ;--------------------------------------------------------------
786 ; vim:set ts=8 noet nowrap