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