source: UsbWattMeter/trunk/fatfs/mmc_rspi.c@ 164

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

TOPPERS/ECNLサンプルアプリ「USB充電器電力計」を追加

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