sd.asm (5352B)
1 ;;; Copyright 2021 Gerd Beuster (gerd@frombelow.net). This is free 2 ;;; software under the GNU GPL v3 license or any later version. See 3 ;;; COPYING in the root directory for details. 4 5 ;; ----------------------------------- 6 ;;; 7 ;;; SD card communication interface 8 ;;; 9 ;;; ----------------------------------- 10 11 12 sd .namespace 13 14 .section zero_page 15 data: .word ? 16 ;; type does not need to be on the zero page. 17 type: .byte ? ; $05 = SD; $c1 = SDHC 18 ;; Everything beyond these reserved variables available to 19 ;; programs in RAM. 20 .send zero_page 21 22 .section rom 23 24 send_cmd: 25 .block 26 ldy #$00 27 cmd_bytes_loop: 28 lda (sd.data),y 29 jsr via.spi_set 30 iny 31 cpy #$06 32 bne cmd_bytes_loop 33 lda #$ff ; Finalize transmission 34 jsr via.spi_set ; with dummy byte 35 rts 36 .bend 37 38 39 print_block: 40 .block 41 ldx #$02 42 ldy #$00 43 loop: 44 phx 45 phy 46 lda (sd.data),y 47 jsr io.puth 48 #io.PRINTS " " 49 ply 50 plx 51 iny 52 bne loop 53 #mem.ADD_WORD sd.data, $0100 54 dex 55 bne loop 56 #io.PRINTNL 57 #mem.SUB_WORD sd.data, $0200 58 rts 59 .bend 60 61 read_block: 62 ;; Read a block of data 63 ;; Block number is passed via stack. 64 .block 65 jsr ds.create_stack_frame 66 #ds.PUSH $04 ; Local variable (32 bit block number) 67 .if DEBUG 68 #io.PRINTSNL "Sending CMD17" 69 .endif 70 lda #$51 ; CMD17 (READ_SINGLE_BLOCK) 71 jsr via.spi_set 72 .if DEBUG 73 ldy #$00 74 lda (ds.frame_ptr),y 75 jsr io.puth 76 ldy #$01 77 lda (ds.frame_ptr),y 78 jsr io.puth 79 ldy #$02 80 lda (ds.frame_ptr),y 81 jsr io.puth 82 ldy #$03 83 lda (ds.frame_ptr),y 84 jsr io.puth 85 .endif 86 jsr send_block_number 87 lda #$01 ; Dummy CRC 88 jsr via.spi_set 89 jsr via.spi_get 90 cmp #$00 91 beq wait_for_start_token 92 jmp read_failed 93 wait_for_start_token: 94 jsr via.spi_get_nonblocking 95 cmp #$ff 96 beq wait_for_start_token 97 cmp #$fe 98 beq read_ok 99 jmp read_failed 100 read_ok: 101 ldx #$02 102 ldy #$00 103 loop: 104 phx 105 phy 106 jsr via.spi_get_nonblocking 107 ply 108 plx 109 sta (sd.data),y 110 iny 111 bne loop 112 .if DEBUG 113 pha 114 phx 115 phy 116 #io.PRINTSNL "Got half block!" 117 ply 118 plx 119 pla 120 .endif 121 #mem.ADD_WORD sd.data, $0100 ; Second half of block 122 dex 123 bne loop 124 #mem.SUB_WORD sd.data, $0200 ; Restore pointer 125 #sd.RECEIVE $2 ; Get CRC 126 jsr ds.delete_stack_frame 127 clc 128 rts 129 read_failed: 130 #io.PRINTSNL "Error reading SD card!" 131 sec 132 jsr ds.delete_stack_frame 133 rts 134 .bend 135 136 send_block_number: 137 .block 138 lda sd.type ; Old cards expect the position 139 cmp #$05 ; as bytes, not blocks 140 beq old_card 141 #ds.lda_LOCAL 0 ; Block number 142 jsr via.spi_set 143 #ds.lda_LOCAL 1 144 jsr via.spi_set 145 #ds.lda_LOCAL 2 146 jsr via.spi_set 147 #ds.lda_LOCAL 3 148 jsr via.spi_set 149 rts 150 old_card: 151 #ds.lda_LOCAL 3 152 asl a 153 #ds.sta_LOCAL 3 154 #ds.lda_LOCAL 2 155 rol a 156 #ds.sta_LOCAL 2 157 #ds.lda_LOCAL 1 158 rol a 159 jsr via.spi_set 160 #ds.lda_LOCAL 2 161 jsr via.spi_set 162 #ds.lda_LOCAL 3 163 jsr via.spi_set 164 lda #$00 165 jsr via.spi_set 166 rts 167 .bend 168 169 write_block: 170 ;; Write block at data to card. 171 ;; Block number is passed via stack. 172 .block 173 jsr ds.create_stack_frame 174 #ds.PUSH $04 ; Local variable (32 bit block number) 175 .if DEBUG 176 #io.PRINTSNL "Sending CMD24" 177 .endif 178 lda #$58 ; CMD24 (WRITE_BLOCK) 179 jsr via.spi_set 180 jsr send_block_number 181 lda #$01 ; Dummy CRC 182 jsr via.spi_set 183 lda #$ff 184 jsr via.spi_set ; Dummy byte 185 #sd.RECEIVE $1 186 ;; Send start token 187 lda #$fe 188 jsr via.spi_set 189 ;; Send data 190 ldx #$02 191 ldy #$00 192 write_loop: 193 phx 194 phy 195 lda (sd.data),y 196 jsr via.spi_set 197 ply 198 plx 199 iny 200 cpy #$00 201 bne write_loop 202 #mem.ADD_WORD sd.data, $0100 ; Second half of block 203 dex 204 cpx #$00 205 bne write_loop 206 #mem.SUB_WORD sd.data, $0200 ; Restore pointer 207 ;; Wait for write operation to complete 208 #sd.RECEIVE $1 209 cmp #$e5 210 bne error_writing 211 wait_loop: 212 #sd.RECEIVE $1 213 beq wait_loop 214 jsr ds.delete_stack_frame 215 clc 216 rts 217 error_writing: 218 #io.PRINTSNL "Error writing to SD card!" 219 jsr ds.delete_stack_frame 220 sec 221 rts 222 .bend 223 224 close: 225 #mem.SET_BITS via.ra, #via.CS 226 rts 227 228 open: 229 .block 230 .if DEBUG 231 #io.PRINTSNL "Initializing SD Card" 232 .endif 233 ;; Configure ports for in- and output 234 #mem.SET_BITS via.ddra, #(via.CS | via.SCK | via.MOSI) 235 #mem.CLEAR_BITS via.ddra, #via.MISO 236 ldy #$10 ; Error counter 237 phy 238 start_init: 239 ;; Card power on sequence: 240 ;; Keep CS high, toggle clock for at least 74 cycles. 241 #mem.SET_BITS via.ra, #(via.CS | via.MOSI) 242 ;; Wait for 80 clock pulses 243 ldx #160 244 boot_wait_loop: 245 #mem.TOGGLE_BITS via.ra, #via.SCK 246 dex 247 bne boot_wait_loop 248 #mem.CLEAR_BITS via.ra, #(via.CS|via.MOSI|via.SCK) 249 #sd.SEND_CMD [$40, $00, $00, $00, $00, $95] ; CMD0 250 #sd.RECEIVE $1 251 cmp #$01 ; Should be $01 (In idle state). 252 beq cont 253 ply 254 dey 255 phy 256 beq failed_init 257 jmp start_init ; If not, start over. 258 failed_init: 259 ply 260 #io.PRINTSNL "Error initializing SD card!" 261 sec 262 rts 263 cont: 264 ;; Card is in SPI mode 265 ply 266 #sd.SEND_CMD [$48, $00, $00, $01, $aa, $87] ; CMD8 267 #sd.RECEIVE $1 268 #sd.SEND_CMD [$45, $00, $00, $00, $00, $5b] ; CMD5 269 #sd.RECEIVE $1 ; $05 = SD; $c1 = SDHC 270 sta sd.type 271 #sd.SEND_CMD [$7b, $00, $00, $00, $00, $83] ; CMD59 272 #sd.RECEIVE $1 ; should be $01 273 ;; Send ACMD41 until card is initialized 274 ldy #$10 ; Fail counter 275 phy 276 wait_for_card_initialized: 277 #sd.SEND_CMD [$77, $00, $00, $00, $00, $65] ; CMD55 278 #sd.RECEIVE $1 ; should be $01 279 #sd.SEND_CMD [$69, $40, $00, $00, $00, $95] ; ACMD41 (v1 & v2 card) 280 #sd.RECEIVE $1 ; $01 if busy, $00 if ready (initialized) 281 cmp #$00 282 beq initialized 283 ply 284 dey 285 phy 286 bne cont2 ; More tries? 287 cont2: 288 jmp wait_for_card_initialized 289 initialized: 290 ply 291 #sd.SEND_CMD [$50, $00, $00, $02, $00, $15] ; CMD16 292 #sd.RECEIVE $1 293 clc 294 rts 295 .bend 296 297 .send rom 298 .endn