]>
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: | |
825ecc9d L |
319 | push temp2 |
320 | ldi temp2,10 | |
9c15f366 L |
321 | mmc_cmdrl: |
322 | rcall spi_rcvr | |
323 | sbrs temp,7 | |
324 | rjmp mmc_cmdexit | |
825ecc9d | 325 | dec temp2 |
9c15f366 L |
326 | brne mmc_cmdrl |
327 | ||
328 | ; Return with response value | |
329 | ||
330 | mmc_cmdexit: | |
825ecc9d | 331 | pop temp2 |
9c15f366 L |
332 | .if MMC_DEBUG |
333 | printstring " CMDRes: " | |
334 | rcall printhex | |
335 | printstring " " | |
336 | rcall uart_wait_empty | |
337 | .endif | |
338 | tst temp ;set flags | |
339 | ret | |
340 | ||
08716d4f L |
341 | ;------------------------------------------------ |
342 | ; Send command and receive ocr response | |
343 | ; temp2: Command, zl: expected cmd response | |
344 | ; yh..xl: Argument | |
345 | ; return: yh..xl: ocr, z flag == 1, if return from mmcCmd was ok. | |
346 | ||
347 | mmcCmd_ocr: | |
348 | ||
349 | rcall mmcCmd | |
350 | ||
351 | cp temp,zl ; | |
352 | brne mmc_cocr_e | |
353 | ||
354 | ; Get trailing return value of R7 response | |
355 | ||
356 | ldi temp2,4 | |
357 | ldiw z,0x1a ;memory address of xl | |
358 | mmc_cocr1: | |
359 | rcall spi_rcvr | |
360 | st z+,temp | |
361 | dec temp2 | |
362 | brne mmc_cocr1 | |
363 | ;z-flag =1 | |
364 | mmc_cocr_e: | |
365 | ret | |
366 | ||
9c15f366 L |
367 | ;------------------------------------------------ |
368 | ; Check if 1 sec timeout | |
369 | ; return Z-Flag set, if timeout | |
370 | ||
371 | mmc_timeout_1s: | |
372 | lds temp,delay_timer1 | |
373 | tst temp | |
374 | brne mmc_ttex | |
825ecc9d | 375 | dec zh |
9c15f366 L |
376 | breq mmc_ttex |
377 | ldi temp,100 | |
378 | sts delay_timer1,temp | |
379 | mmc_ttex: | |
380 | ret | |
381 | ||
382 | ||
383 | ;------------------------------------------------ | |
384 | ; "Public" functions | |
385 | ;------------------------------------------------ | |
386 | ||
387 | ;------------------------------------------------ | |
388 | ; Initialize MMC/SD card | |
389 | ||
390 | mmcInit: | |
391 | .if MMC_DEBUG | |
392 | printnewline | |
393 | printstring "mmcInit " | |
394 | .endif | |
395 | lds temp,mmcStat ;Set 'NO INIT' status | |
396 | sbr temp,MMCST_NOINIT | |
397 | sts mmcStat,temp | |
398 | ||
399 | spi_clkslow | |
400 | ldi temp2,10 | |
401 | mmci_lp: | |
402 | rcall spi_rcvr | |
403 | dec temp2 ;80 dummy clocks | |
404 | brne mmci_lp | |
405 | ||
406 | ldi temp3,0 ;Card type | |
407 | ldi temp2,CMD0 | |
408 | ldiw y,0 | |
409 | movw x,y | |
410 | rcall mmcCmd ;Enter Idle state | |
411 | cpi temp,1 | |
412 | breq mmci_1 | |
413 | rjmp mmci_lend | |
414 | mmci_1: | |
825ecc9d | 415 | ldi zh,10 ;Initialization timeout of 1000 ms. |
9c15f366 L |
416 | ldi temp,100 |
417 | sts delay_timer1,temp | |
418 | ldi temp2,CMD8 | |
419 | ldiw y,0 | |
420 | ldi xh,0x01 | |
421 | ldi xl,0xAA | |
08716d4f L |
422 | ldi zl,1 |
423 | rcall mmcCmd_ocr | |
424 | brne mmci_sdv1 ;SDv2? | |
9c15f366 | 425 | |
08716d4f L |
426 | cpi yl,0x01 ;ocr[2] |
427 | brne mmci_sdv1 | |
428 | cpi yh,0xAA ;ocr[3] | |
9c15f366 L |
429 | brne mmci_sdv1 |
430 | ||
431 | ; The card can work at vdd range of 2.7-3.6V. | |
432 | ; Wait for leaving idle state (ACMD41 with HCS bit). | |
433 | ||
434 | ldi temp2,ACMD41 | |
435 | ldi yh,0x40 | |
436 | ldi yl,0 | |
437 | ldi xh,0 | |
438 | ldi xl,0 | |
439 | mmci_v2l2: | |
440 | rcall mmcCmd | |
441 | breq mmci_ccc | |
442 | rcall mmc_timeout_1s | |
443 | brne mmci_v2l2 | |
444 | rjmp mmci_sdv2end | |
445 | ||
446 | ; Check CCS bit in the OCR | |
447 | mmci_ccc: | |
448 | ldi temp2,CMD58 | |
449 | ldi yh,0 | |
08716d4f L |
450 | ldi zl,0 |
451 | rcall mmcCmd_ocr | |
452 | ||
9c15f366 L |
453 | brne mmci_sdv2end |
454 | ||
9c15f366 | 455 | sbr temp3,CT_SD2 |
08716d4f | 456 | sbrc xl,6 |
9c15f366 L |
457 | sbr temp3,CT_BLOCK |
458 | ||
459 | mmci_sdv2end: | |
460 | rjmp mmci_lend | |
461 | ||
462 | ; SDv1 or MMCv3 | |
463 | ||
464 | mmci_sdv1: | |
465 | ldi temp2,ACMD41 | |
466 | ldiw y,0 | |
467 | movw x,y | |
468 | rcall mmcCmd | |
469 | cpi temp,2 | |
470 | brsh mmci_mmcv3 | |
471 | sbr temp3,CT_SD1 ;SDv1 | |
472 | ldi temp2,ACMD41 | |
473 | rjmp mmci_v1_l | |
474 | mmci_mmcv3: | |
475 | sbr temp3,CT_MMC ;MMCv3 | |
476 | ldi temp2,CMD1 | |
477 | ||
478 | ; Wait for leaving idle state | |
479 | mmci_v1_l: | |
480 | rcall mmcCmd | |
481 | breq mmci_v1_2 | |
482 | rcall mmc_timeout_1s | |
483 | brne mmci_v1_l | |
484 | rjmp mmci_lend ;Timeout | |
485 | ||
486 | ; Set R/W block length to 512 | |
487 | mmci_v1_2: | |
488 | ldi temp2,CMD16 | |
489 | ldiw x,512 | |
490 | rcall mmcCmd | |
491 | breq mmci_lend | |
492 | ldi temp3,0 | |
493 | ||
494 | mmci_lend: | |
495 | sts mmcCardType,temp3 | |
496 | rcall mmcDeselect | |
497 | ||
498 | ; Initialization succeded? | |
499 | ||
500 | lds temp,mmcStat | |
501 | tst temp3 | |
502 | breq mmci_lex | |
503 | cbr temp,MMCST_NOINIT ;Yes, clear 'NO INIT' status | |
504 | sts mmcStat,temp | |
505 | mmci_lex: | |
506 | ||
507 | .if MMC_DEBUG | |
508 | printnewline | |
509 | printstring " CT: " | |
510 | push temp | |
511 | lds temp,mmcCardType | |
512 | rcall printhex | |
513 | pop temp | |
514 | printstring " InitRes: " | |
515 | rcall printhex | |
516 | printstring " " | |
517 | .endif | |
518 | ||
519 | spi_disable | |
520 | ret | |
521 | ||
522 | ||
523 | ;-------------------------------------------------------------- | |
524 | ; Read sector | |
525 | ; z: Pointer to the data buffer to store read data | |
526 | ; yh..xl: Start sector number (LBA) | |
527 | ||
528 | mmcReadSect: | |
529 | .if MMC_DEBUG > 1 | |
530 | printnewline | |
531 | printstring "mmcRdSect " | |
532 | .endif | |
533 | ldiw z,hostbuf ;for now | |
534 | ||
535 | lds _tmp0,mmcStat | |
536 | ldi temp,RES_NOTRDY | |
537 | sbrc _tmp0,MMCST_NOINIT | |
538 | ret | |
539 | ||
540 | spi_clkfast | |
541 | lds temp,mmcCardType | |
542 | sbrs temp,log2(CT_BLOCK) | |
543 | rcall mul_yx_512 ;Convert to byte address (*512) | |
544 | ||
545 | ldi temp2,CMD17 | |
546 | rcall mmcCmd | |
547 | ldi temp2,RES_ERROR | |
548 | brne mmc_rdex | |
549 | ||
550 | ; Receive a data packet from MMC | |
551 | ||
552 | ldiw y,512 ;Number of bytes to tranfer | |
553 | ldi temp,200 ;Wait for data packet in timeout of 200ms. | |
554 | sts delay_timer1,temp | |
555 | mmc_rcv_wl: | |
556 | rcall spi_rcvr | |
557 | cp temp,_255 | |
558 | brne mmc_rcv_start | |
559 | lds _tmp0,delay_timer1 | |
560 | cp _tmp0,_0 | |
561 | brne mmc_rcv_wl | |
562 | .if MMC_DEBUG > 1 | |
563 | printstring "TIMEOUT " | |
564 | rjmp mmc_rcv_dbg1 | |
565 | .endif | |
566 | ||
567 | mmc_rcv_start: | |
568 | .if MMC_DEBUG > 1 | |
569 | cpi temp,0xFE ;If not valid data token, | |
570 | breq mmc_rcv_dbg1 | |
571 | printstring "Token: " | |
572 | rcall printhex | |
573 | printstring " " | |
574 | mmc_rcv_dbg1: | |
575 | .endif | |
576 | cpi temp,0xFE ;If not valid data token, | |
577 | brne mmc_rdex | |
578 | ||
579 | rcall spi_rcvr ;Shift in first byte. | |
4160d270 L |
580 | .if MMC_DEBUG > 3 |
581 | printnewline | |
582 | rcall printhex | |
583 | printstring " " | |
584 | .endif | |
9c15f366 L |
585 | out SPDR,_255 ;Start shift in next byte. |
586 | mmc_rcv_rl: | |
587 | sbiw yl,1 | |
588 | breq mmc_rcv_rle | |
589 | st z+,temp | |
590 | spi_waitm | |
591 | in temp,SPDR | |
4160d270 L |
592 | .if MMC_DEBUG > 3 |
593 | rcall printhex | |
594 | printstring " " | |
595 | .endif | |
9c15f366 L |
596 | out SPDR,_255 |
597 | rjmp mmc_rcv_rl | |
598 | ||
599 | mmc_rcv_rle: | |
600 | st z+,temp ;Store last byte in buffer | |
4160d270 L |
601 | .if MMC_DEBUG > 3 |
602 | printnewline | |
603 | .endif | |
08716d4f | 604 | rcall spi_wait ;while SPI module shifts in crc part1. |
9c15f366 L |
605 | rcall spi_rcvr ;Read second crc. |
606 | ||
607 | ldi temp2,RES_OK ;Return success | |
608 | mmc_rdex: | |
609 | rcall mmcDeselect | |
610 | spi_disable | |
611 | mov temp,temp2 | |
612 | .if MMC_DEBUG > 1 | |
613 | printstring "RdSectRes: " | |
614 | rcall printhex | |
615 | printstring " " | |
616 | .endif | |
617 | ret | |
618 | ||
92202636 | 619 | |
64219415 | 620 | ;-------------------------------------------------------------- |
92202636 | 621 | ; Read word |
08716d4f L |
622 | ; Read Word to ZL,ZH at given ZL/ZH Offset |
623 | ; Needed for reading a single FAT16 entry without killing the | |
624 | ; entries in hostbuffer... | |
64219415 | 625 | ; |
08716d4f | 626 | ; in zh,zl: Pointer to word within the sector to read |
64219415 | 627 | ; in yh..xl: Start sector number (LBA) |
08716d4f | 628 | ; out zh,zl: Word thats been read |
64219415 FZ |
629 | |
630 | mmcReadWord: | |
631 | .if MMC_DEBUG > 1 | |
632 | printnewline | |
08716d4f | 633 | printstring "mmcRdWord " |
64219415 | 634 | .endif |
08716d4f L |
635 | lds _tmp0,mmcStat |
636 | ldi temp,RES_NOTRDY | |
64219415 FZ |
637 | sbrc _tmp0,MMCST_NOINIT |
638 | ret | |
639 | ||
640 | spi_clkfast | |
08716d4f | 641 | lds temp,mmcCardType |
64219415 FZ |
642 | sbrs temp,log2(CT_BLOCK) |
643 | rcall mul_yx_512 ;Convert to byte address (*512) | |
92202636 | 644 | |
08716d4f | 645 | ldi temp2,CMD17 |
64219415 | 646 | rcall mmcCmd |
08716d4f | 647 | ldi temp2,RES_ERROR |
64219415 FZ |
648 | brne mmc_rdexw |
649 | ||
650 | ; Receive a data packet from MMC | |
651 | ||
652 | ldiw y,512 ;Number of bytes to tranfer | |
08716d4f L |
653 | ldi temp,200 ;Wait for data packet in timeout of 200ms. |
654 | sts delay_timer1,temp | |
64219415 FZ |
655 | mmc_rcvw_wl: |
656 | rcall spi_rcvr | |
08716d4f | 657 | cp temp,_255 |
64219415 | 658 | brne mmc_rcvw_start |
08716d4f L |
659 | lds temp2,delay_timer1 |
660 | cpi temp2,0 | |
64219415 FZ |
661 | brne mmc_rcvw_wl |
662 | mmc_rcvw_start: | |
08716d4f L |
663 | cpi temp,0xFE ;If not valid data token, |
664 | ldi temp2,RES_ERROR | |
64219415 FZ |
665 | brne mmc_rdexw |
666 | ||
667 | rcall spi_rcvr ;Shift in first byte. | |
08716d4f | 668 | out SPDR,_255 ;Start shift in next byte. |
64219415 FZ |
669 | mmc_rcvw_rl: |
670 | sbiw yl,1 | |
671 | breq mmc_rcvw_rle | |
08716d4f L |
672 | cp zl,_0 |
673 | cpc zh,_0 | |
92202636 L |
674 | breq mmc_rcvw_sto |
675 | ||
676 | sbiw zl,1 | |
64219415 | 677 | spi_waitm |
08716d4f L |
678 | in temp,SPDR |
679 | out SPDR,_255 | |
64219415 FZ |
680 | rjmp mmc_rcvw_rl |
681 | ||
92202636 L |
682 | mmc_rcvw_sto: |
683 | mov zl,temp | |
678fc0b0 | 684 | spi_waitm |
08716d4f L |
685 | in temp,SPDR |
686 | out SPDR,_255 | |
92202636 L |
687 | mov zh,temp |
688 | ||
678fc0b0 FZ |
689 | mmc_rcvw_rl2: |
690 | sbiw yl,1 | |
691 | breq mmc_rcvw_rle | |
692 | spi_waitm | |
08716d4f L |
693 | in temp,SPDR |
694 | out SPDR,_255 | |
92202636 | 695 | rjmp mmc_rcvw_rl2 |
64219415 | 696 | mmc_rcvw_rle: |
64219415 FZ |
697 | rcall spi_wait ; while SPI module shifts in crc part1. |
698 | rcall spi_rcvr ;Read second crc. | |
699 | ||
08716d4f | 700 | ldi temp2,RES_OK ;Return success |
64219415 FZ |
701 | mmc_rdexw: |
702 | rcall mmcDeselect | |
703 | spi_disable | |
704 | mov temp,temp2 | |
705 | .if MMC_DEBUG > 1 | |
08716d4f | 706 | printstring "RdWordRes: " |
64219415 | 707 | rcall printhex |
08716d4f | 708 | printstring " " |
64219415 | 709 | .endif |
92202636 | 710 | ret |
9c15f366 L |
711 | |
712 | ;-------------------------------------------------------------- | |
713 | ; Write sector | |
714 | ; z: Pointer to the data to be written | |
715 | ; yh..xl: Sector number (LBA) | |
716 | ||
717 | mmcWriteSect: | |
718 | .if MMC_DEBUG > 1 | |
719 | printnewline | |
720 | printstring "mmcWrSect " | |
721 | .endif | |
722 | ldiw z,hostbuf ;for now | |
723 | ||
724 | lds _tmp0,mmcStat | |
725 | ldi temp,RES_NOTRDY | |
726 | sbrc _tmp0,MMCST_NOINIT | |
727 | ret | |
728 | ||
729 | spi_clkfast | |
730 | lds temp,mmcCardType | |
731 | sbrs temp,log2(CT_BLOCK) | |
732 | rcall mul_yx_512 ;Convert to byte address (*512) | |
733 | ||
734 | ldi temp2,CMD24 | |
735 | rcall mmcCmd | |
736 | brne mmc_wrexer | |
737 | ||
738 | ; Send a data packet to MMC | |
739 | ||
740 | .if MMC_DEBUG > 2 | |
741 | ; printnewline | |
742 | printstring "mmcXMIT " | |
743 | .endif | |
744 | rcall mmcWaitReady | |
745 | breq mmc_wrexer | |
746 | ||
747 | ldi temp,0xFE ;Data token | |
748 | out SPDR,temp | |
749 | ldiw y,512 | |
750 | mmc_x_loop: | |
751 | ld temp,z+ | |
752 | spi_waitm | |
753 | out SPDR,temp | |
754 | sbiw yl,1 | |
755 | brne mmc_x_loop | |
756 | ||
757 | rcall spi_wait | |
758 | ldi temp,0xFF ;dummy crc | |
759 | rcall spi_xmit | |
760 | rcall spi_xmit | |
761 | rcall spi_rcvr | |
762 | .if MMC_DEBUG > 2 | |
763 | printstring "XMITRes: " | |
764 | rcall printhex | |
765 | printstring " " | |
766 | .endif | |
767 | andi temp,0x1F ;If not accepted, return with error | |
768 | cpi temp,0x05 | |
769 | ldi temp2,RES_OK ;Return success | |
770 | breq mmc_wrex | |
771 | ||
772 | mmc_wrexer: | |
773 | ldi temp,RES_ERROR | |
774 | mmc_wrex: | |
775 | rcall mmcDeselect | |
776 | spi_disable | |
777 | mov temp,temp2 | |
778 | .if MMC_DEBUG > 1 | |
779 | printstring "WrSectRes: " | |
780 | rcall printhex | |
781 | printstring " " | |
782 | .endif | |
783 | ret | |
784 | ||
785 | ;-------------------------------------------------------------- | |
786 | ; vim:set ts=8 noet nowrap | |
787 |