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