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
332 printstring " CMDRes: "
335 rcall uart_wait_empty
340 ;------------------------------------------------
341 ; Send command and receive ocr response
342 ; temp2: Command, zl: expected cmd response
344 ; return: yh..xl: ocr, z flag == 1, if return from mmcCmd was ok.
353 ; Get trailing return value of R7 response
356 ldiw z,0x1a ;memory address of xl
366 ;------------------------------------------------
367 ; Check if 1 sec timeout
368 ; return Z-Flag set, if timeout
371 lds temp,delay_timer1
377 sts delay_timer1,temp
382 ;------------------------------------------------
384 ;------------------------------------------------
386 ;------------------------------------------------
387 ; Initialize MMC/SD card
392 printstring "mmcInit "
394 lds temp,mmcStat ;Set 'NO INIT' status
395 sbr temp,MMCST_NOINIT
402 dec temp2 ;80 dummy clocks
405 ldi temp3,0 ;Card type
409 rcall mmcCmd ;Enter Idle state
414 ldi temp4,10 ;Initialization timeout of 1000 ms.
416 sts delay_timer1,temp
423 brne mmci_sdv1 ;SDv2?
430 ; The card can work at vdd range of 2.7-3.6V.
431 ; Wait for leaving idle state (ACMD41 with HCS bit).
445 ; Check CCS bit in the OCR
470 sbr temp3,CT_SD1 ;SDv1
474 sbr temp3,CT_MMC ;MMCv3
477 ; Wait for leaving idle state
483 rjmp mmci_lend ;Timeout
485 ; Set R/W block length to 512
494 sts mmcCardType,temp3
497 ; Initialization succeded?
502 cbr temp,MMCST_NOINIT ;Yes, clear 'NO INIT' status
513 printstring " InitRes: "
522 ;--------------------------------------------------------------
524 ; z: Pointer to the data buffer to store read data
525 ; yh..xl: Start sector number (LBA)
530 printstring "mmcRdSect "
532 ldiw z,hostbuf ;for now
536 sbrc _tmp0,MMCST_NOINIT
541 sbrs temp,log2(CT_BLOCK)
542 rcall mul_yx_512 ;Convert to byte address (*512)
549 ; Receive a data packet from MMC
551 ldiw y,512 ;Number of bytes to tranfer
552 ldi temp,200 ;Wait for data packet in timeout of 200ms.
553 sts delay_timer1,temp
558 lds _tmp0,delay_timer1
562 printstring "TIMEOUT "
568 cpi temp,0xFE ;If not valid data token,
570 printstring "Token: "
575 cpi temp,0xFE ;If not valid data token,
578 rcall spi_rcvr ;Shift in first byte.
584 out SPDR,_255 ;Start shift in next byte.
599 st z+,temp ;Store last byte in buffer
603 rcall spi_wait ;while SPI module shifts in crc part1.
604 rcall spi_rcvr ;Read second crc.
606 ldi temp2,RES_OK ;Return success
612 printstring "RdSectRes: "
619 ;--------------------------------------------------------------
621 ; Read Word to ZL,ZH at given ZL/ZH Offset
622 ; Needed for reading a single FAT16 entry without killing the
623 ; entries in hostbuffer...
625 ; in zh,zl: Pointer to word within the sector to read
626 ; in yh..xl: Start sector number (LBA)
627 ; out zh,zl: Word thats been read
632 printstring "mmcRdWord "
636 sbrc _tmp0,MMCST_NOINIT
641 sbrs temp,log2(CT_BLOCK)
642 rcall mul_yx_512 ;Convert to byte address (*512)
649 ; Receive a data packet from MMC
651 ldiw y,512 ;Number of bytes to tranfer
652 ldi temp,200 ;Wait for data packet in timeout of 200ms.
653 sts delay_timer1,temp
658 lds temp2,delay_timer1
662 cpi temp,0xFE ;If not valid data token,
666 rcall spi_rcvr ;Shift in first byte.
667 out SPDR,_255 ;Start shift in next byte.
696 rcall spi_wait ; while SPI module shifts in crc part1.
697 rcall spi_rcvr ;Read second crc.
699 ldi temp2,RES_OK ;Return success
705 printstring "RdWordRes: "
711 ;--------------------------------------------------------------
713 ; z: Pointer to the data to be written
714 ; yh..xl: Sector number (LBA)
719 printstring "mmcWrSect "
721 ldiw z,hostbuf ;for now
725 sbrc _tmp0,MMCST_NOINIT
730 sbrs temp,log2(CT_BLOCK)
731 rcall mul_yx_512 ;Convert to byte address (*512)
737 ; Send a data packet to MMC
741 printstring "mmcXMIT "
746 ldi temp,0xFE ;Data token
757 ldi temp,0xFF ;dummy crc
762 printstring "XMITRes: "
766 andi temp,0x1F ;If not accepted, return with error
768 ldi temp2,RES_OK ;Return success
778 printstring "WrSectRes: "
784 ;--------------------------------------------------------------
785 ; vim:set ts=8 noet nowrap