]> cloudbase.mooo.com Git - avrcpm.git/blame - avr/mmc.asm
* New config option: CPMDSK_SUPPORT
[avrcpm.git] / avr / mmc.asm
CommitLineData
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
116mmcStat:
117 .byte 1
118mmcCardType:
119 .byte 1
9c15f366
L
120
121
122 .cseg
123
124;------------------------------------------------
125; Multiply 32 bit value in yh,yl,xh,xl by 512
126
127mul_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;------------------------------------------------
138spi_rcvr:
139 out SPDR,_255
140spi_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;------------------------------------------------
152spi_xmit:
153.if MMC_DEBUG > 2
154 printstring ">"
155 rcall printhex
156 printstring " "
157.endif
158 out SPDR,temp
159 ;fall thru
160spi_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
169mmcWaitReady:
170 push temp2
171 ldi temp2,2 ;Wait for ready in timeout of 500ms.
172 rcall spi_rcvr
173mmc_wrl:
174 sts delay_timer2,_255
175mmc_wrl1:
176 rcall spi_rcvr
177 cp temp,_255
178 brne mmc_wrl2
179 ldi temp,1
180 rjmp mmc_wrbreak
181
182mmc_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
189mmc_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
199mmcDeselect:
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
209mmcSelect:
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
226mmcCmd:
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
255mmc_cmddo:
256.if MMC_DEBUG
257 sbrc temp2,7
258 rjmp dmmccmd_nonl
259 printnewline
260
261dmmccmd_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
284mmc_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
305mmc_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
320mmc_cmdres:
825ecc9d
L
321 push temp2
322 ldi temp2,10
9c15f366
L
323mmc_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
332mmc_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
349mmcCmd_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
360mmc_cocr1:
361 rcall spi_rcvr
362 st z+,temp
363 dec temp2
364 brne mmc_cocr1
365 ;z-flag =1
366mmc_cocr_e:
367 ret
368
9c15f366
L
369;------------------------------------------------
370; Check if 1 sec timeout
371; return Z-Flag set, if timeout
372
373mmc_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
381mmc_ttex:
382 ret
383
384
385;------------------------------------------------
386; "Public" functions
387;------------------------------------------------
388
389;------------------------------------------------
390; Initialize MMC/SD card
391
392mmcInit:
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
403mmci_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
416mmci_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
441mmci_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
449mmci_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
461mmci_sdv2end:
462 rjmp mmci_lend
463
464; SDv1 or MMCv3
465
466mmci_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
476mmci_mmcv3:
477 sbr temp3,CT_MMC ;MMCv3
478 ldi temp2,CMD1
479
480; Wait for leaving idle state
481mmci_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
489mmci_v1_2:
490 ldi temp2,CMD16
491 ldiw x,512
492 rcall mmcCmd
493 breq mmci_lend
494 ldi temp3,0
495
496mmci_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
507mmci_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
531mmcReadSect:
34527fc2 532
9c15f366
L
533.if MMC_DEBUG > 1
534 printnewline
535 printstring "mmcRdSect "
536.endif
96a054ef 537 ldi temp,(1<<MMC_RDOP)
34527fc2
L
538 rjmp mmc_rw_common
539
540mmcReadWord:
541
542.if MMC_DEBUG > 1
543 printnewline
544 printstring "mmcRdWord "
545.endif
96a054ef 546 ldi temp,(1<<MMC_RDOP) | (1<<MMC_RDWORD)
34527fc2
L
547 rjmp mmc_rw_common
548
549mmcWriteSect:
550
551.if MMC_DEBUG > 1
552 printnewline
553 printstring "mmcWrSect "
554.endif
96a054ef 555 ldi temp,0
9c15f366 556
34527fc2 557mmc_rw_common:
96a054ef
L
558 push temp3
559 mov temp3,temp
34527fc2
L
560 lds temp,mmcStat
561 ldi temp2,RES_NOTRDY
562 sbrc temp,log2(MMCST_NOINIT)
563 rjmp mmc_rwexit_2
9c15f366
L
564
565 spi_clkfast
566 lds temp,mmcCardType
567 sbrs temp,log2(CT_BLOCK)
568 rcall mul_yx_512 ;Convert to byte address (*512)
9c15f366 569
34527fc2
L
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
578mmc_rw_1:
579 ldiw y,hostbuf ;aarrrgh
580 sbrs temp3,MMC_RDWORD
581 movw z,y
582 ldiw y,512
583 sbrs temp3,MMC_RDOP
584 rjmp mmc_wroper
585
586;-------------------------------------------------------------------------------
9c15f366
L
587; Receive a data packet from MMC
588
9c15f366
L
589 ldi temp,200 ;Wait for data packet in timeout of 200ms.
590 sts delay_timer1,temp
591mmc_rcv_wl:
592 rcall spi_rcvr
593 cp temp,_255
594 brne mmc_rcv_start
595 lds _tmp0,delay_timer1
596 cp _tmp0,_0
597 brne mmc_rcv_wl
598.if MMC_DEBUG > 1
599 printstring "TIMEOUT "
600 rjmp mmc_rcv_dbg1
601.endif
602
603mmc_rcv_start:
604.if MMC_DEBUG > 1
605 cpi temp,0xFE ;If not valid data token,
606 breq mmc_rcv_dbg1
607 printstring "Token: "
34527fc2 608 lcall printhex
9c15f366
L
609 printstring " "
610mmc_rcv_dbg1:
611.endif
612 cpi temp,0xFE ;If not valid data token,
34527fc2
L
613 breq mmc_rw_2
614 rjmp mmc_rwexit_error
615mmc_rw_2:
616
9c15f366 617 rcall spi_rcvr ;Shift in first byte.
4160d270
L
618.if MMC_DEBUG > 3
619 printnewline
34527fc2 620 lcall printhex
4160d270
L
621 printstring " "
622.endif
9c15f366 623 out SPDR,_255 ;Start shift in next byte.
9c15f366 624
34527fc2
L
625 sbrs temp3,MMC_RDWORD
626 rjmp mmc_rcv_readloop
92202636 627
34527fc2 628; discard x-1 bytes
64219415 629
64219415
FZ
630mmc_rcvw_rl:
631 sbiw yl,1
34527fc2 632 breq mmc_rcv_rlend
08716d4f
L
633 cp zl,_0
634 cpc zh,_0
92202636
L
635 breq mmc_rcvw_sto
636
637 sbiw zl,1
64219415 638 spi_waitm
08716d4f
L
639 in temp,SPDR
640 out SPDR,_255
64219415
FZ
641 rjmp mmc_rcvw_rl
642
34527fc2
L
643; read next two bytes
644
92202636
L
645mmc_rcvw_sto:
646 mov zl,temp
678fc0b0 647 spi_waitm
08716d4f
L
648 in temp,SPDR
649 out SPDR,_255
92202636
L
650 mov zh,temp
651
34527fc2
L
652; discard the rest
653
678fc0b0
FZ
654mmc_rcvw_rl2:
655 sbiw yl,1
34527fc2 656 breq mmc_rcv_rlend
678fc0b0 657 spi_waitm
08716d4f
L
658 in temp,SPDR
659 out SPDR,_255
92202636 660 rjmp mmc_rcvw_rl2
9c15f366 661
34527fc2 662; read sector, store in buffer
9c15f366 663
34527fc2
L
664mmc_rcv_readloop:
665 sbiw yl,1
666 breq mmc_rcv_rle
667 st z+,temp
668 spi_waitm
669 in temp,SPDR
670.if MMC_DEBUG > 3
671 lcall printhex
672 printstring " "
673.endif
674 out SPDR,_255
675 rjmp mmc_rcv_readloop
676
677mmc_rcv_rle:
678 st z+,temp ;Store last byte in buffer
679mmc_rcv_rlend:
680.if MMC_DEBUG > 3
9c15f366 681 printnewline
9c15f366 682.endif
34527fc2
L
683 rcall spi_wait ;while SPI module shifts in crc part1.
684 rcall spi_rcvr ;Read second crc.
9c15f366 685
34527fc2
L
686 ldi temp2,RES_OK ;Return success
687 rjmp mmc_rwexit
9c15f366 688
9c15f366 689
34527fc2 690;-------------------------------------------------------------------------------
9c15f366
L
691; Send a data packet to MMC
692
34527fc2
L
693mmc_wroper:
694
9c15f366
L
695.if MMC_DEBUG > 2
696; printnewline
697 printstring "mmcXMIT "
698.endif
699 rcall mmcWaitReady
34527fc2 700 breq mmc_rwexit_error
9c15f366
L
701
702 ldi temp,0xFE ;Data token
703 out SPDR,temp
9c15f366
L
704mmc_x_loop:
705 ld temp,z+
706 spi_waitm
707 out SPDR,temp
708 sbiw yl,1
709 brne mmc_x_loop
710
711 rcall spi_wait
712 ldi temp,0xFF ;dummy crc
713 rcall spi_xmit
714 rcall spi_xmit
715 rcall spi_rcvr
716.if MMC_DEBUG > 2
717 printstring "XMITRes: "
34527fc2 718 lcall printhex
9c15f366
L
719 printstring " "
720.endif
721 andi temp,0x1F ;If not accepted, return with error
722 cpi temp,0x05
723 ldi temp2,RES_OK ;Return success
34527fc2 724 breq mmc_rwexit
9c15f366 725
34527fc2
L
726mmc_rwexit_error:
727 ldi temp2,RES_ERROR
728mmc_rwexit:
9c15f366
L
729 rcall mmcDeselect
730 spi_disable
34527fc2 731mmc_rwexit_2:
9c15f366 732 mov temp,temp2
34527fc2 733
9c15f366 734.if MMC_DEBUG > 1
34527fc2
L
735 sbrc temp3,MMC_RDOP
736 rjmp mmc_dbg_rder
737
738 printstring "WrSectRes: "
739 rjmp mmc_dbg_rwerex
740
741mmc_dbg_rder:
742 sbrc temp3,MMC_RDWORD
743 rjmp mmc_dbg_rdwder
744 printstring "RdSectRes: "
745 rjmp mmc_dbg_rwerex
746
747mmc_dbg_rdwder:
748 printstring "RdWordRes: "
749mmc_dbg_rwerex:
750 lcall printhex
9c15f366
L
751 printstring " "
752.endif
96a054ef 753 pop temp3
9c15f366
L
754 ret
755
756;--------------------------------------------------------------
757; vim:set ts=8 noet nowrap
758