]> cloudbase.mooo.com Git - avrcpm.git/blob - avr/mmc.asm
Remove unsupported experimental ADC support
[avrcpm.git] / avr / 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 (masks) (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 (masks) (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 #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
67 ;------------------------------------------------
68 ;
69 .macro spi_clkslow
70 .if MMC_DEBUG > 1
71 printstring "SPI_CLK_SLOW "
72 .endif
73 ldi temp,SPI_MODE|(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0) ;clk/128
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
84 ldi temp,SPI_MODE|(1<<SPE)|(1<<MSTR) ;clk/4
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
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
145 printstring "<"
146 rcall printhex
147 printstring " "
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
221 ; return:
222 ; temp: 0 = ok, no error
223 ; z-flag 1 = ok, no error
224 ;
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:
321 push temp2
322 ldi temp2,10
323 mmc_cmdrl:
324 rcall spi_rcvr
325 sbrs temp,7
326 rjmp mmc_cmdexit
327 dec temp2
328 brne mmc_cmdrl
329
330 ; Return with response value
331
332 mmc_cmdexit:
333 pop temp2
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
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
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
377 dec zh
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:
417 ldi zh,10 ;Initialization timeout of 1000 ms.
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
424 ldi zl,1
425 rcall mmcCmd_ocr
426 brne mmci_sdv1 ;SDv2?
427
428 cpi yl,0x01 ;ocr[2]
429 brne mmci_sdv1
430 cpi yh,0xAA ;ocr[3]
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
452 ldi zl,0
453 rcall mmcCmd_ocr
454
455 brne mmci_sdv2end
456
457 sbr temp3,CT_SD2
458 sbrc xl,6
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
514 lcall printhex
515 pop temp
516 printstring " InitRes: "
517 lcall printhex
518 printstring " "
519 .endif
520
521 spi_disable
522 ret
523
524 ;--------------------------------------------------------------
525
526 .equ MMC_RDOP = 0 ;Read Operation
527 .equ MMC_RDWORD = 1 ;Read Word (FAT entry)
528
529 ;--------------------------------------------------------------
530
531 mmcReadSect:
532
533 .if MMC_DEBUG > 1
534 printnewline
535 printstring "mmcRdSect "
536 .endif
537 ldi temp,(1<<MMC_RDOP)
538 rjmp mmc_rw_common
539
540 mmcReadWord:
541
542 .if (MMC_DEBUG > 1) || (MMC_DEBUG_RDW > 0)
543 printnewline
544 printstring "mmcRdWord "
545 .endif
546 ldi temp,(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 temp,0
556
557 mmc_rw_common:
558 push temp3
559 mov temp3,temp
560 lds temp,mmcStat
561 ldi temp2,RES_NOTRDY
562 sbrc temp,log2(MMCST_NOINIT)
563 rjmp mmc_rwexit_2
564
565 spi_clkfast
566 lds temp,mmcCardType
567 sbrs temp,log2(CT_BLOCK)
568 rcall mul_yx_512 ;Convert to byte address (*512)
569
570 sbrc temp3,MMC_RDOP
571 ldi temp2,CMD17
572 sbrs temp3,MMC_RDOP
573 ldi temp2,CMD24
574 rcall mmcCmd
575 breq mmc_rw_1
576 rjmp mmc_rwexit_error
577
578 mmc_rw_1:
579 ldiw y,512
580 sbrs temp3,MMC_RDOP
581 rjmp mmc_wroper
582
583 ;-------------------------------------------------------------------------------
584 ; Receive a data packet from MMC
585
586 ldi temp,200 ;Wait for data packet in timeout of 200ms.
587 sts delay_timer1,temp
588 mmc_rcv_wl:
589 rcall spi_rcvr
590 cp temp,_255
591 brne mmc_rcv_start
592 lds _tmp0,delay_timer1
593 cp _tmp0,_0
594 brne mmc_rcv_wl
595 .if MMC_DEBUG > 1
596 printstring "TIMEOUT "
597 rjmp mmc_rcv_dbg1
598 .endif
599
600 mmc_rcv_start:
601 .if MMC_DEBUG > 1
602 cpi temp,0xFE ;If not valid data token,
603 breq mmc_rcv_dbg1
604 printstring "Token: "
605 lcall printhex
606 printstring " "
607 mmc_rcv_dbg1:
608 .endif
609 cpi temp,0xFE ;If not valid data token,
610 breq mmc_rw_2
611 rjmp mmc_rwexit_error
612 mmc_rw_2:
613
614 rcall spi_rcvr ;Shift in first byte.
615 .if MMC_DEBUG > 3
616 printnewline
617 lcall printhex
618 printstring " "
619 .endif
620 out SPDR,_255 ;Start shift in next byte.
621
622 sbrs temp3,MMC_RDWORD
623 rjmp mmc_rcv_readloop
624
625 ; discard x-1 bytes
626
627 mmc_rcvw_rl:
628 sbiw yl,1
629 breq mmc_rcv_rlend
630 cp zl,_0
631 cpc zh,_0
632 breq mmc_rcvw_sto
633
634 sbiw zl,1
635 spi_waitm
636 in temp,SPDR
637 out SPDR,_255
638 rjmp mmc_rcvw_rl
639
640 ; read next two bytes
641
642 mmc_rcvw_sto:
643 mov zl,temp
644 spi_waitm
645 in temp,SPDR
646 out SPDR,_255
647 mov zh,temp
648
649 .if MMC_DEBUG_RDW > 0
650 movw temp,z
651 lcall printhexw
652 printstring " "
653 .endif
654
655 ; discard the rest
656
657 mmc_rcvw_rl2:
658 sbiw yl,1
659 breq mmc_rcv_rlend
660 spi_waitm
661 in temp,SPDR
662 out SPDR,_255
663 rjmp mmc_rcvw_rl2
664
665 ; read sector, store in buffer
666
667 mmc_rcv_readloop:
668 sbiw yl,1
669 breq mmc_rcv_rle
670 st z+,temp
671 spi_waitm
672 in temp,SPDR
673 .if MMC_DEBUG > 3
674 lcall printhex
675 printstring " "
676 .endif
677 out SPDR,_255
678 rjmp mmc_rcv_readloop
679
680 mmc_rcv_rle:
681 st z+,temp ;Store last byte in buffer
682 mmc_rcv_rlend:
683 .if MMC_DEBUG > 3
684 printnewline
685 .endif
686 rcall spi_wait ;while SPI module shifts in crc part1.
687 rcall spi_rcvr ;Read second crc.
688
689 ldi temp2,RES_OK ;Return success
690 rjmp mmc_rwexit
691
692
693 ;-------------------------------------------------------------------------------
694 ; Send a data packet to MMC
695
696 mmc_wroper:
697
698 .if MMC_DEBUG > 2
699 ; printnewline
700 printstring "mmcXMIT "
701 .endif
702 rcall mmcWaitReady
703 breq mmc_rwexit_error
704
705 ldi temp,0xFE ;Data token
706 out SPDR,temp
707 mmc_x_loop:
708 ld temp,z+
709 spi_waitm
710 out SPDR,temp
711 sbiw yl,1
712 brne mmc_x_loop
713
714 rcall spi_wait
715 ldi temp,0xFF ;dummy crc
716 rcall spi_xmit
717 rcall spi_xmit
718 rcall spi_rcvr
719 .if MMC_DEBUG > 2
720 printstring "XMITRes: "
721 lcall printhex
722 printstring " "
723 .endif
724 andi temp,0x1F ;If not accepted, return with error
725 cpi temp,0x05
726 ldi temp2,RES_OK ;Return success
727 breq mmc_rwexit
728
729 mmc_rwexit_error:
730 ldi temp2,RES_ERROR
731 mmc_rwexit:
732 rcall mmcDeselect
733 spi_disable
734 mmc_rwexit_2:
735 mov temp,temp2
736
737 .if MMC_DEBUG > 1
738 sbrc temp3,MMC_RDOP
739 rjmp mmc_dbg_rder
740
741 printstring "WrSectRes: "
742 rjmp mmc_dbg_rwerex
743
744 mmc_dbg_rder:
745 sbrc temp3,MMC_RDWORD
746 rjmp mmc_dbg_rdwder
747 printstring "RdSectRes: "
748 rjmp mmc_dbg_rwerex
749
750 mmc_dbg_rdwder:
751 printstring "RdWordRes: "
752 mmc_dbg_rwerex:
753 lcall printhex
754 printstring " "
755 .endif
756 pop temp3
757 ret
758
759 ;--------------------------------------------------------------
760 ; vim:set ts=8 noet nowrap