source: UsbWattMeter/trunk/fatfs/mmc_rspi.c

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

MIMEにSJISを設定

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