sdc: make writing more solid

By not waiting until the SD card wan't busy any more after a write, we
exposed ourselves to errors if another operation was attempted right
after it.
This commit is contained in:
Virgil Dupras 2019-06-07 14:59:53 -04:00
parent e046081900
commit 495d69c1cb
2 changed files with 38 additions and 5 deletions

View File

@ -274,6 +274,7 @@ fsAlloc:
ld a, c ; C == the number of blocks user asked for ld a, c ; C == the number of blocks user asked for
ld (FS_META+FS_META_ALLOC_OFFSET), a ld (FS_META+FS_META_ALLOC_OFFSET), a
pop hl ; now we want our HL arg pop hl ; now we want our HL arg
; TODO: stop after null char. we're filling meta with garbage here.
ld de, FS_META+FS_META_FNAME_OFFSET ld de, FS_META+FS_META_FNAME_OFFSET
ld bc, FS_MAX_NAME_SIZE ld bc, FS_MAX_NAME_SIZE
ldir ldir

View File

@ -117,6 +117,27 @@ sdcWaitResp:
pop bc pop bc
ret ret
; The opposite of sdcWaitResp: we wait until response if 0xff. After a
; successful read or write operation, the card will be busy for a while. We need
; to give it time before interacting with it again. Technically, we could
; continue processing on our side while the card it busy, and maybe we will one
; day, but at the moment, I'm having random write errors if I don't do this
; right after a write, so I prefer to stay cautious for now.
; This has no error condition and preserves A
sdcWaitReady:
push af
push bc
ld b, 20
.loop:
call sdcIdle
inc a ; if 0xff, it's going to become zero
jr z, .end ; zero? good, we're not busy any more
djnz .loop
.end:
pop bc
pop af
ret
; Sends a command to the SD card, along with arguments and specified CRC fields. ; Sends a command to the SD card, along with arguments and specified CRC fields.
; (CRC is only needed in initial commands though). ; (CRC is only needed in initial commands though).
; A: Command to send ; A: Command to send
@ -254,13 +275,20 @@ sdcInitialize:
or a ; cp 0 or a ; cp 0
jr nz, .error jr nz, .error
; Success! out of idle mode! ; Success! out of idle mode!
; At this point, our buffers are innitialized. We could have some logic
; that determines whether a buffer is initialized in appropriate SDC
; routines and act appropriately, but why bother when we could, instead,
; just buffer the first two sectors of the card on initialization? This
; way, no need for special conditions.
; initialize variables ; initialize variables
ld hl, SDC_BUFSEC1 ld hl, SDC_BUFSEC1
ld (SDC_BUFPTR), hl
ld a, 0xff
ld (SDC_BUFSEC1), a
xor a xor a
ld (SDC_BUFDIRTY1), a ld (SDC_BUFPTR), hl
call sdcReadBlk ; read sector 0 in buf1
ld hl, SDC_BUFSEC2
inc a
ld (SDC_BUFPTR), hl
call sdcReadBlk ; read sector 1 in buf2
jr .end jr .end
.error: .error:
@ -341,7 +369,8 @@ sdcReadBlk:
; Read our 2 CRC bytes ; Read our 2 CRC bytes
call sdcIdle call sdcIdle
call sdcIdle call sdcIdle
; success! ; success! wait until card is ready
call sdcWaitReady
jr .end jr .end
.error: .error:
; try to preserve error code ; try to preserve error code
@ -419,6 +448,9 @@ sdcWriteBlk:
inc hl ; dirty flag inc hl ; dirty flag
xor a xor a
ld (hl), a ld (hl), a
; Before returning, wait until card is ready
call sdcWaitReady
jr .end jr .end
.error: .error:
; try to preserve error code ; try to preserve error code