-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy path2_sendcommand.s
319 lines (242 loc) · 5.79 KB
/
2_sendcommand.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
PORTB = $6000
PORTA = $6001
DDRB = $6002
DDRA = $6003
E = %10000000
RW = %01000000
RS = %00100000
SD_CS = %00010000
SD_SCK = %00001000
SD_MOSI = %00000100
SD_MISO = %00000010
PORTA_OUTPUTPINS = E | RW | RS | SD_CS | SD_SCK | SD_MOSI
zp_sd_cmd_address = $40
.org $e000
reset:
ldx #$ff
txs
lda #%11111111 ; Set all pins on port B to output
sta DDRB
lda #PORTA_OUTPUTPINS ; Set various pins on port A to output
sta DDRA
jsr lcd_init
; Let the SD card boot up, by pumping the clock with SD CS disabled
lda #'I'
jsr print_char
; We need to apply around 80 clock pulses with CS and MOSI high.
; Normally MOSI doesn't matter when CS is high, but the card is
; not yet is SPI mode, and in this non-SPI state it does care.
lda #SD_CS | SD_MOSI
ldx #160 ; toggle the clock 160 times, so 80 low-high transitions
.preinitloop:
eor #SD_SCK
sta PORTA
dex
bne .preinitloop
jsr longdelay
.cmd0 ; GO_IDLE_STATE - resets card to idle state, and SPI mode
lda #<cmd0_bytes
sta zp_sd_cmd_address
lda #>cmd0_bytes
sta zp_sd_cmd_address+1
jsr sd_sendcommand
; Expect status response $01 (not initialized)
cmp #$01
bne .initfailed
jsr longdelay
.cmd8 ; SEND_IF_COND - tell the card how we want it to operate (3.3V, etc)
lda #<cmd8_bytes
sta zp_sd_cmd_address
lda #>cmd8_bytes
sta zp_sd_cmd_address+1
jsr sd_sendcommand
; Expect status response $01 (not initialized)
cmp #$01
bne .initfailed
; Read 32-bit return value, but ignore it
jsr sd_readbyte
jsr sd_readbyte
jsr sd_readbyte
jsr sd_readbyte
jsr longdelay
lda #'Y'
jsr print_char
; loop forever
.loop:
jmp .loop
.initfailed
lda #'X'
jsr print_char
jmp .loop
cmd0_bytes
.byte $40, $00, $00, $00, $00, $95
cmd8_bytes
.byte $48, $00, $00, $01, $aa, $87
sd_readbyte:
; Enable the card and tick the clock 8 times with MOSI high,
; capturing bits from MISO and returning them
ldx #8 ; we'll read 8 bits
.loop:
lda #SD_MOSI ; enable card (CS low), set MOSI (resting state), SCK low
sta PORTA
lda #SD_MOSI | SD_SCK ; toggle the clock high
sta PORTA
lda PORTA ; read next bit
and #SD_MISO
clc ; default to clearing the bottom bit
beq .bitnotset ; unless MISO was set
sec ; in which case get ready to set the bottom bit
.bitnotset:
tya ; transfer partial result from Y
rol ; rotate carry bit into read result
tay ; save partial result back to Y
dex ; decrement counter
bne .loop ; loop if we need to read more bits
rts
sd_writebyte:
; Tick the clock 8 times with descending bits on MOSI
; SD communication is mostly half-duplex so we ignore anything it sends back here
ldx #8 ; send 8 bits
.loop:
asl ; shift next bit into carry
tay ; save remaining bits for later
lda #0
bcc .sendbit ; if carry clear, don't set MOSI for this bit
ora #SD_MOSI
.sendbit:
sta PORTA ; set MOSI (or not) first with SCK low
eor #SD_SCK
sta PORTA ; raise SCK keeping MOSI the same, to send the bit
tya ; restore remaining bits to send
dex
bne .loop ; loop if there are more bits to send
rts
sd_waitresult:
; Wait for the SD card to return something other than $ff
jsr sd_readbyte
cmp #$ff
beq sd_waitresult
rts
sd_sendcommand:
; Debug print which command is being executed
jsr lcd_cleardisplay
lda #'c'
jsr print_char
ldx #0
lda (zp_sd_cmd_address,x)
jsr print_hex
lda #SD_MOSI ; pull CS low to begin command
sta PORTA
ldy #0
lda (zp_sd_cmd_address),y ; command byte
jsr sd_writebyte
ldy #1
lda (zp_sd_cmd_address),y ; data 1
jsr sd_writebyte
ldy #2
lda (zp_sd_cmd_address),y ; data 2
jsr sd_writebyte
ldy #3
lda (zp_sd_cmd_address),y ; data 3
jsr sd_writebyte
ldy #4
lda (zp_sd_cmd_address),y ; data 4
jsr sd_writebyte
ldy #5
lda (zp_sd_cmd_address),y ; crc
jsr sd_writebyte
jsr sd_waitresult
pha
; Debug print the result code
jsr print_hex
; End command
lda #SD_CS | SD_MOSI ; set CS high again
sta PORTA
pla ; restore result code
rts
lcd_wait:
pha
lda #%00000000 ; Port B is input
sta DDRB
.busy:
lda #RW
sta PORTA
lda #(RW | E)
sta PORTA
lda PORTB
and #%10000000
bne .busy
lda #RW
sta PORTA
lda #%11111111 ; Port B is output
sta DDRB
pla
rts
lcd_instruction:
jsr lcd_wait
sta PORTB
lda #0 ; Clear RS/RW/E bits
sta PORTA
lda #E ; Set E bit to send instruction
sta PORTA
lda #0 ; Clear RS/RW/E bits
sta PORTA
rts
lcd_init:
lda #%00111000 ; Set 8-bit mode; 2-line display; 5x8 font
jsr lcd_instruction
lda #%00001110 ; Display on; cursor on; blink off
jsr lcd_instruction
lda #%00000110 ; Increment and shift cursor; don't shift display
jsr lcd_instruction
lcd_cleardisplay:
lda #%00000001 ; Clear display
jmp lcd_instruction
print_char:
jsr lcd_wait
sta PORTB
lda #RS ; Set RS; Clear RW/E bits
sta PORTA
lda #(RS | E) ; Set E bit to send instruction
sta PORTA
lda #RS ; Clear E bits
sta PORTA
rts
print_hex:
pha
ror
ror
ror
ror
jsr print_nybble
pla
print_nybble:
and #15
cmp #10
bmi .skipletter
adc #6
.skipletter
adc #48
jsr print_char
rts
delay
ldx #0
ldy #0
.loop
dey
bne .loop
dex
bne .loop
rts
longdelay
jsr mediumdelay
jsr mediumdelay
jsr mediumdelay
mediumdelay
jsr delay
jsr delay
jsr delay
jmp delay
.org $fffc
.word reset
.word $0000