#define CMD55 (55) /* APP_CMD */
#define CMD58 (58) /* READ_OCR */
-/* Disk Status Bits (DSTATUS) */
+/* Disk Status Bits (masks) (DSTATUS) */
#define MMCST_NOINIT 0x01 /* Drive not initialized */
#define MMCST_NODISK 0x02 /* No medium in the drive */
#define MMCST_PROTECT 0x04 /* Write protected */
-/* Card type flags (CardType) */
+/* Card type flags (masks) (CardType) */
#define CT_MMC 0x01 /* MMC ver 3 */
#define CT_SD1 0x02 /* SD ver 1 */
#define CT_SD2 0x04 /* SD ver 2 */
#define RES_NOTRDY 3 /* 3: Not Ready */
#define RES_PARERR 4 /* 4: Invalid Parameter */
+
+#define SPI_MODE_0 (0<<CPOL)|(0<<CPHA)
+#define SPI_MODE_1 (0<<CPOL)|(1<<CPHA)
+#define SPI_MODE_2 (1<<CPOL)|(0<<CPHA)
+#define SPI_MODE_3 (1<<CPOL)|(1<<CPHA)
+#define SPI_MODE SPI_MODE_0
+
;------------------------------------------------
-;
+;
.macro spi_clkslow
.if MMC_DEBUG > 1
printstring "SPI_CLK_SLOW "
.endif
- ldi temp,(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0) ;clk/128
+ ldi temp,SPI_MODE|(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0) ;clk/128
out SPCR,temp
out SPSR,_0
.endm
;------------------------------------------------
-;
+;
.macro spi_clkfast
.if MMC_DEBUG > 1
printstring "SPI_CLK_FAST "
.endif
- ldi temp,(1<<SPE)|(1<<MSTR) ;clk/4
+ ldi temp,SPI_MODE|(1<<SPE)|(1<<MSTR) ;clk/4
out SPCR,temp
#if MMC_SPI2X
ldi temp,(1<<SPI2X)
.endm
;------------------------------------------------
-;
+;
.macro spi_disable
.if MMC_DEBUG > 1
printstring "SPI_DISABLE "
.byte 1
mmcCardType:
.byte 1
-mmc_ocr:
- .byte 4
-
.cseg
rol yl
rol yh
ret
-
+
;------------------------------------------------
spi_rcvr:
out SPDR,_255
rjmp spi_rcvr_l
in temp,SPDR
.if MMC_DEBUG > 2
- push temp
printstring "<"
rcall printhex
printstring " "
- pop temp
.endif
ret
.endif
out SPDR,temp
;fall thru
-spi_wait:
+spi_wait:
sbism8 SPSR,SPIF
rjmp spi_wait
ret
-
+
;------------------------------------------------
-; Wait for card ready
-; return 1:OK, 0:Timeout
+; Wait for card ready
+; return 1:OK, 0:Timeout
mmcWaitReady:
push temp2
brne mmc_wrl ;tmp is 0 here
mmc_wrbreak:
- pop temp2
+ pop temp2
tst temp ;set flags
ret
ret
;------------------------------------------------
-; Select the card and wait for ready
+; Select the card and wait for ready
; return 255:Successful, 0:Timeout
mmcSelect:
breq mmcDeselect ;return via Deselect
sbr temp,255
ret
-
+
;------------------------------------------------
-; Send a command packet to MMC
+; Send a command packet to MMC
; temp2: Command
; yh..xl: Argument
+; return:
+; temp: 0 = ok, no error
+; z-flag 1 = ok, no error
+;
mmcCmd:
sbrs temp2,7
rjmp mmc_cmddo
-; ACMD<n> is the command sequence of CMD55-CMD<n>
-
+; ACMD<n> is the command sequence of CMD55-CMD<n>
+
push yh
push yl
push xh
cpi temp,2
brlo mmc_cmddo ; fall thru, if (retval <= 1)
-
+
tst temp
ret ; else return error
ldi temp,0xFF
rjmp mmc_cmdexit
-
+
; Send command packet
mmc_cmd_p:
rcall spi_wait
out SPDR,xl
rcall spi_wait
-
+
ldi temp,0x95 ;CRC for CMD0(0)
cpi temp2,CMD0
breq mmc_cmdxcrc
- ldi temp,0x87 ;CRC for CMD8(0x1AA)
+ ldi temp,0x87 ;CRC for CMD8(0x1AA)
cpi temp2,CMD8
breq mmc_cmdxcrc
ldi temp,0x01 ;Dummy CRC + Stop
cpi temp2,CMD12 ; Skip a stuff byte when stop reading
brne mmc_cmdres
rcall spi_rcvr
-
+
; Wait for a valid response in timeout of 10 attempts
mmc_cmdres:
- ldi temp,10
- mov _tmp1,temp
+ push temp2
+ ldi temp2,10
mmc_cmdrl:
rcall spi_rcvr
sbrs temp,7
rjmp mmc_cmdexit
- dec _tmp1
+ dec temp2
brne mmc_cmdrl
; Return with response value
mmc_cmdexit:
+ pop temp2
.if MMC_DEBUG
printstring " CMDRes: "
rcall printhex
.endif
tst temp ;set flags
ret
-
+
+;------------------------------------------------
+; Send command and receive ocr response
+; temp2: Command, zl: expected cmd response
+; yh..xl: Argument
+; return: yh..xl: ocr, z flag == 1, if return from mmcCmd was ok.
+
+mmcCmd_ocr:
+
+ rcall mmcCmd
+
+ cp temp,zl ;
+ brne mmc_cocr_e
+
+; Get trailing return value of R7 response
+
+ ldi temp2,4
+ ldiw z,0x1a ;memory address of xl
+mmc_cocr1:
+ rcall spi_rcvr
+ st z+,temp
+ dec temp2
+ brne mmc_cocr1
+ ;z-flag =1
+mmc_cocr_e:
+ ret
+
;------------------------------------------------
; Check if 1 sec timeout
; return Z-Flag set, if timeout
lds temp,delay_timer1
tst temp
brne mmc_ttex
- dec temp4
+ dec zh
breq mmc_ttex
ldi temp,100
sts delay_timer1,temp
; Initialize MMC/SD card
mmcInit:
-.if MMC_DEBUG
+.if MMC_DEBUG
printnewline
printstring "mmcInit "
.endif
cpi temp,1
breq mmci_1
rjmp mmci_lend
-mmci_1:
- ldi temp4,10 ;Initialization timeout of 1000 ms.
+mmci_1:
+ ldi zh,10 ;Initialization timeout of 1000 ms.
ldi temp,100
sts delay_timer1,temp
ldi temp2,CMD8
ldiw y,0
ldi xh,0x01
ldi xl,0xAA
- rcall mmcCmd
- cpi temp,1 ;SDv2?
- brne mmci_sdv1
-
-; Get trailing return value of R7 response
+ ldi zl,1
+ rcall mmcCmd_ocr
+ brne mmci_sdv1 ;SDv2?
- ldi temp2,4
- ldiw z,mmc_ocr
-mmci_v2l1:
- rcall spi_rcvr
- st z+,temp
- dec temp2
- brne mmci_v2l1
- sbiw z,4
- ldd temp,z+2
- cpi temp,0x01
- ldd temp,z+3
- cpc temp,xl ;Reuse 0xAA value in xl
+ cpi yl,0x01 ;ocr[2]
+ brne mmci_sdv1
+ cpi yh,0xAA ;ocr[3]
brne mmci_sdv1
; The card can work at vdd range of 2.7-3.6V.
; Wait for leaving idle state (ACMD41 with HCS bit).
-
+
ldi temp2,ACMD41
ldi yh,0x40
ldi yl,0
rcall mmc_timeout_1s
brne mmci_v2l2
rjmp mmci_sdv2end
-
+
; Check CCS bit in the OCR
mmci_ccc:
ldi temp2,CMD58
ldi yh,0
- rcall mmcCmd
+ ldi zl,0
+ rcall mmcCmd_ocr
+
brne mmci_sdv2end
- ldi temp2,4
-mmci_v2l3:
- rcall spi_rcvr
- st z+,temp
- dec temp2
- brne mmci_v2l3
- sbiw z,4
-
sbr temp3,CT_SD2
- ldd temp,z+0
- sbrc temp,6
+ sbrc xl,6
sbr temp3,CT_BLOCK
mmci_sdv2end:
rjmp mmci_lend
-
+
; SDv1 or MMCv3
mmci_sdv1:
ldi temp2,ACMD41
ldiw y,0
movw x,y
- rcall mmcCmd
+ rcall mmcCmd
cpi temp,2
brsh mmci_mmcv3
sbr temp3,CT_SD1 ;SDv1
rcall mmc_timeout_1s
brne mmci_v1_l
rjmp mmci_lend ;Timeout
-
+
; Set R/W block length to 512
mmci_v1_2:
- ldi temp2,CMD16
+ ldi temp2,CMD16
ldiw x,512
rcall mmcCmd
breq mmci_lend
ldi temp3,0
-
+
mmci_lend:
sts mmcCardType,temp3
rcall mmcDeselect
-
+
; Initialization succeded?
lds temp,mmcStat
printstring " CT: "
push temp
lds temp,mmcCardType
- rcall printhex
+ lcall printhex
pop temp
printstring " InitRes: "
- rcall printhex
+ lcall printhex
printstring " "
.endif
spi_disable
ret
-
-
+
+;--------------------------------------------------------------
+
+ .equ MMC_RDOP = 0 ;Read Operation
+ .equ MMC_RDWORD = 1 ;Read Word (FAT entry)
+
;--------------------------------------------------------------
-; Read sector
-; z: Pointer to the data buffer to store read data
-; yh..xl: Start sector number (LBA)
mmcReadSect:
+
.if MMC_DEBUG > 1
printnewline
printstring "mmcRdSect "
.endif
- ldiw z,hostbuf ;for now
+ ldi temp,(1<<MMC_RDOP)
+ rjmp mmc_rw_common
+
+mmcReadWord:
+
+.if (MMC_DEBUG > 1) || (MMC_DEBUG_RDW > 0)
+ printnewline
+ printstring "mmcRdWord "
+.endif
+ ldi temp,(1<<MMC_RDOP) | (1<<MMC_RDWORD)
+ rjmp mmc_rw_common
+
+mmcWriteSect:
+
+.if MMC_DEBUG > 1
+ printnewline
+ printstring "mmcWrSect "
+.endif
+ ldi temp,0
+
+mmc_rw_common:
+ push temp3
+ mov temp3,temp
+ lds temp,mmcStat
+ ldi temp2,RES_NOTRDY
+ sbrc temp,log2(MMCST_NOINIT)
+ rjmp mmc_rwexit_2
- lds _tmp0,mmcStat
- ldi temp,RES_NOTRDY
- sbrc _tmp0,MMCST_NOINIT
- ret
-
spi_clkfast
lds temp,mmcCardType
sbrs temp,log2(CT_BLOCK)
rcall mul_yx_512 ;Convert to byte address (*512)
- ldi temp2,CMD17
+ sbrc temp3,MMC_RDOP
+ ldi temp2,CMD17
+ sbrs temp3,MMC_RDOP
+ ldi temp2,CMD24
rcall mmcCmd
- ldi temp2,RES_ERROR
- brne mmc_rdex
-
+ breq mmc_rw_1
+ rjmp mmc_rwexit_error
+
+mmc_rw_1:
+ ldiw y,512
+ sbrs temp3,MMC_RDOP
+ rjmp mmc_wroper
+
+;-------------------------------------------------------------------------------
; Receive a data packet from MMC
- ldiw y,512 ;Number of bytes to tranfer
ldi temp,200 ;Wait for data packet in timeout of 200ms.
sts delay_timer1,temp
mmc_rcv_wl:
mmc_rcv_start:
.if MMC_DEBUG > 1
- cpi temp,0xFE ;If not valid data token,
+ cpi temp,0xFE ;If not valid data token,
breq mmc_rcv_dbg1
printstring "Token: "
- rcall printhex
+ lcall printhex
printstring " "
mmc_rcv_dbg1:
.endif
- cpi temp,0xFE ;If not valid data token,
- brne mmc_rdex
-
- rcall spi_rcvr ;Shift in first byte.
- out SPDR,_255 ;Start shift in next byte.
-mmc_rcv_rl:
- sbiw yl,1
- breq mmc_rcv_rle
- st z+,temp
- spi_waitm
- in temp,SPDR
- out SPDR,_255
- rjmp mmc_rcv_rl
+ cpi temp,0xFE ;If not valid data token,
+ breq mmc_rw_2
+ rjmp mmc_rwexit_error
+mmc_rw_2:
-mmc_rcv_rle:
- st z+,temp ;Store last byte in buffer
- rcall spi_wait ; while SPI module shifts in crc part1.
- rcall spi_rcvr ;Read second crc.
-
- ldi temp2,RES_OK ;Return success
-mmc_rdex:
- rcall mmcDeselect
- spi_disable
- mov temp,temp2
-.if MMC_DEBUG > 1
- printstring "RdSectRes: "
- rcall printhex
+ rcall spi_rcvr ;Shift in first byte.
+.if MMC_DEBUG > 3
+ printnewline
+ lcall printhex
printstring " "
.endif
- ret
-
-
-;--------------------------------------------------------------
-; Read word
-; TODO: Read Word to ZL,ZH at given ZL/ZH Offset
-; Need for reading of single FAT16 Entrys without killing the
-; Entrys in hostbuffer...
-;
-; in zh,zl: Pointer to Word within the Sector to read
-; in yh..xl: Start sector number (LBA)
-; out zh,zl : word thats been read
+ out SPDR,_255 ;Start shift in next byte.
-mmcReadWord:
-.if MMC_DEBUG > 1
- printnewline
- printstring "mmcRdWord "
-.endif
- lds _tmp0,mmcStat
- ldi temp,RES_NOTRDY
- sbrc _tmp0,MMCST_NOINIT
- ret
-
- spi_clkfast
- lds temp,mmcCardType
- sbrs temp,log2(CT_BLOCK)
- rcall mul_yx_512 ;Convert to byte address (*512)
+ sbrs temp3,MMC_RDWORD
+ rjmp mmc_rcv_readloop
- ldi temp2,CMD17
- rcall mmcCmd
- ldi temp2,RES_ERROR
- brne mmc_rdexw
-
-; Receive a data packet from MMC
+; discard x-1 bytes
- ldiw y,512 ;Number of bytes to tranfer
- ldi temp,200 ;Wait for data packet in timeout of 200ms.
- sts delay_timer1,temp
-mmc_rcvw_wl:
- rcall spi_rcvr
- cp temp,_255
- brne mmc_rcvw_start
- lds temp2,delay_timer1
- cpi temp2,0
- brne mmc_rcvw_wl
-mmc_rcvw_start:
- cpi temp,0xFE ;If not valid data token,
- ldi temp2,RES_ERROR
- brne mmc_rdexw
-
- rcall spi_rcvr ;Shift in first byte.
- out SPDR,_255 ;Start shift in next byte.
mmc_rcvw_rl:
sbiw yl,1
- breq mmc_rcvw_rle
- cp zl,_0
- cpc zh,_0
+ breq mmc_rcv_rlend
+ cp zl,_0
+ cpc zh,_0
breq mmc_rcvw_sto
sbiw zl,1
spi_waitm
- in temp,SPDR
- out SPDR,_255
+ in temp,SPDR
+ out SPDR,_255
rjmp mmc_rcvw_rl
+; read next two bytes
+
mmc_rcvw_sto:
mov zl,temp
spi_waitm
- in temp,SPDR
- out SPDR,_255
+ in temp,SPDR
+ out SPDR,_255
mov zh,temp
+.if MMC_DEBUG_RDW > 0
+ movw temp,z
+ lcall printhexw
+ printstring " "
+.endif
+
+; discard the rest
+
mmc_rcvw_rl2:
sbiw yl,1
- breq mmc_rcvw_rle
+ breq mmc_rcv_rlend
spi_waitm
- in temp,SPDR
- out SPDR,_255
+ in temp,SPDR
+ out SPDR,_255
rjmp mmc_rcvw_rl2
-mmc_rcvw_rle:
- rcall spi_wait ; while SPI module shifts in crc part1.
- rcall spi_rcvr ;Read second crc.
-
- ldi temp2,RES_OK ;Return success
-mmc_rdexw:
- rcall mmcDeselect
- spi_disable
- mov temp,temp2
-.if MMC_DEBUG > 1
- printstring "RdWordRes: "
- rcall printhex
+
+; read sector, store in buffer
+
+mmc_rcv_readloop:
+ sbiw yl,1
+ breq mmc_rcv_rle
+ st z+,temp
+ spi_waitm
+ in temp,SPDR
+.if MMC_DEBUG > 3
+ lcall printhex
printstring " "
.endif
- ret
-
-;--------------------------------------------------------------
-; Write sector
-; z: Pointer to the data to be written
-; yh..xl: Sector number (LBA)
+ out SPDR,_255
+ rjmp mmc_rcv_readloop
-mmcWriteSect:
-.if MMC_DEBUG > 1
+mmc_rcv_rle:
+ st z+,temp ;Store last byte in buffer
+mmc_rcv_rlend:
+.if MMC_DEBUG > 3
printnewline
- printstring "mmcWrSect "
.endif
- ldiw z,hostbuf ;for now
-
- lds _tmp0,mmcStat
- ldi temp,RES_NOTRDY
- sbrc _tmp0,MMCST_NOINIT
- ret
-
- spi_clkfast
- lds temp,mmcCardType
- sbrs temp,log2(CT_BLOCK)
- rcall mul_yx_512 ;Convert to byte address (*512)
+ rcall spi_wait ;while SPI module shifts in crc part1.
+ rcall spi_rcvr ;Read second crc.
- ldi temp2,CMD24
- rcall mmcCmd
- brne mmc_wrexer
-
+ ldi temp2,RES_OK ;Return success
+ rjmp mmc_rwexit
+
+
+;-------------------------------------------------------------------------------
; Send a data packet to MMC
+mmc_wroper:
+
.if MMC_DEBUG > 2
; printnewline
printstring "mmcXMIT "
.endif
rcall mmcWaitReady
- breq mmc_wrexer
+ breq mmc_rwexit_error
ldi temp,0xFE ;Data token
out SPDR,temp
- ldiw y,512
mmc_x_loop:
ld temp,z+
spi_waitm
out SPDR,temp
sbiw yl,1
brne mmc_x_loop
-
+
rcall spi_wait
ldi temp,0xFF ;dummy crc
rcall spi_xmit
rcall spi_rcvr
.if MMC_DEBUG > 2
printstring "XMITRes: "
- rcall printhex
+ lcall printhex
printstring " "
.endif
andi temp,0x1F ;If not accepted, return with error
cpi temp,0x05
ldi temp2,RES_OK ;Return success
- breq mmc_wrex
+ breq mmc_rwexit
-mmc_wrexer:
- ldi temp,RES_ERROR
-mmc_wrex:
+mmc_rwexit_error:
+ ldi temp2,RES_ERROR
+mmc_rwexit:
rcall mmcDeselect
spi_disable
+mmc_rwexit_2:
mov temp,temp2
+
.if MMC_DEBUG > 1
- printstring "WrSectRes: "
- rcall printhex
+ sbrc temp3,MMC_RDOP
+ rjmp mmc_dbg_rder
+
+ printstring "WrSectRes: "
+ rjmp mmc_dbg_rwerex
+
+mmc_dbg_rder:
+ sbrc temp3,MMC_RDWORD
+ rjmp mmc_dbg_rdwder
+ printstring "RdSectRes: "
+ rjmp mmc_dbg_rwerex
+
+mmc_dbg_rdwder:
+ printstring "RdWordRes: "
+mmc_dbg_rwerex:
+ lcall printhex
printstring " "
.endif
+ pop temp3
ret
;--------------------------------------------------------------
; vim:set ts=8 noet nowrap
-