]>
Commit | Line | Data |
---|---|---|
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 | |
761 |