Код:
sd_select:
call sd_fini
or SD_CS ; select, still idle data
out (RTC), a
ret ; af b trashed
sd_fini:
ld b, 17 ; clock low high low high ... low, 8 pulses
sd_wiggle:
ld a, SD_DOUT ; unselected, idle data
L1:
out (RTC), a
xor SD_CLK
djnz L1
ret ; af b trashed
sd_put: ; byte from a
ld c, a
ld b, 8
L3:
ld a, SD_CS >> 1 ; 7 msbits
rl c
rla ; SD_DOUT is RTC.0
out (RTC), a ; clock is low
or SD_CLK
out (RTC), a ; rising clock edge
djnz L3
and ~SD_CLK
out (RTC), a ; leave with clock low
ret ; af bc trashed
sd_get: ; byte to a
ld b, 8
L2:
in a, (RTC)
rla ; SD_DIN is RTC.7
rl c
ld a, SD_CS | SD_DOUT | SD_CLK
out (RTC), a
and ~SD_CLK
out (RTC), a
djnz L2
ld a, c
ret ; af bc trashed
; command in a, includes fixed msbits
; arg32 in dehl
; z return, if R1 (in a) is 0
sd_command_no_arg:
ld hl, 0
sd_command_word_arg: ; fits in HL
ld de, 0
sd_command: ; command in a, dword arg in dehl
call sd_put ; command includes fixed 01 startbits
ld a, d ; arg
call sd_put
ld a, e
call sd_put
ld a, h
call sd_put
ld a, l
call sd_put
ld a, 095h ; crc7 only valid for initial CMD0
call sd_put ; DOUT ends up idle because of the stopbit
ld hl, 20000 ; XXX timeout XTAL dependent
L4:
call sd_get ; R1 response, when msbit is clear
or a ; zero and sign valid
ret p ; R1 in a. z if ok
dec hl
bit 7, h ; until HL wraps negative
jr z, L4
ret ; 0x80 | ? in a, nz
; command response R1
; 0x00 ok
; or bitfield
; 0x01 idle state
; 0x02 erase reset
; 0x04 illegal command
; 0x08 command crc error
; 0x10 erase sequence error
; 0x20 address error
; 0x40 parameter error
; 0x80 timeout (other bits meaningless)
;
; packet token
; 0xFF none yet
; 0xFE ok
; or bitfield
; 0x01 error
; 0x02 controller error
; 0x04 media ecc failed
; 0x08 out of range
; 0x10 card is locked
sd_wait_token:
ld hl, 20000 ; XXX timeout XTAL dependent
L5:
call sd_get ; token is first non-FF
cp 0FFh
ret nz ; token in a
dec hl
bit 7, h ; until HL wraps negative
jr z, L5
ret ; FF in a
sd_wait_busy:
ld hl, 20000 ; XXX timeout XTAL dependent
L6:
call sd_get ; 8 clocks. data output activates after 1 clock
inc a ; FF is not busy
ret z ; z, ok. a=0
dec hl ; else busy or something
bit 7, h ; until HL wraps negative
jr z, L6
ret ; nz, timeout
CMD0 equ 040h | 0 ; resets the card
CMD9 equ 040h | 9 ; read CSD
CMD10 equ 040h | 10 ; read CID
CMD16 equ 040h | 16 ; set R/W block
CMD17 equ 040h | 17 ; read block
CMD24 equ 040h | 24 ; write block
CMD55 equ 040h | 55 ; next command is ACMDxx
ACMD41 equ 040h | 41 ; send host capacity support, init card
; byte offset in dehl
; z return if ok
sd_read_block:
ld a, CMD17 ; READ_SINGLE_BLOCK
call sd_command ; dehl byteaddress
ret nz ; not "ok"
call sd_wait_token ; packet start or FF if timed out
cp 0FEh
ret nz ; or error
ld hl, (rwaddr)
ld e, 128 ; loop counter
L9:
call sd_get ; data
ld (hl), a
inc hl
dec e
jr nz, L9 ; do the sector
call sd_get ; crc16
ld h, a
call sd_get ; in HL
ld l, a ; crcs are not used
xor a ; zero, no carry
ret
sd_setup:
call sd_select
call sd_wait_busy ; nz if timed out, z a=0 if ok
ret nz
; A is 0 from sd_wait_busy.
; byte address to dehl from TRACK, SECTOR
; when spt 256 and sector 128
ld hl, (sectorx) ; sector to h, zero to l
ld de, (track) ; adehl (TRACK << 16) | (SECTOR << 8) | 0
IF 0
srl d
rr e
rr h
rr l ; dehl sector * 128
xor a ; z, ok. cannot overflow
ELSE
; XXX XXX XXX XXX easy way out
add hl, hl
rl e
rl d ; dehl sector * 512
adc a, a ; z, if ok
ENDIF
ret
sd_read:
call sd_setup
call z, sd_read_block
sd_done:
push af
call sd_fini
call rtc_unselect ; /CS high, clock and dout low
pop af
jp nz, rw_fail
xor a
ret