]> cloudbase.mooo.com Git - avrcpm.git/blob - mmc.asm
* Test: change directory hierarchy.
[avrcpm.git] / mmc.asm
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
42 /* Disk Status Bits (DSTATUS) */
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
47 /* Card type flags (CardType) */
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
60 ;------------------------------------------------
61 ;
62 .macro spi_clkslow
63 .if MMC_DEBUG > 1
64 printstring "SPI_CLK_SLOW "
65 .endif
66 ldi temp,(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0) ;clk/128
67 out SPCR,temp
68 out SPSR,_0
69 .endm
70
71 ;------------------------------------------------
72 ;
73 .macro spi_clkfast
74 .if MMC_DEBUG > 1
75 printstring "SPI_CLK_FAST "
76 .endif
77 ldi temp,(1<<SPE)|(1<<MSTR) ;clk/4
78 out SPCR,temp
79 #if MMC_SPI2X
80 ldi temp,(1<<SPI2X)
81 out SPSR,temp
82 #else
83 out SPSR,_0
84 #endif
85 .endm
86
87 ;------------------------------------------------
88 ;
89 .macro spi_disable
90 .if MMC_DEBUG > 1
91 printstring "SPI_DISABLE "
92 .endif
93 out SPCR,_0
94 .endm
95
96
97 ;------------------------------------------------
98 ;
99 .macro spi_waitm
100 .set spiwl_ = PC
101 sbism8 SPSR,SPIF
102 rjmp spiwl_
103 .endm
104
105 ;------------------------------------------------
106
107 .dseg
108
109 mmcStat:
110 .byte 1
111 mmcCardType:
112 .byte 1
113 mmc_ocr:
114 .byte 4
115
116
117
118 .cseg
119
120 ;------------------------------------------------
121 ; Multiply 32 bit value in yh,yl,xh,xl by 512
122
123 mul_yx_512:
124 mov yh,yl
125 mov yl,xh
126 mov xh,xl
127 ldi xl,0
128 lsl xh
129 rol yl
130 rol yh
131 ret
132
133 ;------------------------------------------------
134 spi_rcvr:
135 out SPDR,_255
136 spi_rcvr_l:
137 sbism8 SPSR,SPIF
138 rjmp spi_rcvr_l
139 in temp,SPDR
140 .if MMC_DEBUG > 2
141 push temp
142 printstring "<"
143 rcall printhex
144 printstring " "
145 pop temp
146 .endif
147 ret
148
149 ;------------------------------------------------
150 spi_xmit:
151 .if MMC_DEBUG > 2
152 printstring ">"
153 rcall printhex
154 printstring " "
155 .endif
156 out SPDR,temp
157 ;fall thru
158 spi_wait:
159 sbism8 SPSR,SPIF
160 rjmp spi_wait
161 ret
162
163 ;------------------------------------------------
164 ; Wait for card ready
165 ; return 1:OK, 0:Timeout
166
167 mmcWaitReady:
168 push temp2
169 ldi temp2,2 ;Wait for ready in timeout of 500ms.
170 rcall spi_rcvr
171 mmc_wrl:
172 sts delay_timer2,_255
173 mmc_wrl1:
174 rcall spi_rcvr
175 cp temp,_255
176 brne mmc_wrl2
177 ldi temp,1
178 rjmp mmc_wrbreak
179
180 mmc_wrl2:
181 lds temp,delay_timer2
182 cpi temp,0
183 brne mmc_wrl1
184 dec temp2
185 brne mmc_wrl ;tmp is 0 here
186
187 mmc_wrbreak:
188 pop temp2
189 tst temp ;set flags
190 ret
191
192
193 ;------------------------------------------------
194 ; Deselect the card and release SPI bus
195 ; return 0
196
197 mmcDeselect:
198 sbi P_MMC_CS,mmc_cs ; CS high
199 rcall spi_rcvr
200 clr temp
201 ret
202
203 ;------------------------------------------------
204 ; Select the card and wait for ready
205 ; return 255:Successful, 0:Timeout
206
207 mmcSelect:
208 cbi P_MMC_CS,mmc_cs ; CS low
209 rcall mmcWaitReady
210 breq mmcDeselect ;return via Deselect
211 sbr temp,255
212 ret
213
214
215 ;------------------------------------------------
216 ; Send a command packet to MMC
217 ; temp2: Command
218 ; yh..xl: Argument
219
220 mmcCmd:
221 sbrs temp2,7
222 rjmp mmc_cmddo
223
224 ; ACMD<n> is the command sequence of CMD55-CMD<n>
225
226 push yh
227 push yl
228 push xh
229 push xl
230 push temp2
231 ldiw y,0
232 movw x,y
233 ldi temp2,CMD55
234 rcall mmcCmd
235 pop temp2
236 pop xl
237 pop xh
238 pop yl
239 pop yh
240
241 cpi temp,2
242 brlo mmc_cmddo ; fall thru, if (retval <= 1)
243
244 tst temp
245 ret ; else return error
246
247 ; Select the card and wait for ready
248
249 mmc_cmddo:
250 .if MMC_DEBUG
251 sbrc temp2,7
252 rjmp dmmccmd_nonl
253 printnewline
254
255 dmmccmd_nonl:
256 printstring "mmcCMD: "
257 mov temp,temp2
258 cbr temp,0x80
259 rcall printhex
260 printstring " "
261 push temp2
262 movw temp,y
263 rcall printhexw
264 movw temp,x
265 rcall printhexw
266 printstring " "
267 pop temp2
268 .endif
269 rcall mmcDeselect
270 rcall mmcSelect
271 brne mmc_cmd_p
272
273 ldi temp,0xFF
274 rjmp mmc_cmdexit
275
276 ; Send command packet
277
278 mmc_cmd_p:
279 mov temp,temp2
280 cbr temp,0x80
281 sbr temp,0x40
282 rcall spi_xmit
283 out SPDR,yh
284 rcall spi_wait
285 out SPDR,yl
286 rcall spi_wait
287 out SPDR,xh
288 rcall spi_wait
289 out SPDR,xl
290 rcall spi_wait
291
292 ldi temp,0x95 ;CRC for CMD0(0)
293 cpi temp2,CMD0
294 breq mmc_cmdxcrc
295 ldi temp,0x87 ;CRC for CMD8(0x1AA)
296 cpi temp2,CMD8
297 breq mmc_cmdxcrc
298 ldi temp,0x01 ;Dummy CRC + Stop
299 mmc_cmdxcrc:
300 .if MMC_DEBUG
301 printstring ".. "
302 rcall printhex
303 .endif
304 rcall spi_xmit
305
306 ; Receive command response
307
308 cpi temp2,CMD12 ; Skip a stuff byte when stop reading
309 brne mmc_cmdres
310 rcall spi_rcvr
311
312 ; Wait for a valid response in timeout of 10 attempts
313
314 mmc_cmdres:
315 ldi temp,10
316 mov _tmp1,temp
317 mmc_cmdrl:
318 rcall spi_rcvr
319 sbrs temp,7
320 rjmp mmc_cmdexit
321 dec _tmp1
322 brne mmc_cmdrl
323
324 ; Return with response value
325
326 mmc_cmdexit:
327 .if MMC_DEBUG
328 printstring " CMDRes: "
329 rcall printhex
330 printstring " "
331 rcall uart_wait_empty
332 .endif
333 tst temp ;set flags
334 ret
335
336 ;------------------------------------------------
337 ; Check if 1 sec timeout
338 ; return Z-Flag set, if timeout
339
340 mmc_timeout_1s:
341 lds temp,delay_timer1
342 tst temp
343 brne mmc_ttex
344 dec temp4
345 breq mmc_ttex
346 ldi temp,100
347 sts delay_timer1,temp
348 mmc_ttex:
349 ret
350
351
352 ;------------------------------------------------
353 ; "Public" functions
354 ;------------------------------------------------
355
356 ;------------------------------------------------
357 ; Initialize MMC/SD card
358
359 mmcInit:
360 .if MMC_DEBUG
361 printnewline
362 printstring "mmcInit "
363 .endif
364 lds temp,mmcStat ;Set 'NO INIT' status
365 sbr temp,MMCST_NOINIT
366 sts mmcStat,temp
367
368 spi_clkslow
369 ldi temp2,10
370 mmci_lp:
371 rcall spi_rcvr
372 dec temp2 ;80 dummy clocks
373 brne mmci_lp
374
375 ldi temp3,0 ;Card type
376 ldi temp2,CMD0
377 ldiw y,0
378 movw x,y
379 rcall mmcCmd ;Enter Idle state
380 cpi temp,1
381 breq mmci_1
382 rjmp mmci_lend
383 mmci_1:
384 ldi temp4,10 ;Initialization timeout of 1000 ms.
385 ldi temp,100
386 sts delay_timer1,temp
387 ldi temp2,CMD8
388 ldiw y,0
389 ldi xh,0x01
390 ldi xl,0xAA
391 rcall mmcCmd
392 cpi temp,1 ;SDv2?
393 brne mmci_sdv1
394
395 ; Get trailing return value of R7 response
396
397 ldi temp2,4
398 ldiw z,mmc_ocr
399 mmci_v2l1:
400 rcall spi_rcvr
401 st z+,temp
402 dec temp2
403 brne mmci_v2l1
404 sbiw z,4
405 ldd temp,z+2
406 cpi temp,0x01
407 ldd temp,z+3
408 cpc temp,xl ;Reuse 0xAA value in xl
409 brne mmci_sdv1
410
411 ; The card can work at vdd range of 2.7-3.6V.
412 ; Wait for leaving idle state (ACMD41 with HCS bit).
413
414 ldi temp2,ACMD41
415 ldi yh,0x40
416 ldi yl,0
417 ldi xh,0
418 ldi xl,0
419 mmci_v2l2:
420 rcall mmcCmd
421 breq mmci_ccc
422 rcall mmc_timeout_1s
423 brne mmci_v2l2
424 rjmp mmci_sdv2end
425
426 ; Check CCS bit in the OCR
427 mmci_ccc:
428 ldi temp2,CMD58
429 ldi yh,0
430 rcall mmcCmd
431 brne mmci_sdv2end
432
433 ldi temp2,4
434 mmci_v2l3:
435 rcall spi_rcvr
436 st z+,temp
437 dec temp2
438 brne mmci_v2l3
439 sbiw z,4
440
441 sbr temp3,CT_SD2
442 ldd temp,z+0
443 sbrc temp,6
444 sbr temp3,CT_BLOCK
445
446 mmci_sdv2end:
447 rjmp mmci_lend
448
449 ; SDv1 or MMCv3
450
451 mmci_sdv1:
452 ldi temp2,ACMD41
453 ldiw y,0
454 movw x,y
455 rcall mmcCmd
456 cpi temp,2
457 brsh mmci_mmcv3
458 sbr temp3,CT_SD1 ;SDv1
459 ldi temp2,ACMD41
460 rjmp mmci_v1_l
461 mmci_mmcv3:
462 sbr temp3,CT_MMC ;MMCv3
463 ldi temp2,CMD1
464
465 ; Wait for leaving idle state
466 mmci_v1_l:
467 rcall mmcCmd
468 breq mmci_v1_2
469 rcall mmc_timeout_1s
470 brne mmci_v1_l
471 rjmp mmci_lend ;Timeout
472
473 ; Set R/W block length to 512
474 mmci_v1_2:
475 ldi temp2,CMD16
476 ldiw x,512
477 rcall mmcCmd
478 breq mmci_lend
479 ldi temp3,0
480
481 mmci_lend:
482 sts mmcCardType,temp3
483 rcall mmcDeselect
484
485 ; Initialization succeded?
486
487 lds temp,mmcStat
488 tst temp3
489 breq mmci_lex
490 cbr temp,MMCST_NOINIT ;Yes, clear 'NO INIT' status
491 sts mmcStat,temp
492 mmci_lex:
493
494 .if MMC_DEBUG
495 printnewline
496 printstring " CT: "
497 push temp
498 lds temp,mmcCardType
499 rcall printhex
500 pop temp
501 printstring " InitRes: "
502 rcall printhex
503 printstring " "
504 .endif
505
506 spi_disable
507 ret
508
509
510 ;--------------------------------------------------------------
511 ; Read sector
512 ; z: Pointer to the data buffer to store read data
513 ; yh..xl: Start sector number (LBA)
514
515 mmcReadSect:
516 .if MMC_DEBUG > 1
517 printnewline
518 printstring "mmcRdSect "
519 .endif
520 ldiw z,hostbuf ;for now
521
522 lds _tmp0,mmcStat
523 ldi temp,RES_NOTRDY
524 sbrc _tmp0,MMCST_NOINIT
525 ret
526
527 spi_clkfast
528 lds temp,mmcCardType
529 sbrs temp,log2(CT_BLOCK)
530 rcall mul_yx_512 ;Convert to byte address (*512)
531
532 ldi temp2,CMD17
533 rcall mmcCmd
534 ldi temp2,RES_ERROR
535 brne mmc_rdex
536
537 ; Receive a data packet from MMC
538
539 ldiw y,512 ;Number of bytes to tranfer
540 ldi temp,200 ;Wait for data packet in timeout of 200ms.
541 sts delay_timer1,temp
542 mmc_rcv_wl:
543 rcall spi_rcvr
544 cp temp,_255
545 brne mmc_rcv_start
546 lds _tmp0,delay_timer1
547 cp _tmp0,_0
548 brne mmc_rcv_wl
549 .if MMC_DEBUG > 1
550 printstring "TIMEOUT "
551 rjmp mmc_rcv_dbg1
552 .endif
553
554 mmc_rcv_start:
555 .if MMC_DEBUG > 1
556 cpi temp,0xFE ;If not valid data token,
557 breq mmc_rcv_dbg1
558 printstring "Token: "
559 rcall printhex
560 printstring " "
561 mmc_rcv_dbg1:
562 .endif
563 cpi temp,0xFE ;If not valid data token,
564 brne mmc_rdex
565
566 rcall spi_rcvr ;Shift in first byte.
567 out SPDR,_255 ;Start shift in next byte.
568 mmc_rcv_rl:
569 sbiw yl,1
570 breq mmc_rcv_rle
571 st z+,temp
572 spi_waitm
573 in temp,SPDR
574 out SPDR,_255
575 rjmp mmc_rcv_rl
576
577 mmc_rcv_rle:
578 st z+,temp ;Store last byte in buffer
579 rcall spi_wait ; while SPI module shifts in crc part1.
580 rcall spi_rcvr ;Read second crc.
581
582 ldi temp2,RES_OK ;Return success
583 mmc_rdex:
584 rcall mmcDeselect
585 spi_disable
586 mov temp,temp2
587 .if MMC_DEBUG > 1
588 printstring "RdSectRes: "
589 rcall printhex
590 printstring " "
591 .endif
592 ret
593
594
595 ;--------------------------------------------------------------
596 ; Read word
597 ; TODO: Read Word to ZL,ZH at given ZL/ZH Offset
598 ; Need for reading of single FAT16 Entrys without killing the
599 ; Entrys in hostbuffer...
600 ;
601 ; in zh,zl: Pointer to Word within the Sector to read
602 ; in yh..xl: Start sector number (LBA)
603 ; out zh,zl : word thats been read
604
605 mmcReadWord:
606 .if MMC_DEBUG > 1
607 printnewline
608 printstring "mmcRdWord "
609 .endif
610 lds _tmp0,mmcStat
611 ldi temp,RES_NOTRDY
612 sbrc _tmp0,MMCST_NOINIT
613 ret
614
615 spi_clkfast
616 lds temp,mmcCardType
617 sbrs temp,log2(CT_BLOCK)
618 rcall mul_yx_512 ;Convert to byte address (*512)
619
620 ldi temp2,CMD17
621 rcall mmcCmd
622 ldi temp2,RES_ERROR
623 brne mmc_rdexw
624
625 ; Receive a data packet from MMC
626
627 ldiw y,512 ;Number of bytes to tranfer
628 ldi temp,200 ;Wait for data packet in timeout of 200ms.
629 sts delay_timer1,temp
630 mmc_rcvw_wl:
631 rcall spi_rcvr
632 cp temp,_255
633 brne mmc_rcvw_start
634 lds temp2,delay_timer1
635 cpi temp2,0
636 brne mmc_rcvw_wl
637 mmc_rcvw_start:
638 cpi temp,0xFE ;If not valid data token,
639 ldi temp2,RES_ERROR
640 brne mmc_rdexw
641
642 rcall spi_rcvr ;Shift in first byte.
643 out SPDR,_255 ;Start shift in next byte.
644 mmc_rcvw_rl:
645 sbiw yl,1
646 breq mmc_rcvw_rle
647 cp zl,_0
648 cpc zh,_0
649 breq mmc_rcvw_sto
650
651 sbiw zl,1
652 spi_waitm
653 in temp,SPDR
654 out SPDR,_255
655 rjmp mmc_rcvw_rl
656
657 mmc_rcvw_sto:
658 mov zl,temp
659 spi_waitm
660 in temp,SPDR
661 out SPDR,_255
662 mov zh,temp
663
664 mmc_rcvw_rl2:
665 sbiw yl,1
666 breq mmc_rcvw_rle
667 spi_waitm
668 in temp,SPDR
669 out SPDR,_255
670 rjmp mmc_rcvw_rl2
671 mmc_rcvw_rle:
672 rcall spi_wait ; while SPI module shifts in crc part1.
673 rcall spi_rcvr ;Read second crc.
674
675 ldi temp2,RES_OK ;Return success
676 mmc_rdexw:
677 rcall mmcDeselect
678 spi_disable
679 mov temp,temp2
680 .if MMC_DEBUG > 1
681 printstring "RdWordRes: "
682 rcall printhex
683 printstring " "
684 .endif
685 ret
686
687 ;--------------------------------------------------------------
688 ; Write sector
689 ; z: Pointer to the data to be written
690 ; yh..xl: Sector number (LBA)
691
692 mmcWriteSect:
693 .if MMC_DEBUG > 1
694 printnewline
695 printstring "mmcWrSect "
696 .endif
697 ldiw z,hostbuf ;for now
698
699 lds _tmp0,mmcStat
700 ldi temp,RES_NOTRDY
701 sbrc _tmp0,MMCST_NOINIT
702 ret
703
704 spi_clkfast
705 lds temp,mmcCardType
706 sbrs temp,log2(CT_BLOCK)
707 rcall mul_yx_512 ;Convert to byte address (*512)
708
709 ldi temp2,CMD24
710 rcall mmcCmd
711 brne mmc_wrexer
712
713 ; Send a data packet to MMC
714
715 .if MMC_DEBUG > 2
716 ; printnewline
717 printstring "mmcXMIT "
718 .endif
719 rcall mmcWaitReady
720 breq mmc_wrexer
721
722 ldi temp,0xFE ;Data token
723 out SPDR,temp
724 ldiw y,512
725 mmc_x_loop:
726 ld temp,z+
727 spi_waitm
728 out SPDR,temp
729 sbiw yl,1
730 brne mmc_x_loop
731
732 rcall spi_wait
733 ldi temp,0xFF ;dummy crc
734 rcall spi_xmit
735 rcall spi_xmit
736 rcall spi_rcvr
737 .if MMC_DEBUG > 2
738 printstring "XMITRes: "
739 rcall printhex
740 printstring " "
741 .endif
742 andi temp,0x1F ;If not accepted, return with error
743 cpi temp,0x05
744 ldi temp2,RES_OK ;Return success
745 breq mmc_wrex
746
747 mmc_wrexer:
748 ldi temp,RES_ERROR
749 mmc_wrex:
750 rcall mmcDeselect
751 spi_disable
752 mov temp,temp2
753 .if MMC_DEBUG > 1
754 printstring "WrSectRes: "
755 rcall printhex
756 printstring " "
757 .endif
758 ret
759
760 ;--------------------------------------------------------------
761 ; vim:set ts=8 noet nowrap
762