source: asp3_tinet_ecnl_rx/trunk/ntshell/fatfs/mmc_rspi.c@ 337

Last change on this file since 337 was 337, checked in by coas-nagasima, 6 years ago

ASP3版ECNLを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 21.9 KB
RevLine 
[337]1/*------------------------------------------------------------------------*/
2/* FRK-RX62N: MMCv3/SDv1/SDv2 (SPI mode) Control Module */
3/*------------------------------------------------------------------------*/
4/*
5/ Copyright (C) 2014, ChaN, all right reserved.
6/
7/ * This software is a free software and there is NO WARRANTY.
8/ * No restriction on use. You can use, modify and redistribute it for
9/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
10/ * Redistributions of source code must retain the above copyright notice.
11/
12/-------------------------------------------------------------------------*/
13
14#include <kernel.h> /* Platform dependent include file */
15#include "diskio.h" /* Common include file for ff.c and disk layer */
16#include <sil.h>
17#include <prc_rename.h>
18#include "target_kernel_impl.h"
19#include "mmc_rspi.h"
20#include "kernel_cfg.h"
21#include <t_syslog.h>
22#include <string.h>
23
24static void CS_LOW()
25{
26 sil_wrb_mem(PORTC_PODR_ADDR, sil_reb_mem(PORTC_PODR_ADDR) & ~PORT_PODR_B0_BIT); /* Set CS# low */
27}
28
29static void CS_HIGH()
30{
31 sil_wrb_mem(PORTC_PODR_ADDR, sil_reb_mem(PORTC_PODR_ADDR) | PORT_PODR_B0_BIT); /* Set CS# high */
32}
33
34static bool_t WP()
35{
36 return false;
37}
38
39static bool_t INS()
40{
41 return (sil_reb_mem(PORT1_PIDR_ADDR) & PORT_PIDR_B5_BIT) == 0;
42}
43
44static void CTRL_INIT()
45{
46 /* CS=OUT */
47 sil_wrb_mem(PORTC_PDR_ADDR, sil_reb_mem(PORTC_PDR_ADDR) | PORT_PDR_B0_BIT);
48 /* INS=IN */
49 sil_wrb_mem(PORT1_PDR_ADDR, sil_reb_mem(PORT1_PDR_ADDR) & ~PORT_PDR_B5_BIT);
50 /* SPICLK,SPIMOSI=OUT */
51 sil_wrb_mem(PORTC_PDR_ADDR, sil_reb_mem(PORTC_PDR_ADDR) | PORT_PDR_B5_BIT | PORT_PDR_B6_BIT);
52 /* CS,SPICLK,SPIMOSI=HI */
53 sil_wrb_mem(PORTC_PODR_ADDR, sil_reb_mem(PORTC_PODR_ADDR) | PORT_PODR_B0_BIT | PORT_PDR_B5_BIT | PORT_PDR_B6_BIT);
54 /* SPIMISO=IN */
55 sil_wrb_mem(PORTC_PDR_ADDR, sil_reb_mem(PORTC_PDR_ADDR) & ~PORT_PDR_B7_BIT);
56 /* SPIMISO=PULLUP */
57 sil_wrb_mem(PORTC_PCR_ADDR, sil_reb_mem(PORTC_PDR_ADDR) | PORT_PDR_B7_BIT);
58 /* CMOSを選択 */
59 sil_wrb_mem(PORTC_ODR0_ADDR, 0x00);
60 /* CMOSを選択 */
61 sil_wrb_mem(PORTC_ODR1_ADDR, 0x00);
62}
63
64#define F_PCLK 48000000UL /* PCLK frequency (configured by SCKCR.PCK) */
65#define SCLK_FAST 24000000UL /* SCLK frequency (R/W) */
66#define SCLK_SLOW 375000UL /* SCLK frequency (Init) */
67
68static void RSPI_ATTACH()
69{
70 /*
71 * モジュールストップ機能の設定(RSPI0)
72 */
73 sil_wrh_mem(SYSTEM_PRCR_ADDR, (uint16_t)0xA502); /* 書込み許可 */
74 sil_wrw_mem(SYSTEM_MSTPCRB_ADDR,
75 sil_rew_mem(SYSTEM_MSTPCRB_ADDR) & ~SYSTEM_MSTPCRB_MSTPB17_BIT);
76 sil_wrh_mem(SYSTEM_PRCR_ADDR, (uint16_t)0xA500); /* 書込み禁止 */
77
78 /* P15をGPIOとして使用 */
79 sil_wrb_mem(PORT1_PMR_ADDR,
80 sil_reb_mem(PORT1_PMR_ADDR) & ~PORT_PMR_B5_BIT);
81 /* PC0をGPIOとして使用 */
82 sil_wrb_mem(PORTC_PMR_ADDR,
83 sil_reb_mem(PORTC_PMR_ADDR) & ~PORT_PMR_B0_BIT);
84 /* PC5, PC6, PC7を周辺機能として使用 */
85 sil_wrb_mem(PORTC_PMR_ADDR,
86 sil_reb_mem(PORTC_PMR_ADDR) | PORT_PMR_B5_BIT | PORT_PMR_B6_BIT | PORT_PMR_B7_BIT);
87
88 /* 書き込みプロテクトレジスタの設定 PFSWEビットへの書き込みを許可 */
89 sil_wrb_mem(MPC_PWPR_ADDR, 0x00);
90 /* 書き込みプロテクトレジスタの設定 PxxFSレジスタへの書き込みを許可 */
91 sil_wrb_mem(MPC_PWPR_ADDR, 0x40);
92
93 /* RSPCKAを選択 */
94 sil_wrb_mem(MPC_PC5PFS_ADDR, 0x0d);
95 /* MOSIAを選択 */
96 sil_wrb_mem(MPC_PC6PFS_ADDR, 0x0d);
97 /* MISOAを選択 */
98 sil_wrb_mem(MPC_PC7PFS_ADDR, 0x0d);
99
100 /* 書き込みプロテクトレジスタの設定 書き込みを禁止 */
101 sil_wrb_mem(MPC_PWPR_ADDR, 0x80);
102}
103
104static void FCLK_FAST()
105{
106 /* RSPI機能を無効化 */
107 sil_wrb_mem(RSPI0_SPCR_ADDR,
108 sil_reb_mem(RSPI0_SPCR_ADDR) & ~RSPI_SPCR_SPE_BIT);
109 /* ビットレート設定 */
110 sil_wrb_mem(RSPI0_SPBR_ADDR, F_PCLK / 2 / SCLK_FAST - 1);
111 /* RSPI機能を有効化 */
112 sil_wrb_mem(RSPI0_SPCR_ADDR,
113 sil_reb_mem(RSPI0_SPCR_ADDR) | RSPI_SPCR_SPE_BIT);
114}
115
116#ifdef SIL_ENDIAN_LITTLE
117#define LDDW(x) rev_endian_uint32(x) /* Little endian: swap bytes */
118#else
119#define LDDW(x) x /* Big endian: no swap */
120#endif
121
122
123
124/*--------------------------------------------------------------------------
125
126 Module Private Functions
127
128---------------------------------------------------------------------------*/
129
130/* MMC/SD command */
131#define CMD0 (0) /* GO_IDLE_STATE */
132#define CMD1 (1) /* SEND_OP_COND (MMC) */
133#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
134#define CMD8 (8) /* SEND_IF_COND */
135#define CMD9 (9) /* SEND_CSD */
136#define CMD10 (10) /* SEND_CID */
137#define CMD12 (12) /* STOP_TRANSMISSION */
138#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
139#define CMD16 (16) /* SET_BLOCKLEN */
140#define CMD17 (17) /* READ_SINGLE_BLOCK */
141#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
142#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
143#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
144#define CMD24 (24) /* WRITE_BLOCK */
145#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
146#define CMD32 (32) /* ERASE_ER_BLK_START */
147#define CMD33 (33) /* ERASE_ER_BLK_END */
148#define CMD38 (38) /* ERASE */
149#define CMD55 (55) /* APP_CMD */
150#define CMD58 (58) /* READ_OCR */
151
152
153
154static volatile
155DSTATUS Stat = STA_NOINIT; /* Physical drive status */
156
157static volatile
158WORD Timer1, Timer2; /* 1000Hz decrement timer stopped at zero (driven by disk_timerproc()) */
159
160static
161BYTE CardType; /* Card type flags */
162
163static
164BYTE CSD[16], CID[16];
165
166static
167uint64_t CardCapacity;
168
169static
170uint32_t CardBlockSize;
171
172/*-----------------------------------------------------------------------*/
173/* Control SPI module */
174/*-----------------------------------------------------------------------*/
175/* Only these five functions are platform dependent. Any other functions */
176/* are portable to different system. */
177
178/*---------------------------------*/
179/* Enable SPI and MMC/SDC controls */
180/*---------------------------------*/
181static
182void power_on(void)
183{
184 /* Initialize CS/INS/WP port */
185 CTRL_INIT();
186
187 /* Attach RSPI0 module to I/O pads, disable module stop */
188 RSPI_ATTACH();
189
190 /* Initialize RSPI module */
191 sil_wrb_mem(RSPI0_SPCR_ADDR, 0); /* Stop RSPI module */
192 sil_wrb_mem(RSPI0_SPPCR_ADDR, 0); /* Fixed idle value, disable loop-back mode */
193 sil_wrb_mem(RSPI0_SPSCR_ADDR, 0); /* Disable sequence control */
194 sil_wrb_mem(RSPI0_SPDCR_ADDR, 0x20); /* SPLW=1 */
195 sil_wrh_mem(RSPI0_SPCMD0_ADDR, 0x0700); /* LSBF=0, SPB=7, BRDV=0, CPOL=0, CPHA=0 */
196 sil_wrb_mem(RSPI0_SPBR_ADDR, F_PCLK / 2 / SCLK_SLOW - 1); /* Bit rate */
197 sil_wrb_mem(RSPI0_SPCR_ADDR, 0xC9); /* Start RSPI in master mode */
198
199 ena_int(INTNO_MMC_RSPI_SPRI);
200 ena_int(INTNO_MMC_RSPI_SPTI);
201 ena_int(INTNO_MMC_RSPI_SPII);
202
203 sta_cyc(MMC_RSPI_CYC);
204}
205
206
207/*---------------------*/
208/* Disable SPI */
209/*---------------------*/
210static
211void power_off(void) /* Disable MMC/SDC interface */
212{
213 stp_cyc(MMC_RSPI_CYC);
214
215 dis_int(INTNO_MMC_RSPI_SPRI);
216 dis_int(INTNO_MMC_RSPI_SPTI);
217 dis_int(INTNO_MMC_RSPI_SPII);
218
219 sil_wrb_mem(RSPI0_SPCR_ADDR, 0); /* Stop RSPI module */
220}
221
222
223/*---------------------*/
224/* Send/Receive a byte */
225/*---------------------*/
226static
227BYTE xchg_spi(
228 BYTE dat /* Data to send */
229 )
230{
231 sil_wrb_mem(RSPI0_SPSR_ADDR, 0xA0);
232 sil_wrw_mem(RSPI0_SPDR_ADDR, dat); /* Start transmission (lower 8bits) */
233 /*while ((sil_reb_mem(RSPI0_SPSR_ADDR) & RSPI_SPSR_SPRF_BIT) == 0); /* Wait for end of transfer */
234 wai_sem(MMC_RSPI_SEMAPHORE);
235 return sil_rew_mem(RSPI0_SPDR_ADDR); /* Returen received byte (lower 8bits) */
236}
237
238
239/*---------------------*/
240/* Send multiple bytes */
241/*---------------------*/
242static
243void xmit_spi_multi(
244 const BYTE *buff, /* Pointer to the data */
245 UINT btx /* Number of bytes to send (multiple of 4) */
246 )
247{
248 const DWORD *lp = (const DWORD*)buff;
249
250 sil_wrh_mem(RSPI0_SPCMD0_ADDR,
251 (sil_reh_mem(RSPI0_SPCMD0_ADDR) & ~RSPI_SPCMD_SPB_MASK) | (3 << RSPI_SPCMD_SPB_OFFSET)); /* Set 32-bit mode */
252
253 do {
254 sil_wrb_mem(RSPI0_SPSR_ADDR, 0xA0);
255 sil_wrw_mem(RSPI0_SPDR_ADDR, LDDW(*lp++)); /* Send four data bytes */
256 /*while ((sil_reb_mem(RSPI0_SPSR_ADDR) & RSPI_SPSR_SPRF_BIT) == 0); /* Wait for end of transfer */
257 wai_sem(MMC_RSPI_SEMAPHORE);
258 sil_rew_mem(RSPI0_SPDR_ADDR); /* Discard four received bytes */
259 } while (btx -= 4); /* Repeat until all data sent */
260
261 sil_wrh_mem(RSPI0_SPCMD0_ADDR,
262 (sil_reh_mem(RSPI0_SPCMD0_ADDR) & ~RSPI_SPCMD_SPB_MASK) | (7 << RSPI_SPCMD_SPB_OFFSET)); /* Set 8-bit mode */
263}
264
265
266/*------------------------*/
267/* Receive multiple bytes */
268/*------------------------*/
269static
270void rcvr_spi_multi(
271 BYTE *buff, /* Pointer to data buffer */
272 UINT btr /* Number of bytes to receive (multiple of 4) */
273 )
274{
275 DWORD *lp = (DWORD*)buff;
276
277 sil_wrh_mem(RSPI0_SPCMD0_ADDR,
278 (sil_reh_mem(RSPI0_SPCMD0_ADDR) & ~RSPI_SPCMD_SPB_MASK) | (3 << RSPI_SPCMD_SPB_OFFSET)); /* Set 32-bit mode */
279
280 do {
281 sil_wrb_mem(RSPI0_SPSR_ADDR, 0xA0);
282 sil_wrw_mem(RSPI0_SPDR_ADDR, 0xFFFFFFFF); /* Send four 0xFFs */
283 /*while ((sil_reb_mem(RSPI0_SPSR_ADDR) & RSPI_SPSR_SPRF_BIT) == 0); /* Wait for end of transfer */
284 wai_sem(MMC_RSPI_SEMAPHORE);
285 *lp++ = LDDW(sil_rew_mem(RSPI0_SPDR_ADDR)); /* Store four received bytes */
286 } while (btr -= 4); /* Repeat until all data received */
287
288 sil_wrh_mem(RSPI0_SPCMD0_ADDR,
289 (sil_reh_mem(RSPI0_SPCMD0_ADDR) & ~RSPI_SPCMD_SPB_MASK) | (7 << RSPI_SPCMD_SPB_OFFSET)); /* Set 8-bit mode */
290}
291
292
293
294
295/*-----------------------------------------------------------------------*/
296/* Wait for card ready */
297/*-----------------------------------------------------------------------*/
298
299static
300int wait_ready( /* 1:Ready, 0:Timeout */
301 UINT wt /* Timeout [ms] */
302 )
303{
304 Timer2 = (WORD)wt;
305
306 do {
307 if (xchg_spi(0xFF) == 0xFF) return 1; /* Card goes ready */
308 /* This loop takes a time. Insert rot_rdq() here for multitask envilonment. */
309 } while (Timer2); /* Wait until card goes ready or timeout */
310
311 return 0; /* Timeout occured */
312}
313
314
315
316/*-----------------------------------------------------------------------*/
317/* Deselect card and release SPI */
318/*-----------------------------------------------------------------------*/
319
320static
321void deselect(void)
322{
323 CS_HIGH(); /* Set CS# high */
324 xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */
325}
326
327
328
329/*-----------------------------------------------------------------------*/
330/* Select card and wait for ready */
331/*-----------------------------------------------------------------------*/
332
333static
334int select(void) /* 1:OK, 0:Timeout */
335{
336 CS_LOW(); /* Set CS# low */
337 xchg_spi(0xFF); /* Dummy clock (force DO enabled) */
338
339 if (wait_ready(500)) return 1; /* Wait for card ready */
340
341 deselect();
342 return 0; /* Failed to select the card due to timeout */
343}
344
345
346
347/*-----------------------------------------------------------------------*/
348/* Receive a data packet from the MMC */
349/*-----------------------------------------------------------------------*/
350
351static
352int rcvr_datablock( /* 1:OK, 0:Error */
353 BYTE *buff, /* Data buffer */
354 UINT btr /* Data block length (byte) */
355 )
356{
357 BYTE token;
358
359
360 Timer1 = 200;
361 do { /* Wait for DataStart token in timeout of 200ms */
362 token = xchg_spi(0xFF);
363 /* This loop will take a time. Insert rot_rdq() here for multitask envilonment. */
364 } while ((token == 0xFF) && Timer1);
365 if (token != 0xFE) return 0; /* Function fails if invalid DataStart token or timeout */
366
367 rcvr_spi_multi(buff, btr); /* Store trailing data to the buffer */
368 xchg_spi(0xFF); xchg_spi(0xFF); /* Discard CRC */
369
370 return 1; /* Function succeeded */
371}
372
373
374
375/*-----------------------------------------------------------------------*/
376/* Send a data packet to the MMC */
377/*-----------------------------------------------------------------------*/
378
379#if _USE_WRITE
380static
381int xmit_datablock( /* 1:OK, 0:Failed */
382 const BYTE *buff, /* Ponter to 512 byte data to be sent */
383 BYTE token /* Token */
384 )
385{
386 BYTE resp;
387
388
389 if (!wait_ready(500)) return 0; /* Wait for card ready */
390
391 xchg_spi(token); /* Send token */
392 if (token != 0xFD) { /* Send data if token is other than StopTran */
393 xmit_spi_multi(buff, 512); /* Data */
394 xchg_spi(0xFF); xchg_spi(0xFF); /* Dummy CRC */
395
396 resp = xchg_spi(0xFF); /* Receive data resp */
397 if ((resp & 0x1F) != 0x05) /* Function fails if the data packet was not accepted */
398 return 0;
399 }
400 return 1;
401}
402#endif /* _USE_WRITE */
403
404
405
406/*-----------------------------------------------------------------------*/
407/* Send a command packet to the MMC */
408/*-----------------------------------------------------------------------*/
409
410static
411BYTE send_cmd( /* Return value: R1 resp (bit7==1:Failed to send) */
412 BYTE cmd, /* Command index */
413 DWORD arg /* Argument */
414 )
415{
416 BYTE n, res;
417
418
419 if (cmd & 0x80) { /* Send a CMD55 prior to ACMD<n> */
420 cmd &= 0x7F;
421 res = send_cmd(CMD55, 0);
422 if (res > 1) return res;
423 }
424
425 /* Select the card and wait for ready except to stop multiple block read */
426 if (cmd != CMD12) {
427 deselect();
428 if (!select()) return 0xFF;
429 }
430
431 /* Send command packet */
432 xchg_spi(0x40 | cmd); /* Start + command index */
433 xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
434 xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
435 xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
436 xchg_spi((BYTE)arg); /* Argument[7..0] */
437 n = 0x01; /* Dummy CRC + Stop */
438 if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
439 if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
440 xchg_spi(n);
441
442 /* Receive command resp */
443 if (cmd == CMD12) xchg_spi(0xFF); /* Diacard stuff byte on CMD12 */
444 n = 10; /* Wait for response (10 bytes max) */
445 do
446 res = xchg_spi(0xFF);
447 while ((res & 0x80) && --n);
448
449 return res; /* Return received response */
450}
451
452
453
454/*--------------------------------------------------------------------------
455
456 Public Functions
457
458---------------------------------------------------------------------------*/
459
460
461/*-----------------------------------------------------------------------*/
462/* Initialize disk drive */
463/*-----------------------------------------------------------------------*/
464
465DSTATUS mmc_rspi_initialize()
466{
467 BYTE n, cmd, ty, ocr[4];
468
469 power_on(); /* Initialize RSPI */
470 for (n = 10; n; n--) xchg_spi(0xFF);/* Send 80 dummy clocks */
471
472 ty = 0;
473 if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI/Idle state */
474 Timer1 = 1000; /* Initialization timeout = 1 sec */
475 if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
476 for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get 32 bit return value of R7 resp */
477 if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* Is the card supports vcc of 2.7-3.6V? */
478 while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for end of initialization with ACMD41(HCS) */
479 if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
480 for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
481 ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Card id SDv2 */
482 }
483 }
484 }
485 else { /* Not SDv2 card */
486 if (send_cmd(ACMD41, 0) <= 1) { /* SDv1 or MMC? */
487 ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */
488 }
489 else {
490 ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */
491 }
492 while (Timer1 && send_cmd(cmd, 0)); /* Wait for end of initialization */
493 //if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set block length: 512 */
494 // ty = 0;
495 }
496 if (ty) {
497 if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
498 && rcvr_datablock(CSD, 16)){
499 /* CSD Ver.1.0 */
500 if ((CSD[0] & 0xC0) == 0) {
501 CardBlockSize = 1 << (CSD[5] & 0x0F);
502 CardCapacity = (((CSD[6] & 0x03) << 10) | (CSD[7] << 2) | ((CSD[8] & 0xC0) >> 6)) + 1;
503 CardCapacity *= (((uint64_t)1) << ((((CSD[9] & 0x03) << 1) | (CSD[10] & 0x80) >> 7) + 2));
504 CardCapacity *= (uint64_t)CardBlockSize;
505 }
506 else {
507 CardBlockSize = 512;
508 CardCapacity = ((uint64_t)((((CSD[7] & 0x3F) << 16) | (CSD[8] << 8) | CSD[9]) + 1)) * 512 * 1024;
509 }
510 if (send_cmd(CMD10, 0) != 0 /* READ_CID */
511 || !rcvr_datablock(CID, 16)) {
512 ty = 0;
513 }
514 }
515 else {
516 ty = 0;
517 }
518 }
519 }
520 CardType = ty; /* Card type */
521 deselect();
522
523 if (ty) { /* OK */
524 FCLK_FAST(); /* Set fast clock */
525 Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */
526 }
527 else { /* Failed */
528 power_off();
529 Stat = STA_NOINIT;
530 }
531
532 return Stat;
533}
534
535
536
537/*-----------------------------------------------------------------------*/
538/* Get disk status */
539/*-----------------------------------------------------------------------*/
540
541DSTATUS mmc_rspi_status()
542{
543 return Stat; /* Return disk status */
544}
545
546
547
548/*-----------------------------------------------------------------------*/
549/* Read sector(s) */
550/*-----------------------------------------------------------------------*/
551
552DRESULT mmc_rspi_read(
553 BYTE *buff, /* Pointer to the data buffer to store read data */
554 DWORD sector, /* Start sector number (LBA) */
555 UINT count /* Number of sectors to read (1..128) */
556 )
557{
558 if (!count) return RES_PARERR; /* Check parameter */
559 if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
560
561 if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ot BA conversion (byte addressing cards) */
562
563 if (count == 1) { /* Single sector read */
564 if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
565 && rcvr_datablock(buff, 512))
566 count = 0;
567 }
568 else { /* Multiple sector read */
569 if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
570 do {
571 if (!rcvr_datablock(buff, 512)) break;
572 buff += 512;
573 } while (--count);
574 send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
575 }
576 }
577 deselect();
578
579 return count ? RES_ERROR : RES_OK; /* Return result */
580}
581
582
583
584/*-----------------------------------------------------------------------*/
585/* Write sector(s) */
586/*-----------------------------------------------------------------------*/
587
588#if _USE_WRITE
589DRESULT mmc_rspi_write(
590 const BYTE *buff, /* Ponter to the data to write */
591 DWORD sector, /* Start sector number (LBA) */
592 UINT count /* Number of sectors to write (1..128) */
593 )
594{
595 if (!count) return RES_PARERR; /* Check parameter */
596 if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */
597 if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protect */
598
599 if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ==> BA conversion (byte addressing cards) */
600
601 if (count == 1) { /* Single sector write */
602 if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
603 && xmit_datablock(buff, 0xFE))
604 count = 0;
605 }
606 else { /* Multiple sector write */
607 if (CardType & CT_SDC) send_cmd(ACMD23, count);
608 if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
609 do {
610 if (!xmit_datablock(buff, 0xFC)) break;
611 buff += 512;
612 } while (--count);
613 if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
614 count = 1;
615 }
616 }
617 deselect();
618
619 return count ? RES_ERROR : RES_OK; /* Return result */
620}
621#endif /* _USE_WRITE */
622
623
624
625/*-----------------------------------------------------------------------*/
626/* Miscellaneous drive controls other than data read/write */
627/*-----------------------------------------------------------------------*/
628
629#if _USE_IOCTL
630DRESULT mmc_rspi_ioctl(
631 BYTE ctrl, /* Control command code */
632 void *buff /* Pointer to the conrtol data */
633 )
634{
635 DRESULT res;
636 BYTE n, csd[16], *ptr = buff;
637 DWORD *dp, st, ed;
638
639
640 if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
641
642 res = RES_ERROR;
643
644 switch (ctrl) {
645 case CTRL_SYNC: /* Wait for end of internal write process of the drive */
646 if (select()) res = RES_OK;
647 break;
648
649 case GET_SECTOR_SIZE:
650 *(WORD*)buff = 512;
651 res = RES_OK;
652 break;
653
654 case GET_SECTOR_COUNT:
655 *(DWORD*)buff = CardCapacity / 512;
656 res = RES_OK;
657 break;
658
659 case GET_BLOCK_SIZE:
660 *(DWORD*)buff = CardBlockSize;
661 res = RES_OK;
662 break;
663
664 case CTRL_TRIM: /* Erase a block of sectors (used when _USE_TRIM == 1) */
665 if (!(CardType & CT_SDC)) break; /* Check if the card is SDC */
666 if (mmc_rspi_ioctl(MMC_GET_CSD, csd)) break; /* Get CSD */
667 if (!(csd[0] >> 6) && !(csd[10] & 0x40)) break; /* Check if sector erase can be applied to the card */
668 dp = buff; st = dp[0]; ed = dp[1]; /* Load sector block */
669 if (!(CardType & CT_BLOCK)) {
670 st *= 512; ed *= 512;
671 }
672 if (send_cmd(CMD32, st) == 0 && send_cmd(CMD33, ed) == 0 && send_cmd(CMD38, 0) == 0 && wait_ready(30000)) /* Erase sector block */
673 res = RES_OK;
674 break;
675
676 /* Following command are not used by FatFs module */
677
678 case MMC_GET_TYPE: /* Get MMC/SDC type (BYTE) */
679 *ptr = CardType;
680 res = RES_OK;
681 break;
682
683 case MMC_GET_CSD: /* Read CSD (16 bytes) */
684 memcpy(ptr, CSD, sizeof(CSD));
685 res = RES_OK;
686 break;
687
688 case MMC_GET_CID: /* Read CID (16 bytes) */
689 memcpy(ptr, CID, sizeof(CID));
690 res = RES_OK;
691 break;
692
693 case MMC_GET_OCR: /* Read OCR (4 bytes) */
694 if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
695 for (n = 4; n; n--) *ptr++ = xchg_spi(0xFF);
696 res = RES_OK;
697 }
698 break;
699
700 case MMC_GET_SDSTAT: /* Read SD status (64 bytes) */
701 if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
702 xchg_spi(0xFF);
703 if (rcvr_datablock(ptr, 64))
704 res = RES_OK;
705 }
706 break;
707
708 default:
709 res = RES_PARERR;
710 }
711
712 deselect();
713
714 return res;
715}
716#endif /* _USE_IOCTL */
717
718
719/*-----------------------------------------------------------------------*/
720/* Device timer function */
721/*-----------------------------------------------------------------------*/
722/* This function must be called from system timer process
723/ in period of 1 ms to generate card control timing.
724*/
725
726void mmc_rspi_cychdr(intptr_t exinf)
727{
728 WORD n;
729 BYTE s;
730
731
732 n = Timer1; /* 1kHz decrement timer stopped at 0 */
733 if (n) Timer1 = --n;
734 n = Timer2;
735 if (n) Timer2 = --n;
736
737 s = Stat;
738 if (WP()) /* Write protected */
739 s |= STA_PROTECT;
740 else /* Write enabled */
741 s &= ~STA_PROTECT;
742 if (INS()) /* Card is in socket */
743 s &= ~STA_NODISK;
744 else /* Socket empty */
745 s |= (STA_NODISK | STA_NOINIT);
746 Stat = s;
747}
748
749void mmc_rspi_spri_handler(void)
750{
751 isig_sem(MMC_RSPI_SEMAPHORE);
752}
753
754void mmc_rspi_spti_handler(void)
755{
756}
757
758void mmc_rspi_spii_handler(void)
759{
760}
761
Note: See TracBrowser for help on using the repository browser.