|
|
@@ -0,0 +1,133 @@ |
|
|
|
; sdc |
|
|
|
; |
|
|
|
; Manages the initialization of a SD card and implement a block device to read |
|
|
|
; and write from/to it, in SPI mode. |
|
|
|
; |
|
|
|
; Note that SPI can't really be used directly from the z80, so this part |
|
|
|
; assumes that you have a device that handles SPI communication on behalf of |
|
|
|
; the z80. This device is assumed to work in a particular way. |
|
|
|
; |
|
|
|
; That device has 3 ports. One write-only port to make CS high, one to make CS |
|
|
|
; low (data sent is irrelevant), and one read/write port to send and receive |
|
|
|
; bytes with the card through the SPI protocol. The device acts as a SPI master |
|
|
|
; and writing to that port initiates a byte exchange. Data from the slave is |
|
|
|
; then placed on a buffer that can be read by reading the same port. |
|
|
|
; |
|
|
|
; It's through that kind of device that this code below is supposed to work. |
|
|
|
|
|
|
|
; *** Defines *** |
|
|
|
; SDC_PORT_CSHIGH: Port number to make CS high |
|
|
|
; SDC_PORT_CSLOW: Port number to make CS low |
|
|
|
; SDC_PORT_SPI: Port number to send/receive SPI data |
|
|
|
|
|
|
|
; Wake the SD card up. After power up, a SD card has to receive at least 74 |
|
|
|
; dummy clocks with CS and DI high. We send 80. |
|
|
|
sdcWakeUp: |
|
|
|
out (SDC_PORT_CSHIGH), a |
|
|
|
ld b, 10 ; 10 * 8 == 80 |
|
|
|
ld a, 0xff |
|
|
|
.loop: |
|
|
|
out (SDC_PORT_SPI), a |
|
|
|
nop |
|
|
|
djnz .loop |
|
|
|
ret |
|
|
|
|
|
|
|
; Initiate SPI exchange with the SD card. A is the data to send. Received data |
|
|
|
; is placed in A. |
|
|
|
sdcSendRecv: |
|
|
|
out (SDC_PORT_SPI), a |
|
|
|
nop |
|
|
|
nop |
|
|
|
in a, (SDC_PORT_SPI) |
|
|
|
nop |
|
|
|
nop |
|
|
|
ret |
|
|
|
|
|
|
|
; sdcSendRecv 0xff until the response is something else than 0xff for a maximum |
|
|
|
; of 20 times. Returns 0xff if no response. |
|
|
|
sdcWaitResp: |
|
|
|
push bc |
|
|
|
ld b, 20 |
|
|
|
.loop: |
|
|
|
ld a, 0xff |
|
|
|
call sdcSendRecv |
|
|
|
inc a ; if 0xff, it's going to become zero |
|
|
|
jr nz, .end ; not zero? good, that's our command |
|
|
|
djnz .loop |
|
|
|
.end: |
|
|
|
; whether we had a success or failure, we return the result. |
|
|
|
; But first, let's bring it back to its original value. |
|
|
|
dec a |
|
|
|
pop bc |
|
|
|
ret |
|
|
|
|
|
|
|
; Sends a command to the SD card, along with arguments and specified CRC fields. |
|
|
|
; (CRC is only needed in initial commands though). |
|
|
|
; A: Command to send |
|
|
|
; H: Arg 1 (MSB) |
|
|
|
; L: Arg 2 |
|
|
|
; D: Arg 3 |
|
|
|
; E: Arg 4 (LSB) |
|
|
|
; C: CRC |
|
|
|
; |
|
|
|
; Returns R1 response in A. |
|
|
|
; |
|
|
|
; This does *not* handle CS. You have to select/deselect the card outside this |
|
|
|
; routine. |
|
|
|
sdcCmd: |
|
|
|
; Wait until ready to receive commands |
|
|
|
push af |
|
|
|
call sdcWaitResp |
|
|
|
pop af |
|
|
|
|
|
|
|
call sdcSendRecv |
|
|
|
; Arguments |
|
|
|
ld a, h |
|
|
|
call sdcSendRecv |
|
|
|
ld a, l |
|
|
|
call sdcSendRecv |
|
|
|
ld a, d |
|
|
|
call sdcSendRecv |
|
|
|
ld a, e |
|
|
|
call sdcSendRecv |
|
|
|
; send CRC |
|
|
|
ld a, c |
|
|
|
call sdcSendRecv |
|
|
|
|
|
|
|
; And now we just have to wait for a valid response... |
|
|
|
call sdcWaitResp |
|
|
|
ret |
|
|
|
|
|
|
|
; Send a command that expects a R1 response, handling CS. |
|
|
|
sdcCmdR1: |
|
|
|
out (SDC_PORT_CSLOW), a |
|
|
|
call sdcCmd |
|
|
|
out (SDC_PORT_CSHIGH), a |
|
|
|
ret |
|
|
|
|
|
|
|
; Send a command that expects a R7 response, handling CS. A R7 is a R1 followed |
|
|
|
; by 4 bytes. Those 4 bytes are returned in HL/DE in the same order as in |
|
|
|
; sdcCmd. |
|
|
|
sdcCmdR7: |
|
|
|
out (SDC_PORT_CSLOW), a |
|
|
|
call sdcCmd |
|
|
|
|
|
|
|
; We have our R1 response in A. Let's try reading the next 4 bytes in |
|
|
|
; case we have a R3. |
|
|
|
push af |
|
|
|
ld a, 0xff |
|
|
|
call sdcSendRecv |
|
|
|
ld h, a |
|
|
|
ld a, 0xff |
|
|
|
call sdcSendRecv |
|
|
|
ld l, a |
|
|
|
ld a, 0xff |
|
|
|
call sdcSendRecv |
|
|
|
ld d, a |
|
|
|
ld a, 0xff |
|
|
|
call sdcSendRecv |
|
|
|
ld e, a |
|
|
|
pop af |
|
|
|
|
|
|
|
out (SDC_PORT_CSHIGH), a |
|
|
|
ret |