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