]>
Commit | Line | Data |
---|---|---|
9c15f366 L |
1 | ; MMC/SD-Card routines |
2 | ; | |
3 | ; Copyright (C) 2010 Leo C. | |
4 | ; | |
5 | ; This file is part of avrcpm. | |
6 | ; | |
7 | ; avrcpm is free software: you can redistribute it and/or modify it | |
8 | ; under the terms of the GNU General Public License as published by | |
9 | ; the Free Software Foundation, either version 3 of the License, or | |
10 | ; (at your option) any later version. | |
11 | ; | |
12 | ; avrcpm is distributed in the hope that it will be useful, | |
13 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ; GNU General Public License for more details. | |
16 | ; | |
17 | ; You should have received a copy of the GNU General Public License | |
18 | ; along with avrcpm. If not, see <http://www.gnu.org/licenses/>. | |
19 | ; | |
20 | ; $Id$ | |
21 | ; | |
22 | ||
23 | /* Definitions for MMC/SDC command */ | |
24 | #define CMD0 (0) /* GO_IDLE_STATE */ | |
25 | #define CMD1 (1) /* SEND_OP_COND (MMC) */ | |
26 | #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ | |
27 | #define CMD8 (8) /* SEND_IF_COND */ | |
28 | #define CMD9 (9) /* SEND_CSD */ | |
29 | #define CMD10 (10) /* SEND_CID */ | |
30 | #define CMD12 (12) /* STOP_TRANSMISSION */ | |
31 | #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ | |
32 | #define CMD16 (16) /* SET_BLOCKLEN */ | |
33 | #define CMD17 (17) /* READ_SINGLE_BLOCK */ | |
34 | #define CMD18 (18) /* READ_MULTIPLE_BLOCK */ | |
35 | #define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */ | |
36 | #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ | |
37 | #define CMD24 (24) /* WRITE_BLOCK */ | |
38 | #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ | |
39 | #define CMD55 (55) /* APP_CMD */ | |
40 | #define CMD58 (58) /* READ_OCR */ | |
41 | ||
34527fc2 | 42 | /* Disk Status Bits (masks) (DSTATUS) */ |
9c15f366 L |
43 | #define MMCST_NOINIT 0x01 /* Drive not initialized */ |
44 | #define MMCST_NODISK 0x02 /* No medium in the drive */ | |
45 | #define MMCST_PROTECT 0x04 /* Write protected */ | |
46 | ||
34527fc2 | 47 | /* Card type flags (masks) (CardType) */ |
9c15f366 L |
48 | #define CT_MMC 0x01 /* MMC ver 3 */ |
49 | #define CT_SD1 0x02 /* SD ver 1 */ | |
50 | #define CT_SD2 0x04 /* SD ver 2 */ | |
51 | #define CT_SDC (CT_SD1|CT_SD2) /* SD */ | |
52 | #define CT_BLOCK 0x08 /* Block addressing */ | |
53 | ||
54 | #define RES_OK 0 /* 0: Successful */ | |
55 | #define RES_ERROR 1 /* 1: R/W Error */ | |
56 | #define RES_WRPRT 2 /* 2: Write Protected */ | |
57 | #define RES_NOTRDY 3 /* 3: Not Ready */ | |
58 | #define RES_PARERR 4 /* 4: Invalid Parameter */ | |
59 | ||
4160d270 L |
60 | |
61 | #define SPI_MODE_0 (0<<CPOL)|(0<<CPHA) | |
62 | #define SPI_MODE_1 (0<<CPOL)|(1<<CPHA) | |
63 | #define SPI_MODE_2 (1<<CPOL)|(0<<CPHA) | |
64 | #define SPI_MODE_3 (1<<CPOL)|(1<<CPHA) | |
65 | #define SPI_MODE SPI_MODE_0 | |
66 | ||
9c15f366 L |
67 | ;------------------------------------------------ |
68 | ; | |
69 | .macro spi_clkslow | |
70 | .if MMC_DEBUG > 1 | |
71 | printstring "SPI_CLK_SLOW " | |
72 | .endif | |
4160d270 | 73 | ldi temp,SPI_MODE|(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0) ;clk/128 |
9c15f366 L |
74 | out SPCR,temp |
75 | out SPSR,_0 | |
76 | .endm | |
77 | ||
78 | ;------------------------------------------------ | |
79 | ; | |
80 | .macro spi_clkfast | |
81 | .if MMC_DEBUG > 1 | |
82 | printstring "SPI_CLK_FAST " | |
83 | .endif | |
4160d270 | 84 | ldi temp,SPI_MODE|(1<<SPE)|(1<<MSTR) ;clk/4 |
9c15f366 L |
85 | out SPCR,temp |
86 | #if MMC_SPI2X | |
87 | ldi temp,(1<<SPI2X) | |
88 | out SPSR,temp | |
89 | #else | |
90 | out SPSR,_0 | |
91 | #endif | |
92 | .endm | |
93 | ||
94 | ;------------------------------------------------ | |
95 | ; | |
96 | .macro spi_disable | |
97 | .if MMC_DEBUG > 1 | |
98 | printstring "SPI_DISABLE " | |
99 | .endif | |
100 | out SPCR,_0 | |
101 | .endm | |
102 | ||
103 | ||
104 | ;------------------------------------------------ | |
105 | ; | |
106 | .macro spi_waitm | |
107 | .set spiwl_ = PC | |
108 | sbism8 SPSR,SPIF | |
109 | rjmp spiwl_ | |
110 | .endm | |
111 | ||
112 | ;------------------------------------------------ | |
113 | ||
114 | .dseg | |
115 | ||
116 | mmcStat: | |
117 | .byte 1 | |
118 | mmcCardType: | |
119 | .byte 1 | |
9c15f366 L |
120 | |
121 | ||
122 | .cseg | |
123 | ||
124 | ;------------------------------------------------ | |
125 | ; Multiply 32 bit value in yh,yl,xh,xl by 512 | |
126 | ||
127 | mul_yx_512: | |
128 | mov yh,yl | |
129 | mov yl,xh | |
130 | mov xh,xl | |
131 | ldi xl,0 | |
132 | lsl xh | |
133 | rol yl | |
134 | rol yh | |
135 | ret | |
136 | ||
137 | ;------------------------------------------------ | |
138 | spi_rcvr: | |
139 | out SPDR,_255 | |
140 | spi_rcvr_l: | |
141 | sbism8 SPSR,SPIF | |
142 | rjmp spi_rcvr_l | |
143 | in temp,SPDR | |
144 | .if MMC_DEBUG > 2 | |
9c15f366 L |
145 | printstring "<" |
146 | rcall printhex | |
147 | printstring " " | |
9c15f366 L |
148 | .endif |
149 | ret | |
150 | ||
151 | ;------------------------------------------------ | |
152 | spi_xmit: | |
153 | .if MMC_DEBUG > 2 | |
154 | printstring ">" | |
155 | rcall printhex | |
156 | printstring " " | |
157 | .endif | |
158 | out SPDR,temp | |
159 | ;fall thru | |
160 | spi_wait: | |
161 | sbism8 SPSR,SPIF | |
162 | rjmp spi_wait | |
163 | ret | |
164 | ||
165 | ;------------------------------------------------ | |
166 | ; Wait for card ready | |
167 | ; return 1:OK, 0:Timeout | |
168 | ||
169 | mmcWaitReady: | |
170 | push temp2 | |
171 | ldi temp2,2 ;Wait for ready in timeout of 500ms. | |
172 | rcall spi_rcvr | |
173 | mmc_wrl: | |
174 | sts delay_timer2,_255 | |
175 | mmc_wrl1: | |
176 | rcall spi_rcvr | |
177 | cp temp,_255 | |
178 | brne mmc_wrl2 | |
179 | ldi temp,1 | |
180 | rjmp mmc_wrbreak | |
181 | ||
182 | mmc_wrl2: | |
183 | lds temp,delay_timer2 | |
184 | cpi temp,0 | |
185 | brne mmc_wrl1 | |
186 | dec temp2 | |
187 | brne mmc_wrl ;tmp is 0 here | |
188 | ||
189 | mmc_wrbreak: | |
190 | pop temp2 | |
191 | tst temp ;set flags | |
192 | ret | |
193 | ||
194 | ||
195 | ;------------------------------------------------ | |
196 | ; Deselect the card and release SPI bus | |
197 | ; return 0 | |
198 | ||
199 | mmcDeselect: | |
200 | sbi P_MMC_CS,mmc_cs ; CS high | |
201 | rcall spi_rcvr | |
202 | clr temp | |
203 | ret | |
204 | ||
205 | ;------------------------------------------------ | |
206 | ; Select the card and wait for ready | |
207 | ; return 255:Successful, 0:Timeout | |
208 | ||
209 | mmcSelect: | |
210 | cbi P_MMC_CS,mmc_cs ; CS low | |
211 | rcall mmcWaitReady | |
212 | breq mmcDeselect ;return via Deselect | |
213 | sbr temp,255 | |
214 | ret | |
215 | ||
216 | ||
217 | ;------------------------------------------------ | |
218 | ; Send a command packet to MMC | |
219 | ; temp2: Command | |
220 | ; yh..xl: Argument | |
34527fc2 L |
221 | ; return: |
222 | ; temp: 0 = ok, no error | |
223 | ; z-flag 1 = ok, no error | |
224 | ; | |
9c15f366 L |
225 | |
226 | mmcCmd: | |
227 | sbrs temp2,7 | |
228 | rjmp mmc_cmddo | |
229 | ||
230 | ; ACMD<n> is the command sequence of CMD55-CMD<n> | |
231 | ||
232 | push yh | |
233 | push yl | |
234 | push xh | |
235 | push xl | |
236 | push temp2 | |
237 | ldiw y,0 | |
238 | movw x,y | |
239 | ldi temp2,CMD55 | |
240 | rcall mmcCmd | |
241 | pop temp2 | |
242 | pop xl | |
243 | pop xh | |
244 | pop yl | |
245 | pop yh | |
246 | ||
247 | cpi temp,2 | |
248 | brlo mmc_cmddo ; fall thru, if (retval <= 1) | |
249 | ||
250 | tst temp | |
251 | ret ; else return error | |
252 | ||
253 | ; Select the card and wait for ready | |
254 | ||
255 | mmc_cmddo: | |
256 | .if MMC_DEBUG | |
257 | sbrc temp2,7 | |
258 | rjmp dmmccmd_nonl | |
259 | printnewline | |
260 | ||
261 | dmmccmd_nonl: | |
262 | printstring "mmcCMD: " | |
263 | mov temp,temp2 | |
264 | cbr temp,0x80 | |
265 | rcall printhex | |
266 | printstring " " | |
267 | push temp2 | |
268 | movw temp,y | |
269 | rcall printhexw | |
270 | movw temp,x | |
271 | rcall printhexw | |
272 | printstring " " | |
273 | pop temp2 | |
274 | .endif | |
275 | rcall mmcDeselect | |
276 | rcall mmcSelect | |
277 | brne mmc_cmd_p | |
278 | ||
279 | ldi temp,0xFF | |
280 | rjmp mmc_cmdexit | |
281 | ||
282 | ; Send command packet | |
283 | ||
284 | mmc_cmd_p: | |
285 | mov temp,temp2 | |
286 | cbr temp,0x80 | |
287 | sbr temp,0x40 | |
288 | rcall spi_xmit | |
289 | out SPDR,yh | |
290 | rcall spi_wait | |
291 | out SPDR,yl | |
292 | rcall spi_wait | |
293 | out SPDR,xh | |
294 | rcall spi_wait | |
295 | out SPDR,xl | |
296 | rcall spi_wait | |
297 | ||
298 | ldi temp,0x95 ;CRC for CMD0(0) | |
299 | cpi temp2,CMD0 | |
300 | breq mmc_cmdxcrc | |
301 | ldi temp,0x87 ;CRC for CMD8(0x1AA) | |
302 | cpi temp2,CMD8 | |
303 | breq mmc_cmdxcrc | |
304 | ldi temp,0x01 ;Dummy CRC + Stop | |
305 | mmc_cmdxcrc: | |
306 | .if MMC_DEBUG | |
307 | printstring ".. " | |
308 | rcall printhex | |
309 | .endif | |
310 | rcall spi_xmit | |
311 | ||
312 | ; Receive command response | |
313 | ||
314 | cpi temp2,CMD12 ; Skip a stuff byte when stop reading | |
315 | brne mmc_cmdres | |
316 | rcall spi_rcvr | |
317 | ||
318 | ; Wait for a valid response in timeout of 10 attempts | |
319 | ||
320 | mmc_cmdres: | |
825ecc9d L |
321 | push temp2 |
322 | ldi temp2,10 | |
9c15f366 L |
323 | mmc_cmdrl: |
324 | rcall spi_rcvr | |
325 | sbrs temp,7 | |
326 | rjmp mmc_cmdexit | |
825ecc9d | 327 | dec temp2 |
9c15f366 L |
328 | brne mmc_cmdrl |
329 | ||
330 | ; Return with response value | |
331 | ||
332 | mmc_cmdexit: | |
825ecc9d | 333 | pop temp2 |
9c15f366 L |
334 | .if MMC_DEBUG |
335 | printstring " CMDRes: " | |
336 | rcall printhex | |
337 | printstring " " | |
338 | rcall uart_wait_empty | |
339 | .endif | |
340 | tst temp ;set flags | |
341 | ret | |
342 | ||
08716d4f L |
343 | ;------------------------------------------------ |
344 | ; Send command and receive ocr response | |
345 | ; temp2: Command, zl: expected cmd response | |
346 | ; yh..xl: Argument | |
347 | ; return: yh..xl: ocr, z flag == 1, if return from mmcCmd was ok. | |
348 | ||
349 | mmcCmd_ocr: | |
350 | ||
351 | rcall mmcCmd | |
352 | ||
353 | cp temp,zl ; | |
354 | brne mmc_cocr_e | |
355 | ||
356 | ; Get trailing return value of R7 response | |
357 | ||
358 | ldi temp2,4 | |
359 | ldiw z,0x1a ;memory address of xl | |
360 | mmc_cocr1: | |
361 | rcall spi_rcvr | |
362 | st z+,temp | |
363 | dec temp2 | |
364 | brne mmc_cocr1 | |
365 | ;z-flag =1 | |
366 | mmc_cocr_e: | |
367 | ret | |
368 | ||
9c15f366 L |
369 | ;------------------------------------------------ |
370 | ; Check if 1 sec timeout | |
371 | ; return Z-Flag set, if timeout | |
372 | ||
373 | mmc_timeout_1s: | |
374 | lds temp,delay_timer1 | |
375 | tst temp | |
376 | brne mmc_ttex | |
825ecc9d | 377 | dec zh |
9c15f366 L |
378 | breq mmc_ttex |
379 | ldi temp,100 | |
380 | sts delay_timer1,temp | |
381 | mmc_ttex: | |
382 | ret | |
383 | ||
384 | ||
385 | ;------------------------------------------------ | |
386 | ; "Public" functions | |
387 | ;------------------------------------------------ | |
388 | ||
389 | ;------------------------------------------------ | |
390 | ; Initialize MMC/SD card | |
391 | ||
392 | mmcInit: | |
393 | .if MMC_DEBUG | |
394 | printnewline | |
395 | printstring "mmcInit " | |
396 | .endif | |
397 | lds temp,mmcStat ;Set 'NO INIT' status | |
398 | sbr temp,MMCST_NOINIT | |
399 | sts mmcStat,temp | |
400 | ||
401 | spi_clkslow | |
402 | ldi temp2,10 | |
403 | mmci_lp: | |
404 | rcall spi_rcvr | |
405 | dec temp2 ;80 dummy clocks | |
406 | brne mmci_lp | |
407 | ||
408 | ldi temp3,0 ;Card type | |
409 | ldi temp2,CMD0 | |
410 | ldiw y,0 | |
411 | movw x,y | |
412 | rcall mmcCmd ;Enter Idle state | |
413 | cpi temp,1 | |
414 | breq mmci_1 | |
415 | rjmp mmci_lend | |
416 | mmci_1: | |
825ecc9d | 417 | ldi zh,10 ;Initialization timeout of 1000 ms. |
9c15f366 L |
418 | ldi temp,100 |
419 | sts delay_timer1,temp | |
420 | ldi temp2,CMD8 | |
421 | ldiw y,0 | |
422 | ldi xh,0x01 | |
423 | ldi xl,0xAA | |
08716d4f L |
424 | ldi zl,1 |
425 | rcall mmcCmd_ocr | |
426 | brne mmci_sdv1 ;SDv2? | |
9c15f366 | 427 | |
08716d4f L |
428 | cpi yl,0x01 ;ocr[2] |
429 | brne mmci_sdv1 | |
430 | cpi yh,0xAA ;ocr[3] | |
9c15f366 L |
431 | brne mmci_sdv1 |
432 | ||
433 | ; The card can work at vdd range of 2.7-3.6V. | |
434 | ; Wait for leaving idle state (ACMD41 with HCS bit). | |
435 | ||
436 | ldi temp2,ACMD41 | |
437 | ldi yh,0x40 | |
438 | ldi yl,0 | |
439 | ldi xh,0 | |
440 | ldi xl,0 | |
441 | mmci_v2l2: | |
442 | rcall mmcCmd | |
443 | breq mmci_ccc | |
444 | rcall mmc_timeout_1s | |
445 | brne mmci_v2l2 | |
446 | rjmp mmci_sdv2end | |
447 | ||
448 | ; Check CCS bit in the OCR | |
449 | mmci_ccc: | |
450 | ldi temp2,CMD58 | |
451 | ldi yh,0 | |
08716d4f L |
452 | ldi zl,0 |
453 | rcall mmcCmd_ocr | |
454 | ||
9c15f366 L |
455 | brne mmci_sdv2end |
456 | ||
9c15f366 | 457 | sbr temp3,CT_SD2 |
08716d4f | 458 | sbrc xl,6 |
9c15f366 L |
459 | sbr temp3,CT_BLOCK |
460 | ||
461 | mmci_sdv2end: | |
462 | rjmp mmci_lend | |
463 | ||
464 | ; SDv1 or MMCv3 | |
465 | ||
466 | mmci_sdv1: | |
467 | ldi temp2,ACMD41 | |
468 | ldiw y,0 | |
469 | movw x,y | |
470 | rcall mmcCmd | |
471 | cpi temp,2 | |
472 | brsh mmci_mmcv3 | |
473 | sbr temp3,CT_SD1 ;SDv1 | |
474 | ldi temp2,ACMD41 | |
475 | rjmp mmci_v1_l | |
476 | mmci_mmcv3: | |
477 | sbr temp3,CT_MMC ;MMCv3 | |
478 | ldi temp2,CMD1 | |
479 | ||
480 | ; Wait for leaving idle state | |
481 | mmci_v1_l: | |
482 | rcall mmcCmd | |
483 | breq mmci_v1_2 | |
484 | rcall mmc_timeout_1s | |
485 | brne mmci_v1_l | |
486 | rjmp mmci_lend ;Timeout | |
487 | ||
488 | ; Set R/W block length to 512 | |
489 | mmci_v1_2: | |
490 | ldi temp2,CMD16 | |
491 | ldiw x,512 | |
492 | rcall mmcCmd | |
493 | breq mmci_lend | |
494 | ldi temp3,0 | |
495 | ||
496 | mmci_lend: | |
497 | sts mmcCardType,temp3 | |
498 | rcall mmcDeselect | |
499 | ||
500 | ; Initialization succeded? | |
501 | ||
502 | lds temp,mmcStat | |
503 | tst temp3 | |
504 | breq mmci_lex | |
505 | cbr temp,MMCST_NOINIT ;Yes, clear 'NO INIT' status | |
506 | sts mmcStat,temp | |
507 | mmci_lex: | |
508 | ||
509 | .if MMC_DEBUG | |
510 | printnewline | |
511 | printstring " CT: " | |
512 | push temp | |
513 | lds temp,mmcCardType | |
34527fc2 | 514 | lcall printhex |
9c15f366 L |
515 | pop temp |
516 | printstring " InitRes: " | |
34527fc2 | 517 | lcall printhex |
9c15f366 L |
518 | printstring " " |
519 | .endif | |
520 | ||
521 | spi_disable | |
522 | ret | |
523 | ||
9c15f366 | 524 | ;-------------------------------------------------------------- |
34527fc2 L |
525 | |
526 | .equ MMC_RDOP = 0 ;Read Operation | |
527 | .equ MMC_RDWORD = 1 ;Read Word (FAT entry) | |
528 | ||
529 | ;-------------------------------------------------------------- | |
9c15f366 L |
530 | |
531 | mmcReadSect: | |
34527fc2 | 532 | |
9c15f366 L |
533 | .if MMC_DEBUG > 1 |
534 | printnewline | |
535 | printstring "mmcRdSect " | |
536 | .endif | |
34527fc2 L |
537 | ldi temp3,(1<<MMC_RDOP) |
538 | rjmp mmc_rw_common | |
539 | ||
540 | mmcReadWord: | |
541 | ||
542 | .if MMC_DEBUG > 1 | |
543 | printnewline | |
544 | printstring "mmcRdWord " | |
545 | .endif | |
546 | ldi temp3,(1<<MMC_RDOP) | (1<<MMC_RDWORD) | |
547 | rjmp mmc_rw_common | |
548 | ||
549 | mmcWriteSect: | |
550 | ||
551 | .if MMC_DEBUG > 1 | |
552 | printnewline | |
553 | printstring "mmcWrSect " | |
554 | .endif | |
555 | ldi temp3,0 | |
9c15f366 | 556 | |
34527fc2 L |
557 | mmc_rw_common: |
558 | lds temp,mmcStat | |
559 | ldi temp2,RES_NOTRDY | |
560 | sbrc temp,log2(MMCST_NOINIT) | |
561 | rjmp mmc_rwexit_2 | |
9c15f366 L |
562 | |
563 | spi_clkfast | |
564 | lds temp,mmcCardType | |
565 | sbrs temp,log2(CT_BLOCK) | |
566 | rcall mul_yx_512 ;Convert to byte address (*512) | |
9c15f366 | 567 | |
34527fc2 L |
568 | sbrc temp3,MMC_RDOP |
569 | ldi temp2,CMD17 | |
570 | sbrs temp3,MMC_RDOP | |
571 | ldi temp2,CMD24 | |
572 | rcall mmcCmd | |
573 | breq mmc_rw_1 | |
574 | rjmp mmc_rwexit_error | |
575 | ||
576 | mmc_rw_1: | |
577 | ldiw y,hostbuf ;aarrrgh | |
578 | sbrs temp3,MMC_RDWORD | |
579 | movw z,y | |
580 | ldiw y,512 | |
581 | sbrs temp3,MMC_RDOP | |
582 | rjmp mmc_wroper | |
583 | ||
584 | ;------------------------------------------------------------------------------- | |
9c15f366 L |
585 | ; Receive a data packet from MMC |
586 | ||
9c15f366 L |
587 | ldi temp,200 ;Wait for data packet in timeout of 200ms. |
588 | sts delay_timer1,temp | |
589 | mmc_rcv_wl: | |
590 | rcall spi_rcvr | |
591 | cp temp,_255 | |
592 | brne mmc_rcv_start | |
593 | lds _tmp0,delay_timer1 | |
594 | cp _tmp0,_0 | |
595 | brne mmc_rcv_wl | |
596 | .if MMC_DEBUG > 1 | |
597 | printstring "TIMEOUT " | |
598 | rjmp mmc_rcv_dbg1 | |
599 | .endif | |
600 | ||
601 | mmc_rcv_start: | |
602 | .if MMC_DEBUG > 1 | |
603 | cpi temp,0xFE ;If not valid data token, | |
604 | breq mmc_rcv_dbg1 | |
605 | printstring "Token: " | |
34527fc2 | 606 | lcall printhex |
9c15f366 L |
607 | printstring " " |
608 | mmc_rcv_dbg1: | |
609 | .endif | |
610 | cpi temp,0xFE ;If not valid data token, | |
34527fc2 L |
611 | breq mmc_rw_2 |
612 | rjmp mmc_rwexit_error | |
613 | mmc_rw_2: | |
614 | ||
9c15f366 | 615 | rcall spi_rcvr ;Shift in first byte. |
4160d270 L |
616 | .if MMC_DEBUG > 3 |
617 | printnewline | |
34527fc2 | 618 | lcall printhex |
4160d270 L |
619 | printstring " " |
620 | .endif | |
9c15f366 | 621 | out SPDR,_255 ;Start shift in next byte. |
9c15f366 | 622 | |
34527fc2 L |
623 | sbrs temp3,MMC_RDWORD |
624 | rjmp mmc_rcv_readloop | |
92202636 | 625 | |
34527fc2 | 626 | ; discard x-1 bytes |
64219415 | 627 | |
64219415 FZ |
628 | mmc_rcvw_rl: |
629 | sbiw yl,1 | |
34527fc2 | 630 | breq mmc_rcv_rlend |
08716d4f L |
631 | cp zl,_0 |
632 | cpc zh,_0 | |
92202636 L |
633 | breq mmc_rcvw_sto |
634 | ||
635 | sbiw zl,1 | |
64219415 | 636 | spi_waitm |
08716d4f L |
637 | in temp,SPDR |
638 | out SPDR,_255 | |
64219415 FZ |
639 | rjmp mmc_rcvw_rl |
640 | ||
34527fc2 L |
641 | ; read next two bytes |
642 | ||
92202636 L |
643 | mmc_rcvw_sto: |
644 | mov zl,temp | |
678fc0b0 | 645 | spi_waitm |
08716d4f L |
646 | in temp,SPDR |
647 | out SPDR,_255 | |
92202636 L |
648 | mov zh,temp |
649 | ||
34527fc2 L |
650 | ; discard the rest |
651 | ||
678fc0b0 FZ |
652 | mmc_rcvw_rl2: |
653 | sbiw yl,1 | |
34527fc2 | 654 | breq mmc_rcv_rlend |
678fc0b0 | 655 | spi_waitm |
08716d4f L |
656 | in temp,SPDR |
657 | out SPDR,_255 | |
92202636 | 658 | rjmp mmc_rcvw_rl2 |
9c15f366 | 659 | |
34527fc2 | 660 | ; read sector, store in buffer |
9c15f366 | 661 | |
34527fc2 L |
662 | mmc_rcv_readloop: |
663 | sbiw yl,1 | |
664 | breq mmc_rcv_rle | |
665 | st z+,temp | |
666 | spi_waitm | |
667 | in temp,SPDR | |
668 | .if MMC_DEBUG > 3 | |
669 | lcall printhex | |
670 | printstring " " | |
671 | .endif | |
672 | out SPDR,_255 | |
673 | rjmp mmc_rcv_readloop | |
674 | ||
675 | mmc_rcv_rle: | |
676 | st z+,temp ;Store last byte in buffer | |
677 | mmc_rcv_rlend: | |
678 | .if MMC_DEBUG > 3 | |
9c15f366 | 679 | printnewline |
9c15f366 | 680 | .endif |
34527fc2 L |
681 | rcall spi_wait ;while SPI module shifts in crc part1. |
682 | rcall spi_rcvr ;Read second crc. | |
9c15f366 | 683 | |
34527fc2 L |
684 | ldi temp2,RES_OK ;Return success |
685 | rjmp mmc_rwexit | |
9c15f366 | 686 | |
9c15f366 | 687 | |
34527fc2 | 688 | ;------------------------------------------------------------------------------- |
9c15f366 L |
689 | ; Send a data packet to MMC |
690 | ||
34527fc2 L |
691 | mmc_wroper: |
692 | ||
9c15f366 L |
693 | .if MMC_DEBUG > 2 |
694 | ; printnewline | |
695 | printstring "mmcXMIT " | |
696 | .endif | |
697 | rcall mmcWaitReady | |
34527fc2 | 698 | breq mmc_rwexit_error |
9c15f366 L |
699 | |
700 | ldi temp,0xFE ;Data token | |
701 | out SPDR,temp | |
9c15f366 L |
702 | mmc_x_loop: |
703 | ld temp,z+ | |
704 | spi_waitm | |
705 | out SPDR,temp | |
706 | sbiw yl,1 | |
707 | brne mmc_x_loop | |
708 | ||
709 | rcall spi_wait | |
710 | ldi temp,0xFF ;dummy crc | |
711 | rcall spi_xmit | |
712 | rcall spi_xmit | |
713 | rcall spi_rcvr | |
714 | .if MMC_DEBUG > 2 | |
715 | printstring "XMITRes: " | |
34527fc2 | 716 | lcall printhex |
9c15f366 L |
717 | printstring " " |
718 | .endif | |
719 | andi temp,0x1F ;If not accepted, return with error | |
720 | cpi temp,0x05 | |
721 | ldi temp2,RES_OK ;Return success | |
34527fc2 | 722 | breq mmc_rwexit |
9c15f366 | 723 | |
34527fc2 L |
724 | mmc_rwexit_error: |
725 | ldi temp2,RES_ERROR | |
726 | mmc_rwexit: | |
9c15f366 L |
727 | rcall mmcDeselect |
728 | spi_disable | |
34527fc2 | 729 | mmc_rwexit_2: |
9c15f366 | 730 | mov temp,temp2 |
34527fc2 | 731 | |
9c15f366 | 732 | .if MMC_DEBUG > 1 |
34527fc2 L |
733 | sbrc temp3,MMC_RDOP |
734 | rjmp mmc_dbg_rder | |
735 | ||
736 | printstring "WrSectRes: " | |
737 | rjmp mmc_dbg_rwerex | |
738 | ||
739 | mmc_dbg_rder: | |
740 | sbrc temp3,MMC_RDWORD | |
741 | rjmp mmc_dbg_rdwder | |
742 | printstring "RdSectRes: " | |
743 | rjmp mmc_dbg_rwerex | |
744 | ||
745 | mmc_dbg_rdwder: | |
746 | printstring "RdWordRes: " | |
747 | mmc_dbg_rwerex: | |
748 | lcall printhex | |
9c15f366 L |
749 | printstring " " |
750 | .endif | |
751 | ret | |
752 | ||
753 | ;-------------------------------------------------------------- | |
754 | ; vim:set ts=8 noet nowrap | |
755 |