]> cloudbase.mooo.com Git - avrcpm.git/blame - avr/mmc.asm
* More fixes, spelling corrections, minor enhancements.
[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
34527fc2
L
537 ldi temp3,(1<<MMC_RDOP)
538 rjmp mmc_rw_common
539
540mmcReadWord:
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
549mmcWriteSect:
550
551.if MMC_DEBUG > 1
552 printnewline
553 printstring "mmcWrSect "
554.endif
555 ldi temp3,0
9c15f366 556
34527fc2
L
557mmc_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
576mmc_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
589mmc_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
601mmc_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 " "
608mmc_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
613mmc_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
628mmc_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
643mmc_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
652mmc_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
662mmc_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
675mmc_rcv_rle:
676 st z+,temp ;Store last byte in buffer
677mmc_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
691mmc_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
702mmc_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
724mmc_rwexit_error:
725 ldi temp2,RES_ERROR
726mmc_rwexit:
9c15f366
L
727 rcall mmcDeselect
728 spi_disable
34527fc2 729mmc_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
739mmc_dbg_rder:
740 sbrc temp3,MMC_RDWORD
741 rjmp mmc_dbg_rdwder
742 printstring "RdSectRes: "
743 rjmp mmc_dbg_rwerex
744
745mmc_dbg_rdwder:
746 printstring "RdWordRes: "
747mmc_dbg_rwerex:
748 lcall printhex
9c15f366
L
749 printstring " "
750.endif
751 ret
752
753;--------------------------------------------------------------
754; vim:set ts=8 noet nowrap
755